我正在建立一个简单的鼓机应用程序,并想尝试动画一个滑块,以节奏的节奏移动,以显示哪个16音符的酒吧,鼓机是在。
我已经设置了一个排序器,它使用javax.sound.midi api在一个16次循环中运行。该程序的声音方面工作良好,但我希望我的滑块在屏幕底部通过我听到的节拍循环。
当我实现代码的changeListener时,滑块的位置只有当我用鼠标单击滑块时才会更新。
我试过使用滑块和JPanels的updateUI,重新绘制,重新验证方法,但是没有什么改变。
用这种方式动画GUI元素是可能的吗?
我在使用swing API
tickDisplaySlider.addChangeListener(e -> {
tickDisplaySlider.setValue((int)sequencer.getTickPosition());
tickDisplaySlider.repaint();
System.out.println(Thread.currentThread() + " is running");
});发布于 2020-06-10 20:35:02
为了确保UI与音乐同步,使Java顺序器每16个音符触发一次事件。为了实现这一点,在序列中每16音符添加一条您自己的Midi Controller消息。
在播放过程中注册排序器以获得这些控制器消息的通知。然后,事件处理程序可以更新事件分派线程上的滑块。
以下是代码:
// Create the sequence
// PPQ = ticks per quarter
// 100 ticks per quarter means 25 ticks for a 16th note
Sequence sequence = new Sequence(Sequence.PPQ, 100);
// .........
// Fill the track with your MidiEvents
Track track = sequence.createTrack();
// track.add(MidiEvent(....));
// .........
// Then add your special controller messages every 16th note
// Let's assume sequence length is 1 measure = 4 beats = 16 x 16th notes
for (int i = 0; i < 16; i++)
{
ShortMessage msg = new ShortMessage();
// 176=control change type
// 0=Midi channel 0
// 110=an undefined control change code I choose to use for 16th notes
// 0=unused in this case
msg.setMessage(176, 0, 110, 0);
// Create the event at a 16th note position
long tickPosition = i * 25;
MidiEvent me = new MidiEvent(msg, tickPosition);
// Add the event to the track
track.add(me);
}
// Register the sequencer so that when you start playback you get notified
// of controller messages 110
int[] controllers = new int[] { 110 };
sequencer.addControllerEventListener(shortMessage -> updateSlider(shortMessage), controllers);
// .........
// Process event to update the slider on the Swing Event Dispatching Thread
void updateSlider(ShortMessage sm)
{
// Convert tick position to slider value
double percentage = sequencer.getTickPosition() / (double) sequencer.getTickLength();
int sliderPosition = (int) (slider.getMinimum() + (slider.getMaximum() - slider.getMinimum()) * percentage);
// Important: sequencer fire events outside of the EDT
SwingUtilities.invokeLater(() -> slider.setValue(sliderPosition));
}发布于 2020-06-10 15:45:54
只有当我用鼠标单击滑块时,滑块的位置才会更新。
tickDisplay.addChangeListener(e -> {
tickDisplay.setValue((int)sequencer.getTickPosition());使用ChangeListener的要点是,当用户更改滑块时,它将生成一个事件。
您不希望在滑块上侦听更改事件,您需要在“排序器”上侦听更改事件。然后,当排序器生成一个事件时,您将更新滑块。我不知道声音API,所以您需要阅读API文档来查看可以使用什么监听器。
如果排序器不生成事件,则可以使用Swing计时器轮询排序器。您可以设置定时器以在指定的时间间隔内生成事件。当计时器启动时,您将得到排序器的滴答位置,然后更新滑块。
有关更多信息,请阅读有关如何使用计时器的Swing教程中的部分。
https://stackoverflow.com/questions/62301163
复制相似问题