Java JFrame repaint();如何使用线程信息更新JFrame?
我试着在JFrame上设置一个简单的计时器。我可以显示计数器的初始值,但任何后续更改都不会在JFrame上更新。对于我所做的错事,如果有人轻推我的答案,我将不胜感激。我认为这是一个无法调用repaint()的问题,但如果我尝试将其放入,结果可能会出现错误,或者什么都没有Java JFrame repaint();如何使用线程信息更新JFrame?,java,swing,Java,Swing,我试着在JFrame上设置一个简单的计时器。我可以显示计数器的初始值,但任何后续更改都不会在JFrame上更新。对于我所做的错事,如果有人轻推我的答案,我将不胜感激。我认为这是一个无法调用repaint()的问题,但如果我尝试将其放入,结果可能会出现错误,或者什么都没有 package com.game.ryan; import java.awt.Dimension; import javax.swing.JFrame; class Screen extends JFrame{ privat
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毫秒更新一次)。您可能希望重新考虑您的设计:
- 一个基本变量保存一个值,就这样。如果将原语保留的值指定给另一个变量,以后更改原始变量将不会影响另一个变量保留的值。例如,代码中的任何内容都不会更改JPanel所持有的计数器变量所持有的值
- 请注意,即使您的计划成功,您也有两个完全独立的单线程对象,更改其中一个对象的状态对另一个对象没有影响
- 最好让GUI侦听变量的更改,然后让线程更改变量的状态,然后通知所有侦听器此更改。PropertyChangeListener可以很好地实现这一点
- 请注意,Swing计时器比后台线程更容易实现
- 一个基本变量保存一个值,就这样。如果将原语保留的值指定给另一个变量,以后更改原始变量将不会影响另一个变量保留的值。例如,代码中的任何内容都不会更改JPanel所持有的计数器变量所持有的值
- 请注意,即使您的计划成功,您也有两个完全独立的单线程对象,更改其中一个对象的状态对另一个对象没有影响
- 最好让GUI侦听变量的更改,然后让线程更改变量的状态,然后通知所有侦听器此更改。PropertyChangeListener可以很好地实现这一点
- 请注意,Swing计时器比后台线程更容易实现
- 我看不到你告诉用户界面它应该自我更新的地方
在复制API中已经可用的内容方面,您也要走很长的路
摆动和螺纹需要仔细考虑。Swing使用单线程模型来管理UI的所有更新。预期UI的所有迭代都将在线程(也称为事件调度线程)的上下文中完成
这意味着,无论何时,您想要从任何其他线程创建或更新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()));
}
}
我没有看到你告诉UI它应该自我更新的地方 在复制API中已经可用的内容方面,您也要走很长的路 摆动和螺纹需要仔细考虑。Swing使用单线程模型来管理UI的所有更新。预期UI的所有迭代都将在线程(也称为事件调度线程)的上下文中完成 这意味着,无论何时,您想要从任何其他线程创建或更新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()));
}
}
swingutilities.invokeLater
委托给EventQueue.invokeLater
,所以这方面没什么…非常感谢大家。我一次又一次地看视频,感到很沮丧,于是决定尝试做点什么。我想你应该从某个地方开始。swingutilities.invokeLater
委托给EventQueue.invokeLater
,所以这方面没什么……非常感谢大家。我一次又一次地看视频,感到很沮丧,于是决定尝试做点什么。我想你得从某个地方开始。