web-dev-qa-db-fra.com

Comment fonctionne paintComponent?

Cela pourrait être une question très noob. Je commence juste à apprendre Java

Je ne comprends pas le fonctionnement de la méthode paintComponent. Je sais que si je veux dessiner quelque chose, je dois remplacer la méthode paintComponent.

public void paintComponent(Graphics g)
{
   ...
}

Mais quand s'appelle-t-il? Je ne vois jamais rien de tel que "object.paintComponent (g)" mais il est quand même dessiné lorsque le programme est en cours d'exécution.

Et quel est le paramètre Graphics? D'où cela vient-il? Le paramètre doit être fourni lors de l'appel de la méthode. Mais comme je l'ai déjà dit, il semble que cette méthode ne soit jamais explicitement appelée. Alors, qui fournit ce paramètre? Et pourquoi devons-nous le convertir en Graphics2D?

public void paintComponent(Graphics g)
{
    ...
    Graphics2D g2= (Graphics2D) g;
    ...
}
58
Hải Phong

La réponse (très) courte à votre question est que paintComponent est appelé "quand il le faut". Parfois, il est plus facile de penser au système d'interface graphique Swing de Java comme une "boîte noire"), où une grande partie des éléments internes sont gérés sans trop de visibilité.

Un certain nombre de facteurs déterminent le moment où un composant doit être repeint: déplacement, redimensionnement, modification de la mise au point, masquage par d'autres cadres, etc. Beaucoup de ces événements sont détectés automatiquement et paintComponent est appelé en interne lorsqu'il est déterminé que cette opération est nécessaire.

