我今天正在编写一个 GUI,它在按下按钮时会进行更长的计算。在计算运行时,我想使用仍在运行的计算的中间结果并将它们写入 JLabel。然而,在计算完成之前,用户不应操作 GUI。起初我在做这样的事情:
(1)
public class GUI extends JFrame {
JLabel label = new JLabel("Status: ");
public GUI(){...}
public void calculate() {
for(int i = 0; i < 10; i++) {
String one = calculationPartOne(i);
label.setText("Status: " + one);
label.repaint(); //*
calculationPartTwo(i);
}
}
}
这不起作用,JLabel 只会在计算完成后更新。我还尝试 .repaint() 和 .validate() 注释 * 行中涉及的所有组件,但它什么也没做。因此,在尝试和搜索 Google/StackoOverflow 一整天后,我终于有了一个可行的解决方案,但我仍然不明白为什么上面不起作用。我希望 GUI 阻塞,所以我很自然地在同一个线程中运行了计算。但是,调用任何方法来重新绘制 GUI -inbetween-计算(在 GUI 更新时停止计算)不起作用,我不明白为什么。有人可以解释吗?
最后,我使用 SwingWorker 类进行计算,并使用它的函数在计算时更新 JLabel。但是,由于我需要阻止 GUI,我现在在执行 SwingWorker 之前禁用所有组件,并在完成计算后让 SwingWorker 重新启用所有组件。所以,我使用 SwingWorker 来不阻止 EDT,然后“假”通过禁用一切来阻止 EDT?这对我来说似乎真的很矛盾。
这是我现在所拥有的大纲:
public class GUI extends JFrame {
JLabel label = new JLabel("Status: ");
//I didn't use a list, but it works to illustrate it here
List<Component> GUIComponents = ...;
public GUI() {...}
public void calculate() {
SwingWorker<Void, String> worker = new SwingWorker<Void, String>() {
protected Void doInBackground() throws Exception {
for(int i = 0; i < 10; i++) {
String one = calculationPartOne(i);
publish(one);
calculationPartTwo(i); //**
}
}
protected void done() {
setEnableGUI(true);
}
protected void process(List<String> chunk) {
label.setText(chunk.get(chunk.size() - 1));
}
};
setEnableGUI(false);
worker.execute();
}
public void setEnableGUI(boolean e) {
for(Component c : GUIComponents) {
c.setEnabled(e);
}
}
//**
public void calculationPartTwo() {...}
}
这行得通。
我希望有人能澄清一下。这个解决方案感觉不对。