I'm writing an application that reads in audio, analyses this data and then displays the results in realtime. Currently I am using a SwingWorker to run the loop that initiates the background analysis and calling the SwingUtilities.invokeLater method inside the loop to update the GUI components each time analysis has completed. At the moment, the GUI seems to be updating randomly, and occasionally not at all.
The following code shows how I'm trying to accomplish this. The TunerListener is an inner class of a JPanel subclass. PrevNote, nextNote, frequency, and the light variables are all components in the JPanel subclass that I want to update:
private class TunerListener implements ActionListener {
private boolean firstUpdate = true;
private boolean executing = false;
private TunerWorker tunerWorker = null;
private final class TunerWorker extends SwingWorker<Void, Void> {
@Override
protected Void doInBackground() {
while (!this.isCancelled()) {
// Audio analysis in worker thread
model.update(firstUpdate);
// Update components in EDT
if (!this.isCancelled()) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
prevNote.setText(model.getPrev());
currentNote.setText(model.getNote());
nextNote.setText(model.getNext());
frequency.setText("Frequency: "
+ 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;
}
firstUpdate = false;
}
});
}
}
return null;
}
@Override
protected void done() {
}
};
@Override
public void actionPerformed(ActionEvent ae) {
if (ae.getActionCommand().equals("tune")) {
if (!executing) {
executing = true;
firstUpdate = true;
tune.setText("Stop Tuning");
tunerWorker = new TunerWorker();
tunerWorker.execute();
} else {
tune.setText("Start Tuning");
executing = false;
tunerWorker.cancel(true);
}
}
}
}
Edit I notice when I use the debugger that I sometimes get to a point where it tells me the source could not be found and in the debugging window it says something about a FutureTask$Sync.innerRun. Does this narrow it down at all?