首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用midi顺序器及时动画Java Swing滑块的问题

用midi顺序器及时动画Java Swing滑块的问题
EN

Stack Overflow用户
提问于 2020-06-10 10:20:00
回答 2查看 130关注 0票数 0

我正在建立一个简单的鼓机应用程序,并想尝试动画一个滑块,以节奏的节奏移动,以显示哪个16音符的酒吧,鼓机是在。

我已经设置了一个排序器,它使用javax.sound.midi api在一个16次循环中运行。该程序的声音方面工作良好,但我希望我的滑块在屏幕底部通过我听到的节拍循环。

当我实现代码的changeListener时,滑块的位置只有当我用鼠标单击滑块时才会更新。

我试过使用滑块和JPanels的updateUI,重新绘制,重新验证方法,但是没有什么改变。

用这种方式动画GUI元素是可能的吗?

我在使用swing API

代码语言:javascript
复制
        tickDisplaySlider.addChangeListener(e -> {
            tickDisplaySlider.setValue((int)sequencer.getTickPosition());
            tickDisplaySlider.repaint();
            System.out.println(Thread.currentThread() + " is running");
        });
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-06-10 20:35:02

为了确保UI与音乐同步,使Java顺序器每16个音符触发一次事件。为了实现这一点,在序列中每16音符添加一条您自己的Midi Controller消息。

在播放过程中注册排序器以获得这些控制器消息的通知。然后,事件处理程序可以更新事件分派线程上的滑块。

以下是代码:

代码语言:javascript
复制
// 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));
}
票数 1
EN

Stack Overflow用户

发布于 2020-06-10 15:45:54

只有当我用鼠标单击滑块时,滑块的位置才会更新。

代码语言:javascript
复制
   tickDisplay.addChangeListener(e -> {
        tickDisplay.setValue((int)sequencer.getTickPosition());

使用ChangeListener的要点是,当用户更改滑块时,它将生成一个事件。

您不希望在滑块上侦听更改事件,您需要在“排序器”上侦听更改事件。然后,当排序器生成一个事件时,您将更新滑块。我不知道声音API,所以您需要阅读API文档来查看可以使用什么监听器。

如果排序器不生成事件,则可以使用Swing计时器轮询排序器。您可以设置定时器以在指定的时间间隔内生成事件。当计时器启动时,您将得到排序器的滴答位置,然后更新滑块。

有关更多信息,请阅读有关如何使用计时器的Swing教程中的部分。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62301163

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档