Hallo zusammen, bevor das Forum schließt stelle ich mal noch eine Frage: Ich habe für ein Programm einen JSlider verwendet, um die ablaufende Zeit anzuzeigen. Leider bewegt er sich nicht kontinuierlich, sondern sprunghaft, im Beispiel im Sekundentakt.
Ich hab aus meinem Code ein KKSB extrahiert und darin alle Kommentare entfernt, um hier keinen Platz zu verschwenden, ich hoffe, es ist auch ohne diese verständlich.
Dazu benötigt man drei Klassen:
- TimeSliderDemo
package stc.ui.timeslider;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class TimeSliderDemo {
private final JFrame frame;
private final TimeRunningSlider timeSlider;
private boolean paused;
public TimeSliderDemo() {
frame = new JFrame();
timeSlider = new TimeRunningSlider();
paused = false;
init();
createGui();
start();
}
private void init() {
initFrame();
}
private void initFrame() {
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setTitle("Time-Slider Demo");
frame.setPreferredSize(new Dimension(600, 200));
}
private void createGui() {
frame.add(createStartStopButtonPart(), BorderLayout.NORTH);
frame.add(createTimePart(), BorderLayout.CENTER);
}
private Component createStartStopButtonPart() {
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(1, 0, 10, 0));
panel.add(createStartButton());
panel.add(createPauseButton());
panel.add(createStopButton());
return panel;
}
private Component createStartButton() {
JButton button = new JButton("Start");
button.addActionListener(e -> start());
return button;
}
private void start() {
timeSlider.start(10);
}
private Component createPauseButton() {
JButton button = new JButton("Pause");
button.addActionListener(e -> pause());
return button;
}
private void pause() {
if (paused) {
timeSlider.endPause();
}
else {
timeSlider.pause();
}
paused = !paused;
}
private Component createStopButton() {
JButton button = new JButton("Stopp");
button.addActionListener(e -> stop());
return button;
}
private void stop() {
timeSlider.stop();
}
private Component createTimePart() {
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
panel.add(timeSlider.getSlider(), BorderLayout.CENTER);
return panel;
}
public void run() {
SwingUtilities.invokeLater(() -> {
frame.pack();
frame.setVisible(true);
});
}
public static void main(String[] args) {
new TimeSliderDemo().run();
}
}
- TimeRunningSlider
package stc.ui.timeslider;
import java.util.Hashtable;
import javax.swing.JLabel;
import javax.swing.JSlider;
public class TimeRunningSlider {
private final JSlider slider;
private long millisStarted;
private long deltaMillis;
private long millisToStop;
private long millisPausedAt;
private ActualisationRunnable actualisationRunnable;
public TimeRunningSlider() {
slider = new JSlider();
initSlider();
}
private void initSlider() {
slider.setMinimum(0);
slider.setMaximum(0);
slider.setValue(0);
slider.setEnabled(false);
slider.setPaintTicks(true);
slider.setSnapToTicks(false);
slider.setMajorTickSpacing(60);
slider.setMinorTickSpacing(15);
}
public void start(int seconds) {
stopActualisationRunnable();
millisStarted = System.currentTimeMillis();
deltaMillis = 1000L * seconds;
millisToStop = millisStarted + deltaMillis;
int maximum = (int) (deltaMillis / 1000L);
slider.setMaximum(maximum);
slider.setValue(0);
String minutesSeconds = secondsToMinutesSeconds(seconds);
Hashtable<Integer, JLabel> labelTable = new Hashtable<>();
labelTable.put(Integer.valueOf(0), new JLabel("0"));
labelTable.put(Integer.valueOf(maximum), new JLabel(minutesSeconds));
slider.setLabelTable(labelTable);
slider.setPaintLabels(true);
createRunnableAndStartActualisationThread();
}
private static String secondsToMinutesSeconds(int lengthInSeconds) {
int minutes = lengthInSeconds / 60;
int secondsLeft = lengthInSeconds % 60;
String between;
if (secondsLeft < 10) {
between = ":0";
}
else {
between = ":";
}
return minutes + between + secondsLeft;
}
private void createRunnableAndStartActualisationThread() {
long actualisationTimeMillis = 10l;
actualisationRunnable = new ActualisationRunnable(() -> actualiseSlider(),
actualisationTimeMillis);
Thread thread = new Thread(actualisationRunnable);
thread.start();
}
private void actualiseSlider() {
long millisNow = System.currentTimeMillis();
if (millisNow >= millisToStop) {
slider.setValue(slider.getMaximum());
stop();
}
else {
long millisFromStart = millisNow - millisStarted;
int secondsFromStart = (int) (millisFromStart / 1000L);
slider.setValue(secondsFromStart);
}
}
public void pause() {
millisPausedAt = System.currentTimeMillis();
stopActualisationRunnable();
}
public void endPause() {
long millisPauseEndAt = System.currentTimeMillis();
long pauseDelta = millisPauseEndAt - millisPausedAt;
millisStarted += pauseDelta;
millisToStop += pauseDelta;
createRunnableAndStartActualisationThread();
}
public void stop() {
stopActualisationRunnable();
}
private void stopActualisationRunnable() {
if (null != actualisationRunnable) {
actualisationRunnable.stop();
}
}
public JSlider getSlider() {
return slider;
}
}
- ActualisationRunnable
package stc.ui.timeslider;
class ActualisationRunnable implements Runnable {
private final static int SLEEP_TIME = 50;
private volatile boolean actualisationRunning;
private final Runnable actualisationRunnable;
private volatile long sleepTimeMillis;
public ActualisationRunnable(Runnable actualisationRunnable) {
this(actualisationRunnable, SLEEP_TIME);
}
public ActualisationRunnable(Runnable actualisationRunnable, long sleepTimeMillis) {
this.actualisationRunnable = actualisationRunnable;
this.sleepTimeMillis = sleepTimeMillis;
}
public void setSleepTimeMillis(int sleepTimeMillis) {
this.sleepTimeMillis = sleepTimeMillis;
}
@Override
public void run() {
actualisationRunning = true;
loop();
}
private void loop() {
while (actualisationRunning) {
actualisationRunnable.run();
sleep(sleepTimeMillis);
}
}
private static void sleep(long milliseconds) {
try {
Thread.sleep(milliseconds);
}
catch (InterruptedException e) {
// do nothing
}
}
public void stop() {
actualisationRunning = false;
}
}
Die Frage ist nun, wie ich den Slider zu einer kontinuierlichen, nicht sprunghaften Fortbewegung bringen könnte.
Sollte das nicht gehen, könnte ich natürlich auch eine JProgressBar nehmen, aber in meiner Anwendung soll der Benutzer den Knopf auch bewegen können.
Eigentlich müsste die Lösung ja relativ einfach sein, aber ich habe mit dem JSlider schon allerlei ausprobiert und diesen Effekt nicht wegbekommen.