我正在编写一个进行音频分析的应用程序(用作吉他调音器,并增加了和弦估计等功能),但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()方法重新执行,但这似乎并没有帮助。
最佳答案
免责声明:多线程不是我最擅长的领域...
您的两个问题实际上都是同一件事,例如您的GUI变得无响应,因为EDT忙于运行while循环。这意味着它不能使用新的文本值重绘按钮,并且不能对用户输入做出反应。
另外,每个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
做什么,所以我从示例中删除了它。希望弄清楚如何重新安装它不会太难。编辑:糟糕,该代码实际上不起作用。现在应该修复。