Search code examples
javaswingjpanelpaintrunnable

Why does super.repaint() not call paint method?


SOLUTION: I needet to add the JPanel into a JFrame. The calling of the paint method is bound to the visibility of the JFrame. thanks @matt

This is my first question so I am sorry if something is missing.

My Problem: I want to create a class which extends JPanel so that I can draw things onto my JFrame. I also want it to be able to repaint itself. So far the run method works but super.repaint() does not. "test1" is being printed and "test2" not.

Thanks in advance :)

public class Main {
    public static GUI gui;
    
    public static void main(String[] args) {
        gui = new GUI();
    }
}
public class GUI extends JFrame{
    public Draw draw;
    public Thread drawT;
    
    public GUI() {
        draw = new Draw();
        drawT = new Thread(draw);
        drawT.start();
    }
}
public class Draw extends JPanel implements Runnable{
    
    @Override
    public void run() {
        while (true) {
            System.out.println("test1");
            super.repaint();
        }   
    }   
    
    @Override
    public void paint(Graphics graphics) {
        System.out.println("test2");
        Graphics2D g = (Graphics2D)graphics;
        
    }
}

Solution

  • repaint schedules you component to be painted. If the component is not visible then paint will not get called.

    A simplified way to look at it. Swing/AWT has the EventDispatchThread which continuously runs, processes events and paints components. When you call "repaint" it tells swing to schedule a paint event for your component. It doesn't call paint. When the EDT gets around to it, it will paint your component.

    In your 'run' method you have a loop that prints out a statement to a terminal, "test1" and then it calls repaint(), and then it repeats. The slowest thing here is the System.out.println.

    You have a really fast loop swamping AWT with repaints requests but that loop will run faster than the EDT loop will run paint events. So maybe you print test1 and call repaint 100 times before the EDT actually performs a single paint. I suspect if you look close, test2 is buried in your output somewhere.

    import java.awt.*;
    
    public class MainS{
        int paints = 0;
        int tags = 0;
        public void runGui(){
            JFrame frame = new JFrame("testing");
            JPanel panel = new JPanel(){
                @Override
                public void paintComponent(Graphics g){
                    super.paintComponent(g);
                    paints++;
                }
            };
            
            frame.add(panel, BorderLayout.CENTER);
            JLabel label = new JLabel("times painted ...");
            frame.add(label, BorderLayout.NORTH);
            
            frame.setSize(200, 400);
            frame.setVisible(true);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            Timer t = new Timer( 1000, evt->{
                label.setText(paints + "/" + tags);
                paints = 0;
                tags = 0;
            });
            t.start();
            
            new Thread( ()->{
                while(true){
                    tags++;
                    panel.repaint();
                }
            }).start();
    
        }
        public static void main(String[] args){
            EventQueue.invokeLater( new MainS()::runGui );
        }
    
    }
    

    Here is a simple example, where the component actually gets repainted. It will display the number of times paintComponent was called and the number of times repaint was called at the top of the frame.