Java 更改侦听器在JSlider中创建障碍
我写了这个播放音乐的代码,JSlider随着音乐的进程自动向前移动,我在JSlider中添加了change listener,用光标改变音乐的位置,问题是当JSlider的nob随着音乐的进程而移动时changeListener();方法也被调用,这会在播放音乐时造成障碍,因此我希望changeListener();方法只应在使用光标移动JSlider的nob时调用。请告诉我怎么做Java 更改侦听器在JSlider中创建障碍,java,swing,clip,jslider,Java,Swing,Clip,Jslider,我写了这个播放音乐的代码,JSlider随着音乐的进程自动向前移动,我在JSlider中添加了change listener,用光标改变音乐的位置,问题是当JSlider的nob随着音乐的进程而移动时changeListener();方法也被调用,这会在播放音乐时造成障碍,因此我希望changeListener();方法只应在使用光标移动JSlider的nob时调用。请告诉我怎么做 import java.net.URL; import javax.sound.sampled.AudioInpu
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);
}
}
只要基础
BoundedRangeModel
发生更改,就会引发stateChanged
事件。这可能有很多原因。问题是,你不知道为什么,一般来说,你也不在乎
在您的案例中,有两种(主要)情况可能会改变模型。while循环
和用户
您需要的是某种方式来改变状态,以便在某些情况下能够检测到谁在进行更改或阻止通知更改
在这个(简单的)示例中,我使用简单标志来指示更新发生的位置,并停止其中一个修改元素更新模型,直到另一个完成。这在这里起作用是因为我使用了Swing计时器来执行进程更新,这确保了“定时”更新和用户更新都发生在同一线程的上下文中。这提供了一定程度的保护,因为在运行stateChanged
方法时,计时器不可能尝试更改UI的状态
这还意味着当从“时间进度”代码引发stateChanged
事件时,我们的stateChanged
处理程序会忽略它,因此它不会干扰剪辑的当前位置
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();
}
}
}
}
没有真正的方法来确定调用stateChanged方法的原因。在播放音乐时设置滑块的值时,可以暂时禁用侦听器。你也应该考虑使用Swing定时器来代替你的LO,这将减少CPU和EDT上的负载,并确保在EDIS上下文中完成更新。JSlider的任何类型的光标监听器??无法区分程序所做的更改和用户所做的更改之间的区别。本质上,它们都调用setValue…我改为使用带有鼠标听器的JProgressBar
,作为一个名为DukeBox的玩家的轨迹“跳转到”点。它回避了使用JSlider
的所有问题。