J'ai travaillé avec Swing pendant de nombreuses années, et je ne pense pas que j'ai jamais appelé directement paintComponent, ni même vu l'appelé directement à partir d'autre chose. Le plus proche que je sois venu utilise les méthodes repaint() pour déclencher par programme une nouvelle peinture de certains composants (ce qui, je suppose, appelle les méthodes paintComponent correctes en aval.

D'après mon expérience, paintComponent est rarement remplacé directement. Je reconnais que certaines tâches de rendu personnalisées nécessitent une telle granularité, mais Java Swing offre un ensemble (assez) robuste de JComponents et de Layouts qui peuvent être utilisés pour faire une bonne partie des tâches lourdes sans avoir Remplacer directement paintComponent. Je suppose que mon objectif ici est de vous assurer que vous ne pouvez pas utiliser quelque chose avec JComponents et Layouts natifs avant d'essayer de lancer vos propres composants rendus personnalisés.

35
SeKa

Deux choses que vous pouvez faire ici:

  1. Lire Peindre en AWT et Swing
  2. Utilisez un débogueur et placez un point d'arrêt dans la méthode paintComponent. Ensuite, parcourez le stacktrace et voyez comment le paramètre Graphics est fourni.

Juste pour info, voici le stacktrace que je tire de l'exemple de code que j'ai posté à la fin:

Thread [AWT-EventQueue-0] (Suspended (breakpoint at line 15 in TestPaint))  
    TestPaint.paintComponent(Graphics) line: 15 
    TestPaint(JComponent).Paint(Graphics) line: 1054    
    JPanel(JComponent).paintChildren(Graphics) line: 887    
    JPanel(JComponent).Paint(Graphics) line: 1063   
    JLayeredPane(JComponent).paintChildren(Graphics) line: 887  
    JLayeredPane(JComponent).Paint(Graphics) line: 1063 
    JLayeredPane.Paint(Graphics) line: 585  
    JRootPane(JComponent).paintChildren(Graphics) line: 887 
    JRootPane(JComponent).paintToOffscreen(Graphics, int, int, int, int, int, int) line: 5228   
    RepaintManager$PaintManager.paintDoubleBuffered(JComponent, Image, Graphics, int, int, int, int) line: 1482 
    RepaintManager$PaintManager.Paint(JComponent, JComponent, Graphics, int, int, int, int) line: 1413  
    RepaintManager.Paint(JComponent, JComponent, Graphics, int, int, int, int) line: 1206   
    JRootPane(JComponent).Paint(Graphics) line: 1040    
    GraphicsCallback$PaintCallback.run(Component, Graphics) line: 39    
    GraphicsCallback$PaintCallback(SunGraphicsCallback).runOneComponent(Component, Rectangle, Graphics, Shape, int) line: 78    
    GraphicsCallback$PaintCallback(SunGraphicsCallback).runComponents(Component[], Graphics, int) line: 115 
    JFrame(Container).Paint(Graphics) line: 1967    
    JFrame(Window).Paint(Graphics) line: 3867   
    RepaintManager.paintDirtyRegions(Map<Component,Rectangle>) line: 781    
    RepaintManager.paintDirtyRegions() line: 728    
    RepaintManager.prePaintDirtyRegions() line: 677 
    RepaintManager.access$700(RepaintManager) line: 59  
    RepaintManager$ProcessingRunnable.run() line: 1621  
    InvocationEvent.dispatch() line: 251    
    EventQueue.dispatchEventImpl(AWTEvent, Object) line: 705    
    EventQueue.access$000(EventQueue, AWTEvent, Object) line: 101   
    EventQueue$3.run() line: 666    
    EventQueue$3.run() line: 664    
    AccessController.doPrivileged(PrivilegedAction<T>, AccessControlContext) line: not available [native method]    
    ProtectionDomain$1.doIntersectionPrivilege(PrivilegedAction<T>, AccessControlContext, AccessControlContext) line: 76    
    EventQueue.dispatchEvent(AWTEvent) line: 675    
    EventDispatchThread.pumpOneEventForFilters(int) line: 211   
    EventDispatchThread.pumpEventsForFilter(int, Conditional, EventFilter) line: 128    
    EventDispatchThread.pumpEventsForHierarchy(int, Conditional, Component) line: 117   
    EventDispatchThread.pumpEvents(int, Conditional) line: 113  
    EventDispatchThread.pumpEvents(Conditional) line: 105   
    EventDispatchThread.run() line: 90  

Le paramètre Graphics vient d'ici:

RepaintManager.paintDirtyRegions(Map) line: 781 

L'extrait impliqué est le suivant:

Graphics g = JComponent.safelyGetGraphics(
                        dirtyComponent, dirtyComponent);
                // If the Graphics goes away, it means someone disposed of
                // the window, don't do anything.
                if (g != null) {
                    g.setClip(rect.x, rect.y, rect.width, rect.height);
                    try {
                        dirtyComponent.Paint(g); // This will eventually call paintComponent()
                    } finally {
                        g.dispose();
                    }
                }

Si vous l'examinez, vous verrez qu'il récupère les graphiques du composant JComponent lui-même (indirectement avec javax.swing.JComponent.safelyGetGraphics(Component, Component)), qui le reprend éventuellement à partir de son premier "parent poids lourd" (raccordé aux limites du composant). lequel il le prend lui-même à partir de la ressource native correspondante.

En ce qui concerne le fait que vous deviez convertir le Graphics en un Graphics2D, Il arrive que lorsque vous utilisez Window Toolkit, le Graphics s'étend en fait Graphics2D Cependant, vous pouvez utiliser d’autres Graphics qui "ne doivent pas" étendre Graphics2D (cela n’arrive pas très souvent, mais AWT/Swing vous permet de le faire).

import Java.awt.Color;
import Java.awt.Graphics;

import javax.swing.JFrame;
import javax.swing.JPanel;

class TestPaint extends JPanel {

    public TestPaint() {
        setBackground(Color.WHITE);
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawOval(0, 0, getWidth(), getHeight());
    }

    public static void main(String[] args) {
        JFrame jFrame = new JFrame();
        jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jFrame.setSize(300, 300);
        jFrame.add(new TestPaint());
        jFrame.setVisible(true);
    }
}
10
Guillaume Polet

Les éléments internes du système graphique appellent cette méthode et transmettent le paramètre Graphics en tant que contexte graphique sur lequel vous pouvez dessiner.

3
Gian

L'appel de object.paintComponent(g) est une erreur.

Au lieu de cela, cette méthode est appelée automatiquement lors de la création du panneau. La méthode paintComponent() peut également être appelée explicitement par la méthode repaint() définie dans la classe Component.

Si vous appelez repaint(), Swing efface automatiquement le graphique sur le panneau et exécute la méthode paintComponent pour redessiner les graphiques sur ce panneau.

3
Saumya Sharma