Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does swing draw simple component twice?

Here is simple example of drawing an oval.

public class SwingPainter extends JFrame{
    public SwingPainter() {
        super("Swing Painter");
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        getContentPane().add(new MySwingComponent());

        setSize(200, 200);
        setVisible(true);
    }

    public static void main(String[] args) {
        new SwingPainter();
    }

    class MySwingComponent extends JComponent {

         public void paintComponent(Graphics g) {
            System.out.println("paintComponent");
            super.paintComponent(g);
            g.setColor(Color.red);
            g.fillOval(10, 10, 50, 50);
        }

        @Override
        protected void paintBorder(Graphics g) {
            System.out.println("Paint border");
            super.paintBorder(g);
        }

        @Override
        protected void paintChildren(Graphics g) {
            System.out.println("Paint children");
            super.paintChildren(g);
        }
    }
}

But in debug mode or adding some info to console before drawing (as in example), you can see that swing draws components twice.

paintComponent

Paint border

Paint children

paintComponent

Paint border

Paint children

I cannot understand why it happens, but I think it can affect performance in a difficult GUI.

like image 544
Dragon Avatar asked Aug 15 '12 09:08

Dragon


3 Answers

The article Painting in AWT and Swing: Additional Paint Properties: Opacity suggests why: "The opaque property allows Swing's paint system to detect whether a repaint request on a particular component will require the additional repainting of underlying ancestors or not." Because you extend JComponent, the opaque property is false by default, and optimization is not possible. Set the property true to see the difference, as well as the artifact from not honoring the property. Related examples may be found here and here.

like image 193
trashgod Avatar answered Oct 04 '22 04:10

trashgod


I agree with Konstantin, what you need to remember, the repaint manager is responding to any number of requests when the application starts, this typically includes the initial paint request when the window is shown and resized (there's two).

Try this. Wait till the application is running and resize the window. I'm sure you'll get more then a couple of repaint requests ;)

like image 26
MadProgrammer Avatar answered Oct 04 '22 04:10

MadProgrammer


This works fine to me. In fact, even in debug mode the output was:

paintComponent
Paint border
Paint children

Please, bear in mind that in AWT and Swing components there are many methods (paint, paintBorder, paintChildren, paintComponent, repaint, and others) that are called via call-back, whenever the GUI engine finds suitable. That may vary from JVM to JVM or even from different execution sessions. They can also be triggered from the interaction to your program (if you minimize/maximize, for example). Or they may not, at all.

like image 35
Filipe Fedalto Avatar answered Oct 04 '22 03:10

Filipe Fedalto