Search code examples
javaswingcanvastimer

Swing Timer and Painting on Canvas


Hi i wanna ask about Swing timer and Canvas. Im doing simple animation for changing color of objects. I made it with Thread.sleep but JFrame was unresponsive while repainting so i change it to Swing Timer. But now when i start the animation its doing nothing timer is working but objects on canvas dont change color. Here is my function to animate change of colors im using it in overide paint function of canvas

    private void paintSearch(Vector<NodeGraph2D> vector,Graphics graphics2D) {
    if (!vector.isEmpty()) {
        final int[] k = {0};
        Timer timer = new Timer(1000, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (repaint) {
                    if (k[0] == vector.size())
                        return;
                    if (vector == pruferTreeNodes) {
                        vector.elementAt(k[0]).draw((Graphics2D) graphics2D);
                    } else {
                        graphics2D.setColor(Color.GREEN);
                        ((Graphics2D) graphics2D).fill(vector.elementAt(k[0]));
                        graphics2D.setColor(Color.BLACK);
                        ((Graphics2D) graphics2D).drawString(vector.elementAt(k[0]).getNodeGraph().getName(), vector.elementAt(k[0]).getX1() + 15, vector.elementAt(k[0]).getY1() + 25);

                    }
                    k[0] += 1;
                }
            }
        });
        timer.start();
    }
}

Do you think my usage of timers is bad ? Thanks for response. :)


Solution

  • When doing custom painting in Swing it is a good idea to subclass JPanel (it could be an anonymous class) and to store painting-related data in attributes somewhere accessible to the panel.

    Your timer would not do any painting but rather manipulate the painting-related data. You should never attempt to do any painting on a graphics object outside of the EventDispatcherThread of Swing or outside of the paintComponent methods of JComponents. (refer to the documentation of these methods for further information)

    Here is an example of how custom painting with a timer manipulating color could look like:

    public static void main(String[] args) {
        EventQueue.invokeLater(Example::new);
    }
    
    // this is the painting-related data that is being manipulated by the timer
    private int currentColorIndex;
    
    public Example() {
        JFrame frame = new JFrame("Custom Painting");
        frame.setSize(640, 480);
        frame.setLocationRelativeTo(null);
    
        Color[] allColors = {Color.RED, Color.BLUE, Color.GREEN,
                Color.YELLOW, Color.ORANGE, Color.MAGENTA};
    
        JPanel myCustomPanel = new JPanel() {
            @Override
            protected void paintComponent(Graphics g) {
                // here the painting related data is being used by the custom JPanel implementation
                g.setColor(allColors[currentColorIndex]);
                g.fillRect(0, 0, getWidth(), getHeight());
            }
        };
        frame.setContentPane(myCustomPanel);
    
        Timer timer = new Timer(100, e -> {
            // the timer does not use any graphics objects, etc, but rather manipulates our painting-related data
            currentColorIndex = (currentColorIndex + 1) % allColors.length;
            // whenever the painting-related data has changed we need to call repaint() on our custom JPanel implementation
            myCustomPanel.repaint();
        });
        timer.setRepeats(true);
        timer.start();
    
        frame.setVisible(true);
    }