首页 > 解决方案 > 时间值触发的JavaFX事件多次触发

问题描述

我对编程比较陌生,为了帮助自己,我正在制作一个个人项目。我正在使用 Javafx 构建鼓机,它允许用户编写一系列节拍。

我已经构建了一组行,每行都将用作每个相应乐器的可编程节拍音序器,每行由 16 个按钮组成。如果按下该按钮,则该按钮被激活,并且当循环通过该点时它将产生乐器的声音。

作为参考,这件套件类似于我想要构建的:

https://images-na.ssl-images-amazon.com/images/I/81RctDCP38L._AC_SL1500_.jpg

每个按钮都分配给一个哈希图;Key 是 0-16 的整数,而 value 是按钮本身的特性。

鼓机在 4 个小节/16 个按钮后循环。

为了触发事件并使乐器演奏,时间(作为所有按钮/16 的一部分)将与按钮的键相匹配。一旦发生这种情况,声音就会播放。执行此操作的方法如下:

   public void beatState(Button button, String filename) {
    EventHandler handler = new EventHandler() {
        @Override
        public void handle(Event event) {
            soundGeneration sound = new soundGeneration(filename);

            // if the corresponding buttons key (on a range of 0-16) matches the time as a fraction (0-16)
            // and if the button text is on (activated by clicking the pad)
            if (button.equals(map.get(time.timeToFraction())) & button.getText().equals("On")) {

                // plays the file
                sound.play();

                // when duration of animation is set lower the filename prints more frequently
                // or sometimes not printed/sound played when the duration is higher
                System.out.println(filename);
            }

        }
    };
    // as i increase the duration of the animation , the program becomes both slower but returns
    // both the sound file and prints the filename more often
    Timeline animationButton = new Timeline(new KeyFrame(Duration.millis(100), handler));
    animationButton.setCycleCount(Timeline.INDEFINITE);
    animationButton.play();
}

接下来我将提供时间元素:

       public Integer timeToFraction(){
    labelFormat();
        new AnimationTimer() {
            @Override
            public void handle(long now) {

                // time elapsed since program execution
                double elapsedMillis = (System.currentTimeMillis() - startTime);
                // converts to long
                // multiplies the value to privide a fraction
                long numerator =  (long) ((elapsedMillis/1000)*8.33);


                // value below denominates the time it takes to travel 4 beats at 125 beats per minute
                double denominator = 1.92;
                // converts below to show as a fraction
                long denominatorToBeat =(long) Math.round(denominator * 8.3);

                    // if the elapsed time raises over 16
                    // resets numerator
                    if (numerator> denominatorToBeat) {
                        startTime = System.currentTimeMillis();
                        elapsedMillis = (System.currentTimeMillis() - startTime);

                    }
                    // converts from long to to allow for hashmap matching against button position
                    fractionTime = (int) numerator;
            }
        }.start();
        return fractionTime;
    }

当值与节拍匹配时,达到我的目标;但是,它会播放多次,并且与节拍有关。我假设动画计时器重复值(以毫秒为单位)是导致这种情况的原因;我减少它,有更多不需要的重复声音。我增加它并且由于动画在触发之前传递了值,因此有时不计算注释。

我希望代码在通过按钮时触发声音文件,更具体地说,当按钮对应的哈希图的整数值与时间分数匹配时。

我花了几个小时研究和阅读文档,对于一个简单的问题,它变得非常难以解决。鉴于这个项目出现在大量的作品集和音乐开发软件中,我相信我的问题有一个简单的解决方案。

感谢您抽出宝贵的时间。

标签: javajavafx

解决方案


一般来说,您的方法是错误的,因为您正在滥用动画计时器来做与 GUI 无关的事情。您必须将逻辑与 GUI 分离。

即控制时间和播放声音的对象应该与按钮或任何 GUI 无关。它应该有一些方法来设置/清除特定间隔的声音,然后使用属性公开其状态,例如带有一些描述当前正在播放的音调的类的 ObjectProperty。

按钮应该调用方法来设置/清除色调,并且您可以向 ObjectProperty 添加更改侦听器以根据状态更新按钮外观。


推荐阅读