我以前从未和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();
}
}
}
答案 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
,即使是快速连续,也应该快速返回。
特定说明:
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
在完成计时器工作之前完成。