*问题解决了 - 感谢您的所有答案,他们非常有帮助!
我正在为一项学校作业制作一个小骰子游戏,我遇到了这个问题。 我想模拟一个模具的滚动,快速循环通过一些模具图标。 这本身并不是造成问题的原因。 如果我直接在JFrame中制作“动画”,它会正确显示。我在下面的代码中已经这样做了:
public class Example{
private static ImageIcon die1 = new ImageIcon("terning1.jpg");
private static ImageIcon die2 = new ImageIcon("terning2.jpg");
private static ImageIcon die3 = new ImageIcon("terning3.jpg");
private static ImageIcon die4 = new ImageIcon("terning4.jpg");
private static ImageIcon die5 = new ImageIcon("terning5.jpg");
private static ImageIcon die6 = new ImageIcon("terning6.jpg");
private static JLabel die = new JLabel(die1);
private static Random generator = new Random();
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(die);
frame.pack();
frame.setVisible(true);
for (int i = 0; i < 100; i++) {
int x = generator.nextInt(6) + 1;
switch(x){
case 1 : die.setIcon(die1);
break;
case 2 : die.setIcon(die2);
break;
case 3 : die.setIcon(die3);
break;
case 4 : die.setIcon(die4);
break;
case 5 : die.setIcon(die5);
break;
case 6 : die.setIcon(die6);
break;
}
//Make the loop wait for 50 millis
long a, b;
a = System.currentTimeMillis();
do {
b = System.currentTimeMillis();
} while ((b-a) < 50);
}
}
}
现在工作正常,但显然它只在我第一次打开JFrame时才有效。所以我想添加一个按钮,使模具滚动。 但是如果我添加一个带有actionlistener的JButton,并将for循环放在actionPerformed方法中,它会停止程序直到循环结束,并且只显示循环中的最后一个die。 例如:
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new FlowLayout());
frame.add(button);
frame.add(die);
button.addActionListener(new ButtonListener());
frame.pack();
frame.setVisible(true);
}
private static class ButtonListener implements ActionListener {
public void actionPerformed(ActionEvent event) {
for (int i = 0; i < 100; i++) {
int x = generator.nextInt(6) + 1;
switch (x) {
case 1:
die.setIcon(die1);
break;
case 2:
die.setIcon(die2);
break;
case 3:
die.setIcon(die3);
break;
case 4:
die.setIcon(die4);
break;
case 5:
die.setIcon(die5);
break;
case 6:
die.setIcon(die6);
break;
}
//Make the loop wait for 50 millis
long a, b;
a = System.currentTimeMillis();
do {
b = System.currentTimeMillis();
} while ((b - a) < 50);
}
有关如何解决此问题的任何提示? 先谢谢!
答案 0 :(得分:3)
发生的事情是所有Swing事件发生的“事件调度线程”必须等待您的代码。不要在事件调度线程上执行长时间运行的东西。这是一个着名的反模式。
您应该阅读从http://docs.oracle.com/javase/tutorial/uiswing/concurrency/index.html开始的Java教程中的课程,该教程描述了这一点。
与您的问题无关的两个小问题:
ImageIcon
变量数组而不是六个单独的变量,那么您的代码将更易于管理。 sleep
课程的Thread
方法,而不是您正在使用的“忙碌睡眠”。答案 1 :(得分:1)
您的UI被锁定,因为所有内容都在同一个线程中,所以它必须等到for循环执行完毕。您需要在一个单独的线程中运行您的逻辑。
答案 2 :(得分:0)
您在EDT中运行actionPerformed(ActionEvent event)
方法,因为您无法更新UI。要从代码更新UI,请尝试使用SwingWorker,它可以在后台进程运行时更新UI。你可以在互联网上找到很多这样的例子。
或者您可以尝试使用Executors进行后台处理并从EDT更新用户界面。
答案 3 :(得分:0)
Swing的事件处理代码在EDT(甚至是调度线程)中运行。 ActionEvent
也不例外。你不能在EDT里面做任何长时间运行的任务。把你的骰子滚动循环放在一个新线程中:
new Thread(){
public void run(){
// your dice rolling code
}
}.start();
然后使用SwingUtilities.invokdeLater()
更新GUI。
注意:您可以使用ImageIcon
数组并使用随机生成的索引访问它,而不是使用switch-case进行调节。
int x = generator.nextInt(6) + 1;
die.setIcon(imageIconArr[x]); // array of image icon