0

我正在尝试在自定义 MIDI 播放器上实现重复功能,但我无法实现重复功能。以下是我正在使用的课程:

NotePlayer- 使用 Java 的 MIDI 包播放 MIDI 音符。

GuitarTunerGUI

  • NotePlayer 类的接口。
  • 为每个吉他弦提供六个 JButton,一个用于选择所需调音的 JComboBox,以及一个用于切换重复功能的 JCheckBox。
  • 提供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();
}

执行方法执行以下操作:

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 时,我需要首先确定是否有任何工作线程当前正在执行,如果是,则在播放指定的音符之前终止这些线程。提前感谢您的时间和反馈。

4

2 回答 2

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);
    }
  }
}
于 2013-06-26T21:47:59.677 回答
0

您需要维护工作人员之间的共享状态。引入新的布尔变量“playing”。执行前检查播放标志是否设置为true,执行后再次设置为false。

于 2013-06-23T20:18:21.320 回答