Change listener creates hinderance in JSlider

 ̄綄美尐妖づ 提交于 2020-01-16 17:34:58

问题


I have writen this code for playing music, the JSlider moves automatically forward with the progress of music, I have add change listener to JSlider for changing the music position with cursor, the problem is that when the nob of JSlider moves with the progress of music changeListener(); method is also invoked, this create hindrance in playing music, so therefore I want that the changeListener(); method should be invoked only when I move the nob of JSlider with cursor. Please tell how it can be done.

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:


A stateChanged event is raised whenever the underlying BoundedRangeModel is changed. This could be for any number of reasons. The problem is, you don't know why and, generally, don't care.

In your case, you have two (main) situations that might change the model. The while-loop and the user.

What you need is some way to alter the state in such away as to be able to either detect who is making the change or prevent the notification of the change under certain circumstances.

In this (simple) example, I use to simple flags to indicate where the updates are occurring and stop either modifying element from updating the model until the other has finished. This works here because I've used a Swing Timer to perform the progression updates, this ensures that both the "timed" update and the user updates are occurring within the context of the same thread. This provides a level of protection, as it's impossible for the Timer to try and change the state of the UI while the stateChanged method is been run.

It also means that when a stateChanged event is raised from the "time progress" code, it is ignored by our stateChanged handler, so it won't mess with the current position of the 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 && !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();
            }
        }
    }

}


来源:https://stackoverflow.com/questions/24600159/change-listener-creates-hinderance-in-jslider

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!