我正在编写一个进行音频分析的应用程序(用作吉他调音器,增加了和弦估计和其他一些东西),但我在使用GUI时遇到了一些麻烦。第一个问题是我有一个按钮,点击后应该更改其显示的文本。单击它时,文本不会更改,但应该更改应该更改它的代码行。
另一件事是我需要一个SwingWorker来重复执行(一旦完成就重新启动)并且每次都更新GUI。正如我的代码目前,我有一个while循环重复执行我的SwingWorker,但这导致GUI变得无响应,因为它在EDT中运行(大概)。让SwingWorker重复执行的最佳方法是什么?我应该创建一个新线程来运行循环,还是别的什么?
我的内部ActionListener类的代码如下:
private class TunerListener implements ActionListener {
private boolean firstUpdate = true;
private volatile boolean executing = false;
private final SwingWorker<Void, Void> tunerWorker = new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() {
model.update();
return null;
}
@Override
protected void done() {
if (!this.isCancelled()) {
prev.setText(model.getPrev());
currentNote.setText(model.getNote());
next.setText(model.getNext());
frequency.setText(model.getFrequency());
switch (model.getOffset()) {
case -2:
light_2.setIcon(onRed);
light_1.setIcon(off);
light0.setIcon(offBig);
light1.setIcon(off);
light2.setIcon(off);
break;
case -1:
light_2.setIcon(off);
light_1.setIcon(onRed);
light0.setIcon(offBig);
light1.setIcon(off);
light2.setIcon(off);
break;
case 0:
light_2.setIcon(off);
light_1.setIcon(off);
light0.setIcon(onGreen);
light1.setIcon(off);
light2.setIcon(off);
break;
case 1:
light_2.setIcon(off);
light_1.setIcon(off);
light0.setIcon(offBig);
light1.setIcon(onRed);
light2.setIcon(off);
break;
case 2:
light_2.setIcon(off);
light_1.setIcon(off);
light0.setIcon(offBig);
light1.setIcon(off);
light2.setIcon(onRed);
break;
}
}
}
};
@Override
public void actionPerformed(ActionEvent ae) {
if (ae.getActionCommand().equals("tune")) {
if (!executing) {
tune.setText("Stop Tuning");
executing = true;
while (executing) {
tunerWorker.execute();
firstUpdate = false;
}
firstUpdate = true;
} else {
tune.setText("Start Tuning");
executing = false;
tunerWorker.cancel(true);
firstUpdate = true;
}
}
}
}
编辑:按钮文本问题现在似乎已修复,但我仍然无法使此SwingWorker正常工作。我已经尝试完全删除while循环并让它从done()方法重新执行,但这似乎并没有帮助解决问题...
答案 0 :(得分:6)
“SwingWorker
只能执行一次。”而是控制工作人员的执行和生命周期,如example所示。
答案 1 :(得分:5)
免责声明:多线程不是我最专业的领域......
你的两个问题都是一样的,例如由于EDT正忙于运行while循环,因此您的GUI变得无法响应。这意味着它无法使用新文本值重绘按钮,并且无法对用户输入做出反应。
此外,SwingWorker的每个实例只能运行一次,因此在循环中多次调用execute()
只会运行一次。
我建议创建一个TunerWorker对象并将循环放在其中,然后在需要启动循环时创建一个新对象。像这样:
class TunerListener implements ActionListener {
private TunerWorker tw = null;
@Override
public void actionPerformed(ActionEvent ae) {
if (ae.getActionCommand().equals("tune")) {
if (tw == null || tw.isDone()) {
tune.setText("Stop Tuning");
executing = true;
tw = new TunerWorker();
tw.execute();
} else {
tune.setText("Start Tuning");
executing = false;
tw.cancel(true);
}
}
}
}
final class TunerWorker extends SwingWorker<Void, Void> {
@Override
protected Void doInBackground() {
while (!this.isCancelled()) {
model.update();
}
return null;
}
@Override
protected void done() {
if (!this.isCancelled()) {
//Removed this code to make the example prettier...
}
}
}
哦,我不确定你要对firstUpdate
做什么,所以我把它从例子中拿出来了。希望能够找到如何重新投入使用它并不会太难。