0

我试图在 JFrame 上设置一个简单的时间记录器。我能够显示计数器的初始值,但任何后续更改都不会在 JFrame 上更新。任何对我做错的事情的回答都会受到赞赏。我认为这是 repaint() 没有被调用的问题,但是我要么最终出现错误,要么尝试将其放入。

package com.game.ryan;
import java.awt.Dimension;
import javax.swing.JFrame;
class Screen extends JFrame{


private Dimension d = new Dimension(800,600);
private JFrame f;

public Screen(){
    f = new JFrame();
    f.setIgnoreRepaint(false);
    f.setResizable(false);
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    f.setMinimumSize(d);
    f.setLocationRelativeTo(null);
    f.add(new MyPanel());
    f.pack();
    f.setVisible(true);
}

public static void main(String[] args){
    Screen s = new Screen();
}

}

我也有:

package com.game.ryan;

import java.awt.Graphics;

import javax.swing.JPanel;

public class MyPanel extends JPanel{

private OneThread ot = new OneThread();
private int counter = ot.getThreadCounter();

public MyPanel(){
    Thread t1 = new Thread(new OneThread());
    t1.start();

}

public void paintComponent(Graphics g){
    g.drawString("TIME: ", 10, 20);
    g.drawString(Integer.toString(counter), 50, 20);        
}
}

最后

package com.game.ryan;

public class OneThread implements Runnable{

private int counter = 45;

public OneThread(){

}

@Override
public void run() {

    for(int x = 0; x >= 0; x++){
        try{
            Thread.sleep(1000);
            counter++;
            x++;
            System.out.println(counter);

        }catch(Exception e){
            e.printStackTrace();
        }
    }       
}

public int getThreadCounter(){
    return counter;
}
}

我在控制台上的计数器越来越多,所以我猜这部分工作正常。

预期结果是计数器在 JFrame 中正确显示(每 1000 毫秒更新一次)。

4

2 回答 2

2

您可能希望重新考虑您的设计:

  • 原始变量保存一个值,仅此而已。如果您将原语持有的值分配给另一个变量,那么稍后更改原始变量将不会影响另一个变量持有的值。例如,您的代码中的任何内容都不会更改 JPanel 所持有的 counter 变量所持有的值。
  • 请注意,即使您的计划成功,您也有两个完全独立的 OneThread 对象,并且更改一个对象的状态不会影响另一个对象。
  • 最好让您的 GUI 侦听变量的更改,然后让您的线程更改变量的状态,然后通知所有侦听器此更改。PropertyChangeListener 可以很好地解决这个问题。
  • 请注意,Swing 计时器比后台线程更容易实现。
于 2013-05-31T03:01:00.877 回答
2

我没有看到您告诉 UI 它应该自行更新的任何地方。

在复制 API 中已有的内容方面,您还需要走很长一段路。

摆动和线程需要仔细考虑。Swing 使用单线程模型来管理 UI 的所有更新。预计所有与 UI 的迭代都将在线程(AKA 事件调度线程)的上下文中完成。

这意味着任何时候您想从任何其他线程创建或更新 UI,您都需要将调用同步回 EDT。

虽然有很多方法可以实现这一点,但在您的情况下最简单的是使用javax.swing.Timer

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class LabelClock {

    public static void main(String[] args) {
        new LabelClock();
    }

    protected static final DateFormat DATE_FORMAT = new SimpleDateFormat("HH:mm.ss");
    private JLabel clock;

    public LabelClock() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                clock = new JLabel();
                tick();

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new GridBagLayout());
                frame.add(clock);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);

                Timer timer = new Timer(500, new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        tick();
                    }
                });
                timer.setRepeats(true);
                timer.setCoalesce(true);
                timer.start();
            }
        });
    }

    protected void tick() {
        clock.setText(DATE_FORMAT.format(new Date()));
    }

}
于 2013-05-31T03:06:25.627 回答