【问题标题】:Refreshing JComponent to make a count down isn't working刷新 JComponent 倒计时不起作用
【发布时间】:2013-12-08 10:09:15
【问题描述】:

我制作了这个示例来对 java 对话消息倒计时 30 秒。不知何故,消息组件没有刷新,直到现在我才明白为什么。如果时间正在更新并且组件重新绘制它应该可以工作。我尝试重新绘制 message.repaint()messageFrame.repaint() 两个组件,但都没有工作。

下面的代码可以运行了。

import java.awt.Component;
import java.awt.Container;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Toolkit;

import javax.swing.JFrame;
import javax.swing.JLabel;

public class Chronometer {


    private static final Insets INSETS = new Insets(1, 1, 1, 1);


public Chronometer(){

    double timeToNext = System.currentTimeMillis() + 30000;
        double timeDifference = 30000;

    JFrame messageFrame = new JFrame();
    messageFrame.setLayout(new GridBagLayout());
    messageFrame.setTitle("Warning");
    JLabel message = new JLabel("Preventing connection block. Next query in " + timeDifference/1000 + " seconds.");
    messageFrame.setSize(1000,1000);
    messageFrame.setLocationRelativeTo(null);
    addComponent(messageFrame, message, 0, 0, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.CENTER);
    messageFrame.setVisible(true);

    while(timeDifference > 0){
        timeDifference = timeToNext - System.currentTimeMillis();
        messageFrame.repaint();
        //message.repaint();
    }
}


private static void addComponent(Container container, Component component, int gridx, int gridy,
        int gridwidth, int gridheight, int anchor, int fill) {

      GridBagConstraints gbc = new GridBagConstraints(gridx, gridy, gridwidth, gridheight, 1.0, 1.0,
    anchor, fill, INSETS, 0, 0);

      container.add(component, gbc);
      }


public static void main(String[] args){

Chronometer c = new Chronometer();
}

}

【问题讨论】:

    标签: java swing refresh components repaint


    【解决方案1】:

    你走错路了。在构造函数中使用 while 循环是个坏主意。 您应该改用计时器,因为这正是 Chronometer 的含义。我拿了你的代码并用计时器快速重写了它,并利用观察者模式来更新标签。

    使用实现 Observer 接口的控制器。

    import java.awt.Component;
    import java.awt.Container;
    import java.awt.GridBagConstraints;
    import java.awt.GridBagLayout;
    import java.awt.Insets;
    import java.util.Observable;
    import java.util.Observer;
    
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    
    public class Controller implements Observer {
        private static final Insets INSETS = new Insets(1, 1, 1, 1);
        private Chronometer chrono = new Chronometer();
        private final JLabel message = new JLabel();
    
        public Controller() {
            final JFrame messageFrame = new JFrame("Warning");
    
            messageFrame.setLayout(new GridBagLayout());
            messageFrame.setSize(1000,1000);
            messageFrame.setLocationRelativeTo(null);
    
            addComponent(messageFrame, message, 0, 0, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.CENTER);
    
            messageFrame.setVisible(true);
    
            chrono.addObserver(this);
        }
    
        public void startChrono(int delay) {
            chrono.startCountDown(delay);
        }
    
        public void refreshLabel() {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    message.setText("Preventing connection block. Next query in " + chrono.getTime()/1000 + " seconds.");
                }
            });
        }
    
        @Override
        public void update(Observable o, Object arg) {
            refreshLabel();
        }
    
        private static void addComponent(Container container, Component component, int gridx, int gridy, int gridwidth, int gridheight, int anchor, int fill) {
            GridBagConstraints gbc = new GridBagConstraints(gridx, gridy, gridwidth, gridheight, 1.0, 1.0,anchor, fill, INSETS, 0, 0);
            container.add(component, gbc);
        }
    }
    

    创建一个带有计时器的计时器类:

    import java.util.Observable;
    import java.util.Timer;
    import java.util.TimerTask;
    
    public class Chronometer extends Observable {
    
        private Timer timer = new Timer();
        private final int startTime = 30000;
        private int time = 30000;
    
        public void decreaseTime() {
            if (time > 0) time--;
        }
    
        public int getTime() {
            return time;
        }
    
        public void reset() {
            time = startTime;
        }
    
        public void startCountDown(int delay) {
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    decreaseTime();
                    setChanged();
                    notifyObservers();
                }
            }, delay,1);
        }
    }
    

    最后启动你的控制器

    public class Main {
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    new Controller().startChrono(1);
                }
            });
        }
    }
    

    【讨论】:

    • 谢谢,我会分析这段代码,当我尝试在我的主程序上执行此操作时,我只是实现了一个可运行的 cos,组件的更新变为空白,呵呵,你刚刚想出了另一部分我正在构建的解决方案哈哈哈 ty
    • 现在,这几乎是正确的。只需要修改以在事件调度线程中创建和访问 swing 组件 - 最好使用 swing Timer 而不是通用计时器,以便在 EDT 中进行标签更新。
    • @kiheru 我只是想指出在构造函数中使用 while 循环并在他的代码中添加一个计时器来演示是一个坏主意。如果您使用摆动计时器或其他计时器,则无关紧要,因为这是一个实现细节,在这种情况下,重要的是原理。
    • EDT == event dispatch thread。计时器的类型很重要,因为更改标签必须在 EDT 中完成。摆动计时器会自动执行此操作,对于 java.util.Timer,必须使用 SwingUtilities.invokeLater()
    • 不是唯一的更新。问题是在 EDT 之外调用 message.setText()(现在直接通过观察者。如果您不确定,请与 SwingUtilities.isEventDispatchThread() 联系)。那不是线程安全的。它“通常”似乎可以工作,但是 gui 程序越复杂,它就越有可能以看似随机的方式中断,除非它遵守线程规则。用invokeLater() 包裹那个电话就可以了。同样,GUI 的创建应该在 EDT 中完成。
    【解决方案2】:

    我认为您需要手动更新 JLabel 文本。尝试像这样更改您的 while 循环:

     while(timeDifference > 0) {
         timeDifference = timeToNext - System.currentTimeMillis();
         message.setText("Preventing connection block. Next query in " + timeDifference/1000 + " seconds.");
     }
    

    【讨论】:

    • 我不认为while循环是解决这个问题的方法,检查我的答案。
    猜你喜欢
    • 2013-05-09
    • 2017-03-05
    • 1970-01-01
    • 2016-12-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多