Событие stateChanged
возникает всякий раз, когда изменяется базовое BoundedRangeModel
. Это может быть по любому количеству причин. Проблема в том, что вы не знаете почему и, как правило, вам все равно.
В вашем случае у вас есть две (основные) ситуации, которые могут изменить модель. while-loop
и пользователь.
Что вам нужно, так это какой-то способ изменить состояние таким образом, чтобы иметь возможность либо определить, кто вносит изменение, либо предотвратить уведомление об изменении при определенных обстоятельствах.
В этом (простом) примере я использую простые флаги, чтобы указать, где происходят обновления, и запретить модифицирующему элементу обновлять модель до тех пор, пока не завершится другой. Это работает здесь, потому что я использовал 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 && !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();
}
}
}
}
person
MadProgrammer
schedule
07.07.2014
JProgressBar
сMouseListener
для использования в качестве точки перехода трека для плеера DukeBox. Он обходит стороной все проблемы с использованиемJSlider
. - person Andrew Thompson   schedule 07.07.2014