How does paintComponent work?

This can be a very empty question. I'm just starting to learn Java

I do not understand the operation of the paintComponent method. I know if I want to draw something, I have to override the paintComponent method.

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

But when is it called? I never see anything like "object.paintComponent (g)", but still it is drawn when the program is running.

And what is the Graphics parameter? Where is it from? The parameter must be specified when calling the method. But, as I said, it seems that this method will never be explicitly called. So who provides this option? And why should we transfer it to Graphics2D?

 public void paintComponent(Graphics g) { ... Graphics2D g2= (Graphics2D) g; ... } 
+50
java swing paintcomponent
Mar 21 '13 at 10:10
source share
4 answers

The (very) short answer to your question is that paintComponent is called "when necessary." It is sometimes easier to think of the Java Swing GUI system as a black box, where most of the internal elements are processed without visible visibility.

There are a number of factors that determine when it is necessary to repaint a component, starting from moving, resizing, changing focus, hiding other frames, etc. etc. Many of these events are automatically detected, and paintComponent is called internally when it is determined that this operation is necessary.

I have been working with Swing for many years, and I don’t think I have ever been called paintComponent directly, or even seen that it was called directly from something else. The closest I came up with is to use the repaint() methods to programmatically redraw certain components (which I believe calls the correct paintComponent methods downstream.

In my experience, paintComponent rarely redefined. I admit that there are personalized rendering tasks that require such granularity, but Java Swing offers a (fairly) reliable set of JComponents and Layouts that can be used for most of the hard work without directly overriding paintComponent . My guess is that my point is to make sure you can't do something with native JComponents and layouts before you leave, trying to collapse your own components created with custom components.

+29
Mar 21 '13 at 10:45
source share

Two things you can do here:

  • Read Painting in AWT and Swing
  • Use a debugger and set a breakpoint in the paintComponent method. Then go up the freeze frame and see how you provide the Graphics parameter.

Just for information, here is the stack I got from the sample code that I posted at the end:

 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 

The Graphics parameter is displayed here:

 RepaintManager.paintDirtyRegions(Map) line: 781 

The entered fragment is presented below:

 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(); } } 

If you look at it, you will see that it extracts graphics from the JComponent itself (indirectly using javax.swing.JComponent.safelyGetGraphics(Component, Component) ), which itself takes it ultimately from its first “heavy parent” (bound to the boundaries of the component), which he himself takes it from the corresponding resource.

Regarding the fact that you need to drop Graphics on Graphics2D , it just happens that when working with the Window Toolkit Graphics actually expands Graphics2D , but you can use other Graphics that are “not required” to extend Graphics2D (this does not happen very often, but AWT / Swing lets do it).

 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
Mar 21 '13 at 10:41
source share

Internal GUI systems call this method, and they pass the Graphics parameter as the graphics context you can draw onto.

+3
Mar 21 '13 at 10:11
source share

The call to object.paintComponent(g) is an error.

Instead, this method is called automatically when the panel is created. The paintComponent() method can also be explicitly called by the repaint() method defined in the Component class.

The effect of calling repaint() is that Swing automatically clears the graphics on the panel and executes the paintComponent method to redraw the graphics on the panel.

+2
Oct 23 '14 at 0:17
source share



All Articles