我正在尝试编写一个播放音乐和弦的程序。我想添加一个窗口,显示一个进度条,显示和弦演奏的时间以及它们已完成的程度。为了演奏和弦,我一直使用 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();
}
}
感谢您的帮助。
最佳答案
建议:
- 新的依赖对话框窗口应该只是一个对话框,例如 JDialog,而不是创建整个独立应用程序的新 JFrame。
- 您知道您应该在后台线程中创建声音,而您的黑屏正是由这个问题引起的,但我在您的代码中没有看到任何线程创建 - 为什么?
- 我自己,我不会使用 Swing Timer 和轮询数据,而是在 SwingWorker 中完成所有操作,在 SwingWorker 的
doInBackground
方法中,我会更新其进度状态,并且我会将 PropertyChangeListener 添加到 SwingWorker 并监视此状态。 - 顺便说一句,您几乎永远不会想创建一个 Runnable 类,然后调用它的
run()
方法。如果您要创建 Runnable 以允许其在后台线程中运行,那么您可能会将其放入线程中,然后在该线程上调用start()
。由于上面的代码应该在 Swing 事件线程上运行,因此如果不是从此线程调用它,则应该通过SwingUtilities.invokeLater(myRunnable);
将其排队到该线程上
- 我不确定如何从 StdAudio 库中获取进度值。如果有办法,那么可以通过其
setProgress(...)
方法来设置 SwingWorker 的进度状态。如果没有,那么您可以猜测,我想或者您最好使用不确定的进度条。我相信 JProgressBar 有一个名为setInminateate(true)
的方法可以用于此目的。
关于java - StdAudio 类使我的 JFrame 不显示,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31100748/