请查看以下代码。
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JFrame;
import javax.swing.JPanel;
class thread_jishu extends Thread{
@Override
public void run(){
int p=-1;
for(;;){
//here continuously checking that whether
//the value of label_thread.i is equals to p or not
if(label_thread.i!=p){
try{
Thread.sleep(1000);
}catch(Exception e){}
label_thread.lb.setText("after sleeping at -> "+label_thread.i);
// here i want to set the JLabel
// text after waiting 1sec only when
// label_thread.i has been changed,
// but not happening
p=label_thread.i;
}
}
}
}
public class label_thread implements java.awt.event.ActionListener{
/**
* @param evt
*/
@Override
public void actionPerformed(java.awt.event.ActionEvent evt){
i+=1;
lb.setText("Button clicked at -> "+i);
}
static int i=-1;
static JLabel lb=new JLabel("hello here");
static JFrame window=new JFrame("Jishu");
static JFrame window2=new JFrame("Jishu");
public static void main(String[] args) {
// TODO code application logic here
new thread_jishu().start();
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setMinimumSize(new java.awt.Dimension(200,200));
JButton bt=new JButton("Click here");
bt.addActionListener(new label_thread());
JPanel panel=new JPanel();
panel.add(bt);
window.add(panel);
window2.add(lb);
window.setVisible(true);
window2.setVisible(true);
window2.setMinimumSize(new java.awt.Dimension(200,200));
}
}
当JLabel
的值不等于i
时,我想重置第二个窗口中的p
,这意味着在第一个窗口中点击了该按钮。
但点击按钮时JLabel
的文字未被更改。
答案 0 :(得分:0)
不应在AWT event thread之外修改Swing元素。如果您想在AWT事件线程中执行代码,可以使用SwingUtilities.invokeLater。
类似的东西:
SwingUtilities.invokeLater(new Runnable() {
@override
public void run() {
//Swing stuff here.
}
});
会让你非常接近。
答案 1 :(得分:0)
存在许多潜在问题;
static
static
没有帮助,从长远来看可能会导致各种问题。 static
不是一个跨对象的通信机制,你应该学习其他没有它的交易技术
Swing是单线程框架,它不是线程安全的,这基本上意味着你不应该在事件调度线程的上下文中执行长时间运行的任务,你也不应该在上下文之外修改UI的状态。 EDT(比如从另一个线程设置标签的文本)。
从Thread
内部访问变量并且存在问题,因为Thread
可以获得它自己的变量副本,这意味着对变量的读取和写入可以在线程,意味着他们可能看不到最新的价值。通常,您可以使用volatile
关键字或使用原子API(例如AtomicInteger
)解决此问题,但我认为通过更好的设计,您可以避免这些需求。
现在,您可以使用SwingWorker
或Swing Timer
,它们都提供了以节省方式控制EDT更新的解决方案,但您仍然使用线程。
你的程序受到基本的糟糕设计的影响,你将一堆属性暴露给不受控制的修改和访问,这使得很难解决类的责任(谁可以做什么以及何时做)。
所以,首先,我要定义一些控件
public interface Counter {
public int getCount();
public void setText(String text);
}
这个简单的界面提供对当前count
值的访问,并为另一个类提供了设置实现文本的方法。这定义了"合同"。这意味着,无论我将此接口的实例传递给谁,他们只能执行这两项任务,并且由实现决定如何控制这些操作
接下来,我设置Thread
....
public class ThreadJishu implements Runnable {
private Counter counter;
private int initialCount;
public ThreadJishu(Counter counter) {
this.counter = counter;
}
@Override
public void run() {
this.initialCount = counter.getCount();
while (true) {
if (counter.getCount() != initialCount) {
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
}
initialCount = counter.getCount();
counter.setText("After sleep at -> " + initialCount);
}
Thread.yield();
}
}
}
所以,这与你正在做的不同,除了,我依靠Counter
的实施来完成我需要做的工作。
最后,Counter
的实施,CounterPane
public class CounterPane extends JPanel implements Counter {
private int count = 0;
private JLabel label;
public CounterPane() {
label = new JLabel("Hello");
JButton btn = new JButton("Click here");
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
add(label, gbc);
add(btn, gbc);
btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
count++;
setText("Button click count = " + count);
}
});
Thread t = new Thread(new ThreadJishu(this));
t.start();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
@Override
public int getCount() {
return count;
}
@Override
public void setText(String text) {
if (EventQueue.isDispatchThread()) {
label.setText(text);
} else {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
setText(text);
}
});
}
}
}
这为用户提供了界面,并定义了Counter
的工作方式。在setText
方法中,我们有一个安全的保护措施,可以确保对JLabel
的所有修改都是在EDT的上下文中完成的,为简单起见,JButton
' ActionListener
实际上也使用setText
方法。
可运行的例子......
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class LabelThread {
public static void main(String[] args) {
new LabelThread();
}
public LabelThread() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new CounterPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public interface Counter {
public int getCount();
public void setText(String text);
}
public class CounterPane extends JPanel implements Counter {
private int count = 0;
private JLabel label;
public CounterPane() {
label = new JLabel("Hello");
JButton btn = new JButton("Click here");
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
add(label, gbc);
add(btn, gbc);
btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
count++;
setText("Button click count = " + count);
}
});
Thread t = new Thread(new ThreadJishu(this));
t.start();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
@Override
public int getCount() {
return count;
}
@Override
public void setText(String text) {
if (EventQueue.isDispatchThread()) {
label.setText(text);
} else {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
setText(text);
}
});
}
}
}
public class ThreadJishu implements Runnable {
private Counter counter;
private int initialCount;
public ThreadJishu(Counter counter) {
this.counter = counter;
}
@Override
public void run() {
this.initialCount = counter.getCount();
while (true) {
if (counter.getCount() != initialCount) {
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
}
initialCount = counter.getCount();
counter.setText("After sleep at -> " + initialCount);
}
Thread.yield();
}
}
}
}
并发是一个复杂的主题,因为Swing API的需求(比如大多数GUI API)而变得更加复杂。
看看:
了解更多细节和常见问题的可能解决方案
Timer
示例...... 使用Swing Timer
的简单实现,不需要Thread
public class CounterPane extends JPanel implements Counter {
private int count = 0;
private JLabel label;
private Timer timer;
public CounterPane() {
label = new JLabel("Hello");
JButton btn = new JButton("Click here");
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
add(label, gbc);
add(btn, gbc);
btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
count++;
setText("Button click count = " + count);
timer.restart();
}
});
timer = new Timer(1000, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
setText("After sleep at -> " + getCount());
}
});
timer.setRepeats(false);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
@Override
public int getCount() {
return count;
}
@Override
public void setText(String text) {
label.setText(text);
}
}