如何在没有ActionListener的情况下修改窗口中的JLabel?

时间:2014-08-30 16:31:05

标签: java swing while-loop jframe jlabel

我对JLabels有疑问。我正在尝试使用许多JLabel编写一个具有窗口(使用JFrame设置。)的应用程序。无论如何,我想知道是否有一种方法可以让窗口显示,然后修改JLabels的文本。我遇到的问题是,在程序到达课程结束之前,窗口不会显示。有没有办法解决这个问题?我必须使用线程吗?如果是这样,我该怎么做。 谢谢,   〜录音棚

示例:

public class Start extends JFrame{
   private static final long serialVersionUID = 1L;
  Random random = new Random();

  JPanel panel = new JPanel();
  JLabel label = new JLabel("Label");

  panel.add(label);
  add(panel);

  while(true){
    int rnd = random.nextInt(4);
    label.setText("" + rnd);
  }

} // I want to do that, but the window won't show until the loop ends. In this case, the loop
  // never will end. How would I do something like this if not the same exact thing?

2 个答案:

答案 0 :(得分:2)

让我们从Swing不是线程安全的事实开始,并且所有对UI的交互和修改都应该在Event Dispatching Thread的contentext中进行。

这也意味着您永远不会在事件调度线程的上下文中执行任何长时间运行或耗时的操作,因为这将阻止它处理放置在EventQueue上的新事件,包括重绘请求。 / p>

有关详细信息,请参阅Concurrency in Swing

最简单的解决方案是使用javax.swing.Timer。这将允许您安排定期回拨,保证在EDT的上下文中触发,从而可以安全地更新UI

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class RandomLabels {

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

    public RandomLabels() {
        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 TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private JLabel label;
        private Random rnd;

        public TestPane() {
            setLayout(new GridBagLayout());
            label = new JLabel();
            add(label);

            rnd = new Random();

            Timer timer = new Timer(40, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    label.setText(Integer.toString(rnd.nextInt()));
                }
            });
            timer.start();
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

    }

}

这也意味着你可以控制Timer,启动它并在你想要/需要时轻松停止它。

您可以使用Thread,但管理要求会增加......您负责管理UI更新的同步,以及必须实现实际停止线程的功能。

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.reflect.InvocationTargetException;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class RandomLabels {

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

    public RandomLabels() {
        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 TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private JLabel label;
        private Random rnd;

        public TestPane() {
            setLayout(new GridBagLayout());
            label = new JLabel();
            add(label);

            rnd = new Random();

            Thread t = new Thread(new Randomizer());
            t.start();
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        public class Randomizer implements Runnable {

            @Override
            public void run() {
                while (true) {
                    try {
                        EventQueue.invokeAndWait(new Runnable() {
                            @Override
                            public void run() {
                                label.setText(Integer.toString(rnd.nextInt()));
                            }
                        });
                    } catch (InterruptedException | InvocationTargetException exp) {
                        exp.printStackTrace();
                    }
                    try {
                        Thread.sleep(40);
                    } catch (InterruptedException ex) {
                    }
                }
            }

        }

    }

}

另一个(优于使用Thread)解决方案可能是使用SwingWorker。这将允许您在后台执行长时间运行/阻塞/耗时的操作,但提供了自动将更新轻松发送回UI的功能。

详细了解How to use Swing TimersWorker Threads and SwingWorker了解详情

最后,看看Initial Threads。您必须确保在EDT的上下文中启动/构建UI ...

答案 1 :(得分:-1)

在输入while循环之前,在构造函数中调用setVisibile。

public class Start extends JFrame {
    private static final long serialVersionUID = 1L;

    public Start() {
        Random random = new Random();

        JPanel panel = new JPanel();
        JLabel label = new JLabel("Label");

        panel.add(label);
        add(panel);

        this.setVisible(true); //IMPORTANT PART

        while(true){
            int rnd = random.nextInt(4);
            label.setText("" + rnd);
        }
    }
}