Swing中的Thread和JLabel-无法正常工作 [英] Thread and JLabel in Swing- Not working properly

查看:59
本文介绍了Swing中的Thread和JLabel-无法正常工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请查看下面的代码.

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));
    }

}

i的值不等于p时,我想在第二个窗口中重置JLabel,这意味着在第一个窗口中单击了按钮.

I want to reset the JLabel in the 2nd window when the value of i is not equals to p that means the button is clicked in 1st window.

但是当单击按钮时,JLabel的文本不会更改.

But when button is clicked JLabel's text is not being changed.

推荐答案

存在许多潜在问题;

  • 过度使用/依赖static
  • 违反摆动线程
  • 变量的线程内存访问
  • 一般的不良设计.
  • Overuse/reliance on static
  • Swing thread violations
  • Thread memory access of variables
  • And general poor design.

static并没有帮助,从长远来看可能会引起各种各样的问题. static不是跨对象通信机制,如果没有它,您应该学习其他处理方法

static is not helpful and can cause all sorts of issues in the long run. static is not a cross object communication mechanism and you should learn other techniques for dealing without it

Swing是单线程框架,并且不是线程安全的,这基本上意味着您不应在事件调度线程的上下文中执行长时间运行的任务,并且也不应在以下情况的上下文之外修改UI的状态: EDT(例如从另一个线程设置标签文本).

Swing is single threaded framework and it is not thread safe, this basically means that you should not perform long running tasks within the context of the Event Dispatching Thread and you should also not modify the state of the UI from outside the context of the EDT (like setting the text of the label from another thread).

Thread内部访问变量并存在问题,因为Thread可以获取其自己的变量副本,这意味着可以在线程之间延迟对变量的读写,这意味着它们可能看不到最新值.通常,您可以使用volatile关键字或使用原子API(例如AtomicInteger)来解决此问题,但是我认为采用更好的设计可以避免这些需求.

Accessing variables from within Threads and be problematic, as the Thread can get it's own copy of the variable, this means that reads and writes to the variable can be delayed between threads, meaning that they may not see the latest value. Typically, you can resolve this with the volatile keyword or using the atomic API, like AtomicInteger, but I think with a little better design, you can avoid these needs.

现在,您可以使用SwingWorker或Swing Timer,它们都提供了以保存方式控制对EDT更新的解决方案,但是您仍然可以使用线程.

Now, you could use a SwingWorker or a Swing Timer, both of which provide solutions to controlling updates to the EDT in a save way, but you also still use a thread.

您的程序正遭受基本的不良设计之苦,您将一堆属性暴露给不受控制的修改和访问,从而难以解决类的职责(谁可以做什么,什么时候做什么).

You program is suffering from basic poor design, you're expose a bunch of properties to uncontrolled modifications and access, making it difficult to resolve the responsibilities of the classes (who can do what and when).

因此,首先,我将定义一些控件

So, to start with, I'm going to define some control

public interface Counter {
    public int getCount();
    public void setText(String text);
}

这个简单的接口提供对当前count值的访问,并为另一个类提供了一种设置实现文本的方法.这定义了合同".这意味着,无论我将这个接口的实例传递给谁,他们都只能执行这两个任务,并且要由实现来决定如何控制这些动作

This simple interface provides access to the current count value and provides a means for another class to set the text of the implementation. This defines the "contract". This means that who ever I pass an instance of this interface to, they can only perform those two tasks and it's up to the implementation to decide how those actions are controlled

接下来,我设置Thread ....

Next, I setup the 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的实现来完成我需要它执行的工作.

So, this isn't that different from what you were doing, except, I'm relying on the implementation of Counter to do the work I need it to do.

最后是CounterCounterPane

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的上下文内完成的,并且为简单起见,JButtonActionListener实际上使用了setText方法.

This provides the interface to the user as well as defines the workings of the Counter. In the setText method, we have a safe guard which ensures that all modifications to the JLabel are done from within the context of the EDT and for simplicity, the JButton's ActionListener actually uses the setText method as well.

可运行的示例...

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)的需要而变得更加复杂.

Concurrency is a complex subject to begin with, made more complicated by the needs of the Swing API (like most GUI APIs).

看看:

  • Concurrency in Swing
  • Worker Threads and SwingWorker
  • How to use Swing Timers

有关常见问题的更多详细信息和可能的解决方案

for more details and possible solutions for common problems

这是使用Swing Timer的简单实现,不需要Thread

And a simple implementation using a Swing Timer, no Thread's required

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);
    }

}

这篇关于Swing中的Thread和JLabel-无法正常工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