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;
...
}
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.
Deux choses que vous pouvez faire ici:
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);
}
}
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.
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.