【问题标题】:Java Swing display glitch when disabling buttons禁用按钮时 Java Swing 显示故障
【发布时间】:2018-06-12 11:20:00
【问题描述】:

我正在开发的一个小程序出现了一个奇怪的故障。它是 Pictionary 或 Charades 等游戏的记分员/计时器。

我将从程序应该做什么开始。单击 Start Timer 按钮禁用 Set Time、Reset Timer 和 Start Timer 按钮,然后开始计时器倒计时。倒计时本身是在一个线程中处理的,因此可以使用 Timer Stop 按钮将其停止。所有这些功能都运行良好,除了当我点击开始时发生的一个奇怪的小图形故障:

您可以看到“重置计时器”按钮的“幽灵”出现在数字上方,并且“6”的一点点出现在“重置计时器”按钮上方。这通常会发生,但有时会出现启动计时器的幽灵,或者有时什么都没有。这个“幽灵”在倒计时循环的下一次迭代和随后的计时器重绘中消失。

话虽如此,我已将问题追溯到禁用三个按钮。当我从我的代码中删除它时,没有任何故障。禁用按钮后,也许整个底部的 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();
}

【问题讨论】:

  • 对我来说最突出的是您的线程正在直接更新 UI 组件。这应该通过 EventQueue.invokeLater() 来处理。
  • 嗯...我还没有使用 EventQueue.invokeLater()。我仍然在学习线程方面搞砸了。我将不得不寻找一些关于它是如何工作的例子。如果我使用它,计时器中的数字还会实时更新吗?

标签: java swing button repaint display


【解决方案1】:

使用 Swing Timer 而不是单独的线程。

计时器将在您指定的时间间隔内生成一个事件。代码将在Event Dispatch Thread 上执行。然后你只需设置标签的文本。不需要paintImmediately(...)。

计时器还支持停止/启动方法,因此易于控制。

阅读 How to Use Swing Timers 上的 Swing 教程部分了解更多信息。

您还可以查看:Program freezes during Thread.sleep() and with Timer 的简单示例,它只是每秒更新时间。

【讨论】:

  • 哦,酷...这听起来比我在这里得到的要简单得多。我会研究一下并试一试。谢谢!
  • Swing Timer 运行良好,而且比我的代码更简洁。再次感谢!
  • @JeremyWilson,很高兴它有帮助。
猜你喜欢
  • 1970-01-01
  • 2010-09-11
  • 2014-07-09
  • 2014-05-15
  • 2012-10-10
  • 2020-07-31
  • 1970-01-01
  • 1970-01-01
  • 2013-08-13
相关资源
最近更新 更多