我是java的新手,我刚刚开始编写这个愚蠢的小程序作为GUI测试。它应该做的是有12个按钮,将它们全部设置为白色,连续使3个随机按钮变黑,再将所有按钮设置为白色,等待一秒然后重复。问题是,我似乎无法重复它。每当我尝试在使随机按钮变黑的代码部分周围放置一段时间或for循环时,它就不会运行。它不会给出任何错误,并且进程本身会运行,但不会出现任何窗口。这是类的代码(减去import语句):
public class testingness extends JFrame {
JButton one, two, three, four, five, six, seven, eight, nine, ten, eleven,
twelve;
JPanel panel;
testingness(String title) {
super(title);
this.init();
this.setSize(800, 800);
this.setLocationRelativeTo(null);
this.setVisible(true);
}
void init() {
panel = new JPanel();
panel.setLayout(new GridLayout(3, 4));
one = new JButton();
one.setBackground(Color.white);
two = new JButton();
two.setBackground(Color.white);
three = new JButton();
three.setBackground(Color.white);
four = new JButton();
four.setBackground(Color.white);
five = new JButton();
five.setBackground(Color.white);
six = new JButton();
six.setBackground(Color.white);
seven = new JButton();
seven.setBackground(Color.white);
eight = new JButton();
eight.setBackground(Color.white);
nine = new JButton();
nine.setBackground(Color.white);
ten = new JButton();
ten.setBackground(Color.white);
eleven = new JButton();
eleven.setBackground(Color.white);
twelve = new JButton();
twelve.setBackground(Color.white);
panel.add(one);
panel.add(two);
panel.add(three);
panel.add(four);
panel.add(five);
panel.add(six);
panel.add(seven);
panel.add(eight);
panel.add(nine);
panel.add(ten);
panel.add(eleven);
panel.add(twelve);
this.add(panel);
while (true) {
randomness();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void randomness() {
for (int timesdone = 0; timesdone < 4; timesdone++) {
panel.update(panel.getGraphics());
Random r = new Random();
int rand = r.nextInt(12);
if (rand == 0) {
one.setBackground(Color.black);
} else if (rand == 1) {
two.setBackground(Color.black);
} else if (rand == 2) {
three.setBackground(Color.black);
} else if (rand == 3) {
four.setBackground(Color.black);
} else if (rand == 4) {
five.setBackground(Color.black);
} else if (rand == 5) {
six.setBackground(Color.black);
} else if (rand == 6) {
seven.setBackground(Color.black);
} else if (rand == 7) {
eight.setBackground(Color.black);
} else if (rand == 8) {
nine.setBackground(Color.black);
} else if (rand == 9) {
ten.setBackground(Color.black);
} else if (rand == 10) {
eleven.setBackground(Color.black);
} else if (rand == 11) {
twelve.setBackground(Color.black);
}
one.setBackground(Color.white);
two.setBackground(Color.white);
three.setBackground(Color.white);
four.setBackground(Color.white);
five.setBackground(Color.white);
six.setBackground(Color.white);
seven.setBackground(Color.white);
eight.setBackground(Color.white);
nine.setBackground(Color.white);
ten.setBackground(Color.white);
eleven.setBackground(Color.white);
twelve.setBackground(Color.white);
}
}
}
我在这里做错了什么?
答案 0 :(得分:4)
Swing是一个单线程环境。要求对UI的所有交互和修改都在事件调度线程的上下文中执行。
除其他事项外,EDT负责处理重绘请求和传入事件
阻止EDT的任何操作或操作都会阻止它处理这些事件并更新屏幕。
在您的代码中,您正在执行此操作...
while (true) {
randomness();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
这可能会阻止EDT,阻止它更新屏幕。
同样,你也是这样做的......
for (int timesdone = 0; timesdone < 4; timesdone++) {
/*...*/
}
同样会阻止EDT,阻止它更新屏幕......
此外,这个panel.update(panel.getGraphics());
是一个非常糟糕的主意。在Swing中,您无法控制绘制过程,这取决于RepaintManager
。您可以请求更新/重新绘制,但由RepaintManager
决定何时何地。然后将这些请求发布到EDT ......如果被阻止,将无效。
getGraphics
也可以返回null
,这永远不会很漂亮......
要解决您的问题,您需要将“等待”时间卸载到某种后台进程,在准备就绪时,需要告诉用户界面相应地更改其状态...
您可以使用Thread
,但这意味着您有责任将所有回拨的信息重新同步到EDT,这很麻烦并且几乎没有收获。
您可以使用SwingWorker
,但它并不适合您手头的任务
更好的解决方案是使用javax.swing.Timer
,它会在指定的延迟后重复触发actionPerformed
事件,就像在EDT的上下文中执行一样。
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
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;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Flashy01 {
public static void main(String[] args) {
new Flashy01();
}
public Flashy01() {
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 FlashPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class FlashPane extends JPanel {
private final BigButton one, two, three, four, five, six, seven, eight, nine, ten, eleven,
twelve;
private final JPanel panel;
private final Random random;
private int timesDone;
public FlashPane() {
panel = new JPanel();
panel.setLayout(new GridLayout(3, 4));
one = new BigButton();
one.setBackground(Color.white);
two = new BigButton();
two.setBackground(Color.white);
three = new BigButton();
three.setBackground(Color.white);
four = new BigButton();
four.setBackground(Color.white);
five = new BigButton();
five.setBackground(Color.white);
six = new BigButton();
six.setBackground(Color.white);
seven = new BigButton();
seven.setBackground(Color.white);
eight = new BigButton();
eight.setBackground(Color.white);
nine = new BigButton();
nine.setBackground(Color.white);
ten = new BigButton();
ten.setBackground(Color.white);
eleven = new BigButton();
eleven.setBackground(Color.white);
twelve = new BigButton();
twelve.setBackground(Color.white);
panel.add(one);
panel.add(two);
panel.add(three);
panel.add(four);
panel.add(five);
panel.add(six);
panel.add(seven);
panel.add(eight);
panel.add(nine);
panel.add(ten);
panel.add(eleven);
panel.add(twelve);
this.add(panel);
random = new Random();
Timer timer = new Timer(1000, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
randomness();
}
});
timer.start();
}
public void randomness() {
int rand = random.nextInt(12);
timesDone++;
if (timesDone % 5 != 0) {
if (rand == 0) {
one.setBackground(Color.black);
} else if (rand == 1) {
two.setBackground(Color.black);
} else if (rand == 2) {
three.setBackground(Color.black);
} else if (rand == 3) {
four.setBackground(Color.black);
} else if (rand == 4) {
five.setBackground(Color.black);
} else if (rand == 5) {
six.setBackground(Color.black);
} else if (rand == 6) {
seven.setBackground(Color.black);
} else if (rand == 7) {
eight.setBackground(Color.black);
} else if (rand == 8) {
nine.setBackground(Color.black);
} else if (rand == 9) {
ten.setBackground(Color.black);
} else if (rand == 10) {
eleven.setBackground(Color.black);
} else if (rand == 11) {
twelve.setBackground(Color.black);
}
} else {
one.setBackground(Color.white);
two.setBackground(Color.white);
three.setBackground(Color.white);
four.setBackground(Color.white);
five.setBackground(Color.white);
six.setBackground(Color.white);
seven.setBackground(Color.white);
eight.setBackground(Color.white);
nine.setBackground(Color.white);
ten.setBackground(Color.white);
eleven.setBackground(Color.white);
twelve.setBackground(Color.white);
}
}
}
public class BigButton extends JButton {
@Override
public Dimension getPreferredSize() {
return new Dimension(20, 20);
}
}
}
看看......
了解更多详情......
答案 1 :(得分:2)
在randomness()函数结束时,您将所有按钮设置为白色。你应该将其移到所有if-elses之上,而不是之后。
答案 2 :(得分:2)
正如Germann Arlington指出的那样,永远不允许GUI线程运行,因为你的构造函数永远不会返回。但是,在GUI线程(需要更改GUI组件的属性)上定期执行某些操作的更好方法是使用Timer(http://docs.oracle.com/javase/7/docs/api/javax/swing/Timer.html)。 E.g:
int delay = 1000; //milliseconds
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
randomness();
}
};
new Timer(delay, taskPerformer).start();
答案 3 :(得分:0)
主要的问题是你运行代码,但因为它永远不会结束循环你永远不会绘制组件 - 尝试在循环内的方法结束时唤起repaint()方法。
另一点:如果你有多个按钮,你最好(以编程方式)将它们添加到容器中并循环遍历此容器内容。