Swing Timer里面的绘画不起作用

时间:2016-01-19 17:46:46

标签: java swing timer paint

我以前从未和Timer合作过,所以我的问题可能真的很愚蠢。我的程序绘制一个红色的圆圈,随机秒后圆圈应将其颜色更改为绿色。我刚刚制作了一个摆动计时器,你可以在下面的代码中看到。它进入actionPerformed()方法,但它不会改变颜色。你能帮我改变颜色来解决我的问题吗?

我的代码:

package igrica;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;


public class ChangingCircle implements ActionListener{

JFrame frame;

Timer timer;
Random r;

public static void main(String[] args) {
    ChangingCircle gui = new ChangingCircle();
    gui.go();
}

public void go() {
    frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    MyPanel panel = new MyPanel();

    frame.getContentPane().add(BorderLayout.CENTER, panel);
    frame.setSize(300, 300);
    frame.setVisible(true);
}   

public void actionPerformed(ActionEvent event) {
    frame.repaint();
}

class MyPanel extends JPanel {
    public void paintComponent(Graphics g) {


        g.setColor(Color.red);
        g.fillOval(100, 100, 100, 100);

        Random r = new Random();

        Timer timer = new Timer(r.nextInt(5000) + 1000, new ActionListener() {
            public void actionPerformed(ActionEvent ev) {
                System.out.println("Timer out");
                g.setColor(Color.green);
                g.fillOval(100, 100, 100, 100);
            } 
        });
        timer.start();
    }
}
}

3 个答案:

答案 0 :(得分:8)

你的代码中有很多混乱。试试这个:

public class ChangingCircle {

    Color color = Color.RED;
    MyPanel panel = new MyPanel();

    public static void main(String[] args) {

        SwingUtilities.invokeLater(() -> {
            ChangingCircle gui = new ChangingCircle();
            gui.go();
        });
    }

    public void go() {

        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        frame.getContentPane().add(panel, BorderLayout.CENTER);
        frame.pack();
        frame.setVisible(true);

        Random r = new Random();
        Timer timer = new Timer(r.nextInt(5000) + 1000, new ActionListener() {

            public void actionPerformed(ActionEvent ev) {

                System.out.println("Timer");
                color = Color.GREEN;
                panel.repaint();
            }
        });
        timer.setRepeats(false);
        timer.start();
    }

    class MyPanel extends JPanel {

        private int size = 100, loc = 100;

        @Override
        public void paintComponent(Graphics g) {

            super.paintComponent(g);
            g.setColor(color);
            g.fillOval(loc, loc, size, size);
        }

        @Override
        public Dimension getPreferredSize() {

            return new Dimension(size + loc, size + loc);
        }
    }
}

这个想法是计时器只改变要绘制的形状的属性,然后调用repaint()来反映变化。无论何时需要,都会调用paintComponent,即使是快速连续,也应该快速返回。

特定说明:

  • Start Swing from the EDT
  • paintComponent之外创建并启动计时器,因为它被多次调用,这将创建并启动许多计时器。
  • 您应该将计时器设置为不重复。
  • super.paintComponent(g);作为paintComponent内的第一件事。
  • 您似乎有ActionListener无效。

一般提示:

  • 适用时使用@Override注释。
  • 在框架上调用pack(),而不是手动设置其大小,并@Override您绘制的组件的getPreferredSize方法。根据您绘制的内容返回有意义的大小。
  • 使用add(component, location)而不是相反(弃用)。
  • 当局部变量执行时不要使用字段(例如Random r)。
  • 使用大写常量名称(Color.RED代替Color.red)。

答案 1 :(得分:6)

不要在paintComponent方法中启动Timer。此方法仅适用于绘画和绘画。而是在构造函数中启动Timer并在Timer的actionPerromed中调用repaint(),更改类的字段状态,并使用paintComponent中的信息使用该字段来绘制任何新信息。

e.g。

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

public class ChangingCircle {
    JFrame frame;

    public static void main(String[] args) {
        ChangingCircle gui = new ChangingCircle();
        gui.go();
    }

    public void go() {
        frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        MyPanel panel = new MyPanel();

        frame.getContentPane().add(BorderLayout.CENTER, panel);
        frame.setSize(300, 300);
        frame.setVisible(true);
    }   

    public void actionPerformed(ActionEvent event) {
        frame.repaint();
    }

    class MyPanel extends JPanel {
        private Random r = new Random();
        private boolean draw = false;

        public MyPanel() {
            Timer timer = new Timer(r.nextInt(5000) + 1000, new ActionListener() {
                public void actionPerformed(ActionEvent ev) {
                    draw = true;
                    repaint();
                } 
            });
            timer.setRepeats(false);
            timer.start();
        }
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            if (draw) {
                g.setColor(Color.red);
                g.fillOval(100, 100, 100, 100);
            }
        }
    }
}

另外,不要忘记在覆盖中调用super的paintComponent方法。

如果您需要更改颜色,请为JPanel指定一个Color字段,例如调用color并从Timer中更改它的值,然后调用repaint()。同样在paintComponent中,使用该字段的值来绘制椭圆。同样在这种情况下,Timer 应该重复,所以在这种情况下摆脱timer.setRepeats(false)

答案 2 :(得分:0)

计时器以异步方式工作,paintComponent在完成计时器工作之前完成。