Java 如何在同一面板上创建具有两个不同时间间隔的计时器/动作事件的多个动画组件?
我需要一个简单的动画作业的帮助。它是这样的 我在一个Java 如何在同一面板上创建具有两个不同时间间隔的计时器/动作事件的多个动画组件?,java,swing,layout,jpanel,paintcomponent,Java,Swing,Layout,Jpanel,Paintcomponent,我需要一个简单的动画作业的帮助。它是这样的 我在一个JPanel上有两个刹车灯,目标是让它们有不同的时间间隔,即在不同的时间有灯光循环 如果我一次只有一盏灯,一切都很好。我对这方面比较陌生,但我相信我知道问题所在 在本文下面的代码中,我多次使用this。我相信我的问题发生在public void cycle()方法中,它只是说this.repaint();我有一种感觉,面板是在两个不同的时间段重新喷漆的,它给了我一个随机的光线变化,而不是一个很好的循环 有没有一种方法可以让这两个组件在同一个JP
JPanel
上有两个刹车灯,目标是让它们有不同的时间间隔,即在不同的时间有灯光循环
如果我一次只有一盏灯,一切都很好。我对这方面比较陌生,但我相信我知道问题所在
在本文下面的代码中,我多次使用this
。我相信我的问题发生在public void cycle()
方法中,它只是说this.repaint()
;我有一种感觉,面板是在两个不同的时间段重新喷漆的,它给了我一个随机的光线变化,而不是一个很好的循环
有没有一种方法可以让这两个组件在同一个JPanel
上使用更具体的重新绘制方法(可能是单个灯具周围的边界框),或者创建单独的面板是更好的选择(如果是这样的话,会有一些帮助,因为我了解基本布局,但以前从未使用过它们)
以这种方式运行两个计时器是可以实现的。就我个人而言,我会编写一个“信号”类,用它自己的计时和绘制例程控制单个灯光,但这不是您所要求的 您需要做的是为每个信号维护某种状态变量,并分别更新它们 然后需要修改绘制代码以检测这些状态并采取适当的操作…例如
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestBlink {
public static void main(String[] args) {
new TestBlink();
}
public TestBlink() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private Timer blink1;
private Timer blink2;
private boolean light1 = false;
private boolean light2 = false;
public TestPane() {
blink1 = new Timer(250, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
light1 = !light1;
repaint();
}
});
blink2 = new Timer(1000, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
light2 = !light2;
repaint();
}
});
blink1.start();
blink2.start();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int radius = 20;
int x = (getWidth() - (radius * 2)) / 2;
int y = (getHeight() - (radius * 2)) / 2;
Ellipse2D signal1 = new Ellipse2D.Float(x, y, radius, radius);
Ellipse2D signal2 = new Ellipse2D.Float(x + radius, y, radius, radius);
g2d.setColor(Color.RED);
g2d.draw(signal1);
if (light1) {
g2d.fill(signal1);
}
g2d.setColor(Color.GREEN);
g2d.draw(signal2);
if (light2) {
g2d.fill(signal2);
}
g2d.dispose();
}
}
}
已更新
更好的解决方案(如我前面所述)是在单个类中包含单个序列的所有逻辑。这将隔离绘画,并允许您更改每个序列的单独性质
例如
这是一个简单的例子,它使用固定的变化率,所以每个灯光获得相同的时间
public class TraficLight01 extends JPanel {
public static final int RADIUS = 20;
private Timer timer;
private int state = 0;
public TraficLight01() {
timer = new Timer(500, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
state++;
if (state > 2) {
state = 0;
}
repaint();
}
});
timer.start();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(RADIUS, (RADIUS + 1) * 3);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int radius = 20;
Ellipse2D light = new Ellipse2D.Float(0, 0, RADIUS, RADIUS);
int x = (getWidth() - radius) / 2;
int y = ((getHeight()- (radius * 3)) / 2) + (radius * 2);
Color color[] = new Color[]{Color.RED, Color.YELLOW, Color.GREEN};
for (int index = 0; index < color.length; index++) {
g2d.translate(x, y);
g2d.setColor(color[index]);
g2d.draw(light);
if (state == index) {
g2d.fill(light);
}
g2d.translate(-x, -y);
y -= radius + 1;
}
g2d.dispose();
}
}
公共类交通灯01扩展JPanel{
公共静态最终整数半径=20;
私人定时器;
私有int状态=0;
公共交通灯01(){
计时器=新计时器(500,新ActionListener(){
@凌驾
已执行的公共无效操作(操作事件e){
状态++;
如果(状态>2){
状态=0;
}
重新油漆();
}
});
timer.start();
}
@凌驾
公共维度getPreferredSize(){
返回新尺寸(半径,(半径+1)*3);
}
@凌驾
受保护组件(图形g){
超级组件(g);
Graphics2D g2d=(Graphics2D)g.create();
int半径=20;
Ellipse2D灯光=新的Ellipse2D.Float(0,0,半径,半径);
intx=(getWidth()-radius)/2;
int y=((getHeight()-(radius*3))/2)+(radius*2);
颜色[]=新颜色[]{Color.RED,Color.YELLOW,Color.GREEN};
for(int index=0;index
或者为每个灯光提供可变间隔
public static class TraficLight02 extends JPanel {
public static final int RADIUS = 20;
private Timer timer;
private int state = 0;
// Green, Yellow, Red
private int[] intervals = new int[]{3000, 500, 3000};
public TraficLight02() {
timer = new Timer(intervals[0], new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
timer.stop();
state++;
if (state > 2) {
state = 0;
}
timer.setInitialDelay(intervals[state]);
repaint();
timer.restart();
}
});
timer.start();
timer.setRepeats(false);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(RADIUS, (RADIUS + 1) * 3);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int radius = 20;
Ellipse2D light = new Ellipse2D.Float(0, 0, RADIUS, RADIUS);
int x = (getWidth() - radius) / 2;
int y = ((getHeight()- (radius * 3)) / 2) + (radius * 2);
Color color[] = new Color[]{Color.GREEN, Color.YELLOW, Color.RED};
for (int index = 0; index < color.length; index++) {
g2d.translate(x, y);
g2d.setColor(color[index]);
g2d.draw(light);
if (state == index) {
g2d.fill(light);
}
g2d.translate(-x, -y);
y -= radius + 1;
}
g2d.dispose();
}
}
公共静态类TraficLight02扩展JPanel{
公共静态最终整数半径=20;
私人定时器;
私有int状态=0;
//绿色,黄色,红色
私有int[]区间=新int[]{30005003000};
公共交通灯02(){
计时器=新计时器(间隔[0],新ActionListener(){
@凌驾
已执行的公共无效操作(操作事件e){
timer.stop();
状态++;
如果(状态>2){
状态=0;
}
timer.setInitialDelay(间隔[状态]);
重新油漆();
timer.restart();
}
});
timer.start();
timer.setRepeats(假);
}
@凌驾
公共维度getPreferredSize(){
返回新尺寸(半径,(半径+1)*3);
}
@凌驾
受保护组件(图形g){
超级组件(g);
Graphics2D g2d=(Graphics2D)g.create();
int半径=20;
Ellipse2D灯光=新的Ellipse2D.Float(0,0,半径,半径);
intx=(getWidth()-radius)/2;
int y=((getHeight()-(radius*3))/2)+(radius*2);
颜色[]=新颜色[]{Color.GREEN,Color.YELLOW,Color.RED};
for(int index=0;index
通过setter
方法改变这两个概念,以可变的间隔为它们播种并不需要太多
同样,您可以使用三个
定时器,每次一个定时器触发,您只需启动下一个定时器即可。通过这种方式,您可以定义一个计时器链,每个计时器在完成其父计时器后以不同的间隔触发…可以实现以这种方式运行两个计时器。就我个人而言,我会编写一个“信号”类,用它自己的计时和绘制例程控制单个灯光,但这不是您所要求的
您需要做的是为每个信号维护某种状态变量,并分别更新它们
然后需要修改绘制代码以检测这些状态并采取适当的操作…例如
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestBlink {
public static void main(String[] args) {
new TestBlink();
}
public TestBlink() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private Timer blink1;
private Timer blink2;
private boolean light1 = false;
private boolean light2 = false;
public TestPane() {
blink1 = new Timer(250, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
light1 = !light1;
repaint();
}
});
blink2 = new Timer(1000, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
light2 = !light2;
repaint();
}
});
blink1.start();
blink2.start();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int radius = 20;
int x = (getWidth() - (radius * 2)) / 2;
int y = (getHeight() - (radius * 2)) / 2;
Ellipse2D signal1 = new Ellipse2D.Float(x, y, radius, radius);
Ellipse2D signal2 = new Ellipse2D.Float(x + radius, y, radius, radius);
g2d.setColor(Color.RED);
g2d.draw(signal1);
if (light1) {
g2d.fill(signal1);
}
g2d.setColor(Color.GREEN);
g2d.draw(signal2);
if (light2) {
g2d.fill(signal2);
}
g2d.dispose();
}
}
}
已更新
更好的解决方案(如我所说)
Time(s) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
Light1 ON OFF ON OFF ON OFF ON OFF
Light2 ON OFF ON