我正在尝试在自定义MIDI播放器上实现重复功能,但我无法实现重复功能。以下是我正在使用的课程:
NotePlayer
- 使用Java的MIDI包播放MIDI音符。
GuitarTunerGUI
toggleRepeat()
来切换repeatEnabled
字段,GuitarTunerGUI
类的私有字段。我创建了一个SwingWorker,负责在单独的线程中播放MIDI音符。这解决了在播放音符时保持GUI响应的问题。 但是,当启用重复并且用户按下多个按钮时会出现问题。
当用户按下六个JButton中的一个时,监听器执行以下操作:
public void actionPerformed(ActionEvent event) {
// The note param is a private field of the listener object
MusicianWorker clapton = new MusicianWorker(note);
clapton.execute();
}
execute方法执行以下操作:
protected Void doInBackground() throws Exception {
do {
NotePlayer.playNote(thisNote);
try {
Thread.sleep(3000);
} catch (InterruptedException ex) {
System.out.println(ex.getMessage());
}
} while (repeatEnabled);
return null;
}
当用户按下多个按钮而不切换重复时,会出现问题。例如,当按顺序按下“A”按钮和“E”按钮时,会创建两个线程,并且“A”和“E”音符都重复播放,直到repeatEnabled
被切换了。当用户推送JButton时,我需要首先确定当前是否正在执行任何工作线程,如果是,则在播放指定的注释之前杀死这些线程。提前感谢您的时间和反馈。
答案 0 :(得分:0)
您需要维护员工之间的共享状态。引入新的布尔变量“播放”。在执行之前检查播放标志是否设置为true,执行后再将其设置为false。
答案 1 :(得分:0)
您提供的代码非常棒,只需稍微调整一下即可。当您创建SwingWorker
时,您应该在实例变量中跟踪它(如果您想要在某个时间点播放多个音符,可能在List
中)。然后,在播放新音符之前,检查最后一个音符是否已完成,如果没有,则取消它。
取消是否会对您的MusicianWorker
产生任何影响取决于您。工作线程将被中断,这意味着如果Thread.sleep
方法正在运行,它将提前终止 - 您必须检查您的文档以查看它对NotePlayer
会产生什么影响。
最后,您似乎根本不需要使用SwingWorker
,因为您的后台任务没有与UI交互。您可能需要调查Executors
。
您可以尝试这样的事情:
public class AlbertHall {
private final ExecutorService es = Executors.newSingleThreadExecutor();
// No longer a local variable in the listener
private Future<Void> clapton; // ... or maybe a Collection of Futures
private class Listener implements ActionListener {
private final Note note;
public Listener(Note note) {
this.note = note;
}
public void actionPerformed(ActionEvent event) {
// Watch out, Clapton may finish after you have asked if he is done
// but before you call cancel
if (clapton != null && !clapton.isDone()) clapton.cancel(true);
// You may need to have a wait loop here if Clapton takes a while
// to leave the stage
// Next note
clapton = es.submit(new MusicianWorker(note));
}
}
static class MusicianWorker implements Runnable {
private final Note note;
public MusicianWorker(Note note) {
this.note = note;
}
public void run() {
boolean cancelRequested = false;
do {
NotePlayer.playNote(thisNote);
try {
Thread.sleep(3000);
} catch (InterruptedException ex) {
// Looks like we got cancelled
cancelRequested = true;
}
} while (repeatEnabled && !cancelRequested);
}
}
}