Ваш код нарушает правила потоков Swing:
- Вы делаете вызовы Swing из фоновых потоков, и это опасно и может привести к непредсказуемым вызовам исключений.
- Вы используете
java.uti.Timer
и должны использовать javax.swing.Timer
, так как повторяющийся код последнего выполняется в потоке событий Swing.
- У вас есть
while (true)
петли, которые не принадлежат. Таймер берет на себя функцию цикла.
- Вы постоянно создаете и запускаете таймер Swing из цикла while - почему?
Например, следующий код использует JSlider для установки частоты мигания и флажок для запуска / остановки таймера качания, который мигает цветом фона основного JPanel:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import javax.swing.*;
@SuppressWarnings("serial")
public class BlinkEg extends JPanel {
public static final Color COLOR = Color.RED;
private JSlider slider = new JSlider(100, 1000, 500);
private JCheckBox blinkBox = new JCheckBox("Blink");
private Timer timer = new Timer(slider.getValue(), new TimerListener());
public BlinkEg() {
slider.setOpaque(false);
slider.setMajorTickSpacing(200);
slider.setMinorTickSpacing(10);
slider.setPaintTicks(true);
slider.setPaintLabels(true);
setPreferredSize(new Dimension(400, 200));
JPanel bottomPanel = new JPanel();
bottomPanel.add(blinkBox);
bottomPanel.setOpaque(false);
blinkBox.setOpaque(false);
blinkBox.addItemListener(evt -> {
if (evt.getStateChange() == ItemEvent.SELECTED) {
timer.start();
} else {
timer.stop();
setBackground(null);
}
});
slider.addChangeListener(evt -> {
int value = slider.getValue();
timer.setDelay(value);
});
setLayout(new BorderLayout());
add(slider);
add(bottomPanel, BorderLayout.PAGE_END);
}
private class TimerListener implements ActionListener {
private boolean drawColor = false;
@Override
public void actionPerformed(ActionEvent e) {
Color color = drawColor ? null : COLOR;
BlinkEg.this.setBackground(color);
drawColor = !drawColor;
}
}
private static void createAndShowGui() {
BlinkEg mainPanel = new BlinkEg();
JFrame frame = new JFrame("BlinkEg");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
Обратите внимание, что для изменения времени таймера Swing просто вызовите его метод setDelay(...)
:
// timer changed to rate set by JSlider:
slider.addChangeListener(evt -> {
int value = slider.getValue();
timer.setDelay(value);
});
Чтобы начать и остановить мигание, просто запустите и остановите таймер:
// timer start and stopped based on JCheckBox state
blinkBox.addItemListener(evt -> {
if (evt.getStateChange() == ItemEvent.SELECTED) {
timer.start();
} else {
timer.stop();
setBackground(null); // so always stops with baseline color
}
});
Таймер Swing использует ActionListener, который использует логическое значение для определения цвета фона, а затем меняет значение логического
private class TimerListener implements ActionListener {
private boolean drawColor = false;
@Override
public void actionPerformed(ActionEvent e) {
// choose color based on the state of drawColor
Color color = drawColor ? null : COLOR;
BlinkEg.this.setBackground(color);
drawColor = !drawColor; // now toggle drawColor's boolean value
}
}