Прослушиватель изменений создает помехи в JSlider

#java #swing #clip #jslider

#java #swing #клип #jslider

Вопрос:

Я написал этот код для воспроизведения музыки, JSlider автоматически перемещается вперед с ходом воспроизведения музыки, я добавил change listener в JSlider для изменения позиции музыки с помощью курсора, проблема в том, что когда параметр JSlider перемещается с ходом воспроизведения музыки, также вызывается метод ChangeListener();, это создает помехи при воспроизведении музыки, поэтому я хочу, чтобы метод ChangeListener(); вызывался только тогда, когда я перемещаю параметр JSlider с помощью курсора. Пожалуйста, расскажите, как это можно сделать.

 import java.net.URL;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.swing.JFrame;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;




public class A implements ChangeListener {

    Clip clip;

    public A() throws Exception {

         JFrame f = new JFrame();
         f.setSize(800,400);
         f.setVisible(true);
         f.setLayout(null);
         URL url = this.getClass().getClassLoader().getResource("jal pari.wav");
         AudioInputStream audioIn = AudioSystem.getAudioInputStream(url);
         clip = AudioSystem.getClip();
         clip.open(audioIn);
         int x = (int)(clip.getMicrosecondLength()/1000000);
         JSlider s = new JSlider(JSlider.HORIZONTAL,0,x,0);
         s.addChangeListener(this);
         s.setBounds(50,50,800,100);
         f.add(s);
         clip.start();


         while( clip.getMicrosecondPosition()!=clip.getMicrosecondLength() ) {
             s.setValue((int)(clip.getMicrosecondPosition()/1000000));
         }
    }

    public static void main(String arg[]) throws Exception {
        new A();
    }


    public void stateChanged(ChangeEvent e) {
        JSlider js = (JSlider)e.getSource();
        int v = js.getValue();
        clip.setMicrosecondPosition(v*1000000);
    }


}
  

Комментарии:

1. Нет реального способа определить, почему был вызван метод StateChanged. Вы могли бы временно отключить прослушиватель, установив значение ползунка во время воспроизведения музыки. Вам также следует рассмотреть возможность использования таймера переключения вместо того, чтобы переходить в while loo, что снизит нагрузку на процессор и EDT, а также обеспечит выполнение обновлений в контексте EDT

2. Существует ли какой-либо прослушиватель типа cursor для JSlider???

3. Нет, как я уже сказал, нет способа определить разницу между изменением, внесенным программой, и изменением, внесенным пользователем. По сути, они оба вызывают setValue…

4. Вместо этого я адаптировал a JProgressBar с помощью a MouseListener для использования в качестве точки перехода к треку для проигрывателя под названием DukeBox. Это устраняет все проблемы с использованием JSlider .

Ответ №1:

stateChanged Событие возникает всякий раз, когда изменяется базовый BoundedRangeModel файл. Это может быть по ряду причин. Проблема в том, что вы не знаете почему, и, как правило, вам все равно.

В вашем случае у вас есть две (основные) ситуации, которые могут изменить модель. while-loop и пользователь.

Что вам нужно, так это какой-то способ изменить состояние таким образом, чтобы иметь возможность либо определять, кто вносит изменение, либо предотвращать уведомление об изменении при определенных обстоятельствах.

В этом (простом) примере я использую флаги to simple, чтобы указать, где происходят обновления, и остановить обновление модели одним из изменяющих элементов до завершения работы другого. Здесь это работает, потому что я использовал Swing Timer для выполнения обновлений прогрессии, это гарантирует, что как «синхронизированное» обновление, так и пользовательские обновления происходят в контексте одного потока. Это обеспечивает определенный уровень защиты, поскольку Timer невозможно попытаться изменить состояние пользовательского интерфейса во время выполнения stateChanged метода.

Это также означает, что когда stateChanged событие вызывается из кода «time progress», оно игнорируется нашим stateChanged обработчиком, поэтому оно не повлияет на текущее положение Clip

 import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public class MusicPlayer {

    public static void main(String[] args) {
        new MusicPlayer();
    }

    public MusicPlayer() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private JSlider slider;
        private Clip clip;
        private Timer updateTimer;
        private boolean timerUpdate = false;
        private boolean userUpdate = false;

        public TestPane() {
            setLayout(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridwidth = GridBagConstraints.REMAINDER;
            gbc.weightx = 1;
            gbc.fill = GridBagConstraints.HORIZONTAL;

            slider = new JSlider();
            slider.setMinorTickSpacing(5);
            slider.setMajorTickSpacing(10);
            slider.setPaintTicks(true);
            slider.setValue(0);
            add(slider);

            updateTimer = new Timer(100, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    if (clip != null) {
                        if (!userUpdate) {
                            timerUpdate = true;
                            try {
                                long length = TimeUnit.NANOSECONDS.convert(clip.getMicrosecondLength(), TimeUnit.SECONDS);
                                long time = TimeUnit.NANOSECONDS.convert(clip.getMicrosecondPosition(), TimeUnit.SECONDS);
                                int progress = (int) Math.round(((double) time / (double) length) * 100d);
                                slider.setValue(progress);
                            } finally {
                                timerUpdate = false;
                            }
                        }
                    }
                }
            });
            updateTimer.start();

            slider.addChangeListener(new ChangeListener() {
                @Override
                public void stateChanged(ChangeEvent e) {
                    if (!timerUpdate amp;amp; !userUpdate) {
                        userUpdate = true;
                        try {
                            long length = clip.getMicrosecondLength();
                            int progress = slider.getValue();
                            long time = (long) (length * (progress / 100d));
                            clip.setMicrosecondPosition(time);
                        } finally {
                            userUpdate = false;
                        }
                    }
                }
            });

            try {
                File source = new File("\...\Kalimba.wav");
                AudioInputStream audioIn = AudioSystem.getAudioInputStream(source);
                clip = AudioSystem.getClip();
                clip.open(audioIn);
                clip.start();
            } catch (UnsupportedAudioFileException | IOException | LineUnavailableException exp) {
                exp.printStackTrace();
            }
        }
    }

}