我正在尝试编写一个播放音乐和弦的程序。我想添加一个窗口,显示一个进度条,显示和弦的播放时间以及完成的次数。为了演奏和弦,我一直在使用StdAudio class的略微修改版本。到目前为止,当我要求和弦播放时,我会运行以下代码。
public static void playNotes(double[] frequencies, double duration, double amplitude)
{
PlayAudioGUI g = new PlayAudioGUI(duration);
g.run();
amp = amplitude;
ArrayList<double[]> chord = new ArrayList<double[]>();
for(double freq : frequencies) {
double[] note = StdAudio.tone(freq, duration);
chord.add(note);
}
double[] chordCombined = new double[chord.get(0).length];
for (int i = 0; i < chordCombined.length; i++) {
for (double[] note : chord) {
chordCombined[i] += note[i];
}
chordCombined[i] /= chord.size();
}
StdAudio.play(chordCombined);
}
我之前从未尝试过多线程,所以我不知道我做错了什么。当我运行代码时,它在播放和弦时显示一个空窗口,然后正确显示窗口。我希望它能够在播放音频的同时显示窗口。
这是我的窗口类的代码。
import java.awt.Container;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JProgressBar;
import javax.swing.Timer;
public class PlayAudioGUI implements Runnable {
private JFrame window;
private JProgressBar prog;
private double duration;
private Timer t;
class TimerListener implements ActionListener {
// This runs every few milliseconds, depending on the delay set below
public void actionPerformed(ActionEvent event) {
prog.setValue(prog.getValue() + 1);
// Stop the timer and hide the window when the progress bar
// completes
if (prog.getValue() == prog.getMaximum()) {
t.stop();
window.setVisible(false);
}
}
}
public PlayAudioGUI(double duration) {
this.window = new JFrame("Playing audio...");
this.duration = duration;
}
@Override
public void run() {
// Setting up gridbag layout. I will add more components later.
Container pane = this.window.getContentPane();
pane.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.gridx = 0;
c.gridy = 0;
c.insets = new Insets(30, 30, 30, 30);
// Display the approximate duration
String clippedDuration;
if (Double.toString(duration).length() > 5) {
clippedDuration = Double.toString(duration).substring(0, 4);
} else {
clippedDuration = Double.toString(duration);
}
String message = "Playing audio for " + clippedDuration + " seconds";
pane.add(new JLabel(message), c);
// Make a progressbar
c.gridy = 1;
this.prog = new JProgressBar();
this.prog.setMinimum(0);
this.prog.setMaximum(250);
pane.add(this.prog, c);
// More window management stuff
this.window.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
this.window.pack();
this.window.setVisible(true);
// Set up the timer
ActionListener listener = new TimerListener();
final int DELAY = (int) (4 * this.duration); // This works, I did the
// math :)
t = new Timer(DELAY, listener);
t.start();
}
}
感谢您的帮助。
答案 0 :(得分:2)
建议:
doInBackground
方法中我会更新其进度状态,并且我会添加一个PropertyChangeListener到SwingWorker并监控这种状态。run()
方法。如果您正在创建Runnable以允许它在后台线程中运行,那么您可能会将其放入Thread中,然后在Thread上调用start()
。由于上面的代码应该在Swing事件线程上运行,如果没有从这个线程调用它,它应该通过SwingUtilities.invokeLater(myRunnable);
setProgress(...)
方法设置SwingWorker的进度状态。如果没有,那么你可以猜测,或者你可能会更好地使用不确定的进度条。我相信JProgressBar有一个名为setIndeterminate(true)
的方法可以用于此。