Java 禁用按钮时摇摆显示故障
Java Swing display glitch when disabling buttons
我正在处理的一个小程序出现了一个奇怪的故障。 scorekeeper/timer 适用于 Pictionary 或 Charades 等游戏。
我将从程序应该做什么开始。单击启动计时器按钮将禁用设置时间、重置计时器和启动计时器按钮,然后开始计时器倒计时。倒计时本身在线程中处理,因此可以使用 Timer Stop 按钮将其停止。所有这些功能都运行良好,除了当我单击“开始”时发生的奇怪的小图形故障:
您可以看到 'ghost' 的“重置计时器”按钮出现在数字上方,并且“6”的一小部分出现在“重置计时器”按钮上方。这通常是发生的情况,但有时它是出现的开始计时器的幽灵,或者有时根本什么都没有。 'ghost' 在倒计时循环的下一次迭代及其随后的计时器重绘中消失。
话虽这么说,我已将问题追溯到三个按钮的禁用。当我从我的代码中删除它时,没有出现任何故障。也许在禁用按钮后整个底部的 JPanel 需要重新绘制?我不认为那是必要的。无论如何,我将在下面粘贴相关代码。我希望你能提供一些关于如何防止这种情况发生的建议。
public void disableButtons() {
timerStartButton.setEnabled(false);
resetTimerButton.setEnabled(false);
setTimeButton.setEnabled(false);
}
public void enableButtons() {
timerStartButton.setEnabled(true);
resetTimerButton.setEnabled(true);
setTimeButton.setEnabled(true);
}
public void timerThread(){
disableButtons();
timerRunning = true;
Thread t = new Thread(new Runnable(){
@Override
public void run(){
timerInterrupted = false;
while(timerRunning && timer > 0){
try {
timerLabel.setText(Integer.toString(timer));
timerLabel.paintImmediately(timerLabel.getVisibleRect());
Thread.sleep(1000);
} catch (InterruptedException ex) {
Logger.getLogger(ScoreTime.class.getName()).log(Level.SEVERE, null, ex);
}
timer--;
}
timerRunning = false;
if (!timerInterrupted) {
timer = 0;
timerLabel.setText(Integer.toString(timer));
if (soundOn) {
try {
//load the buzzer sound as a clip
AudioInputStream buzzerAudioIn = AudioSystem.getAudioInputStream(buzzerSoundFile);
Clip buzzerClip = AudioSystem.getClip();
buzzerClip.open(buzzerAudioIn);
buzzerClip.start();
Thread.sleep(1500);
} catch (UnsupportedAudioFileException | IOException | LineUnavailableException | InterruptedException ex) {
Logger.getLogger(ScoreTime.class.getName()).log(Level.SEVERE, null, ex);
}
}
else {
try {
Thread.sleep(1500);
} catch (InterruptedException ex) {
Logger.getLogger(ScoreTime.class.getName()).log(Level.SEVERE, null, ex);
}
}
timer = userTime;
timerLabel.setText(Integer.toString(timer));
enableButtons();
}
}
});
t.start();
}
使用 Swing 计时器而不是单独的线程。
定时器将在您指定的时间间隔生成一个事件。代码将在 Event Dispatch Thread
上执行。然后你只需设置标签的文本。不需要 paintImmediately(...)。
Timer也支持stop/start方法,方便控制。
阅读 How to Use Swing Timers 上的 Swing 教程部分了解更多信息。
您还可以查看:Program freezes during Thread.sleep() and with Timer 一个简单的示例,每秒更新一次时间。
我正在处理的一个小程序出现了一个奇怪的故障。 scorekeeper/timer 适用于 Pictionary 或 Charades 等游戏。
我将从程序应该做什么开始。单击启动计时器按钮将禁用设置时间、重置计时器和启动计时器按钮,然后开始计时器倒计时。倒计时本身在线程中处理,因此可以使用 Timer Stop 按钮将其停止。所有这些功能都运行良好,除了当我单击“开始”时发生的奇怪的小图形故障:
您可以看到 'ghost' 的“重置计时器”按钮出现在数字上方,并且“6”的一小部分出现在“重置计时器”按钮上方。这通常是发生的情况,但有时它是出现的开始计时器的幽灵,或者有时根本什么都没有。 'ghost' 在倒计时循环的下一次迭代及其随后的计时器重绘中消失。
话虽这么说,我已将问题追溯到三个按钮的禁用。当我从我的代码中删除它时,没有出现任何故障。也许在禁用按钮后整个底部的 JPanel 需要重新绘制?我不认为那是必要的。无论如何,我将在下面粘贴相关代码。我希望你能提供一些关于如何防止这种情况发生的建议。
public void disableButtons() {
timerStartButton.setEnabled(false);
resetTimerButton.setEnabled(false);
setTimeButton.setEnabled(false);
}
public void enableButtons() {
timerStartButton.setEnabled(true);
resetTimerButton.setEnabled(true);
setTimeButton.setEnabled(true);
}
public void timerThread(){
disableButtons();
timerRunning = true;
Thread t = new Thread(new Runnable(){
@Override
public void run(){
timerInterrupted = false;
while(timerRunning && timer > 0){
try {
timerLabel.setText(Integer.toString(timer));
timerLabel.paintImmediately(timerLabel.getVisibleRect());
Thread.sleep(1000);
} catch (InterruptedException ex) {
Logger.getLogger(ScoreTime.class.getName()).log(Level.SEVERE, null, ex);
}
timer--;
}
timerRunning = false;
if (!timerInterrupted) {
timer = 0;
timerLabel.setText(Integer.toString(timer));
if (soundOn) {
try {
//load the buzzer sound as a clip
AudioInputStream buzzerAudioIn = AudioSystem.getAudioInputStream(buzzerSoundFile);
Clip buzzerClip = AudioSystem.getClip();
buzzerClip.open(buzzerAudioIn);
buzzerClip.start();
Thread.sleep(1500);
} catch (UnsupportedAudioFileException | IOException | LineUnavailableException | InterruptedException ex) {
Logger.getLogger(ScoreTime.class.getName()).log(Level.SEVERE, null, ex);
}
}
else {
try {
Thread.sleep(1500);
} catch (InterruptedException ex) {
Logger.getLogger(ScoreTime.class.getName()).log(Level.SEVERE, null, ex);
}
}
timer = userTime;
timerLabel.setText(Integer.toString(timer));
enableButtons();
}
}
});
t.start();
}
使用 Swing 计时器而不是单独的线程。
定时器将在您指定的时间间隔生成一个事件。代码将在 Event Dispatch Thread
上执行。然后你只需设置标签的文本。不需要 paintImmediately(...)。
Timer也支持stop/start方法,方便控制。
阅读 How to Use Swing Timers 上的 Swing 教程部分了解更多信息。
您还可以查看:Program freezes during Thread.sleep() and with Timer 一个简单的示例,每秒更新一次时间。