从单独的线程连续更新循环内的JLabel

时间:2016-12-20 20:44:12

标签: java multithreading swing

有没有办法从单独的线程中连续更新循环内的JLabel。现在,只有循环结束后,Jlabel才会更新。

如果错误,请纠正我,我认为这是因为事件调度程序线程暂停,直到另一个线程完成执行。

有什么办法可以同时运行两个线程吗?

我尝试在循环中给出一个Thread.sleep(300)但是没有用。

1 个答案:

答案 0 :(得分:4)

  

如果错误,请纠正我,我认为这是因为事件调度程序线程暂停,直到另一个线程完成执行。

这是错误的。如果另一个线程真正在Swing事件线程中运行,则两个线程应该同时运行。你有一个错误:

  1. 您认为自己正在逃离Swing事件线程,但您不是或
  2. 您认为您正在更新Swing事件线程中的GUI,但您并非如此。
  3. 最重要的是,您在代码中未显示错误,为了获得更好的答案,请显示相关代码。

    如,

    import java.awt.BorderLayout;
    import java.awt.FlowLayout;
    import java.awt.event.ActionEvent;
    import java.util.concurrent.TimeUnit;
    
    import javax.swing.*;
    
    @SuppressWarnings("serial")
    public class UpdateLabel extends JPanel {
        // label to update
        private JLabel statusLabel = new JLabel("");
    
        public UpdateLabel() {
            JPanel topPanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 3, 3));
            topPanel.add(new JLabel("Counter:"));
            topPanel.add(statusLabel);
    
            JPanel bottomPanel = new JPanel();
            bottomPanel.add(new JButton(new StartThreadAction("Start Thread")));
    
            setLayout(new BorderLayout());
            add(topPanel, BorderLayout.PAGE_START);
            add(bottomPanel, BorderLayout.PAGE_END);
        }
    
        // fail safe method that is guaranteed to add text to the label
        // **on the Swing event thread**
        public void setLabelText(final String text) {
            if (SwingUtilities.isEventDispatchThread()) {
                statusLabel.setText(text);
            } else {
                SwingUtilities.invokeLater(() -> {
                    statusLabel.setText(text);
                });
            }
        }
    
        // Abstract Action for our JButton
        private class StartThreadAction extends AbstractAction {
            protected static final int MAX_COUNT = 10;
            protected static final long SLEEP_TIME = 1;
    
            public StartThreadAction(String name) {
                super(name);
            }
    
            @Override
            public void actionPerformed(ActionEvent e) {
                // start a new thread
                new Thread(new Runnable() {
                    private int counter = 0;
    
                    @Override
                    public void run() {
                        // within the background thread update a counter and sleep
                        while (counter < MAX_COUNT) {
                            String text = "" + counter;
                            setLabelText(text); // call our fail safe method
                            counter++;
                            try {
                                // sleep for 1 second
                                TimeUnit.SECONDS.sleep(SLEEP_TIME);
                            } catch (InterruptedException e) {
                                // rare time it's OK to leave this blank
                            }
                        }
                    }
                }).start();
            }
        }
    
        private static void createAndShowGui() {
            UpdateLabel mainPanel = new UpdateLabel();
    
            JFrame frame = new JFrame("UpdateLabel");
            frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
            frame.getContentPane().add(mainPanel);
            frame.pack();
            frame.setLocationByPlatform(true);
            frame.setVisible(true);
        }
    
        public static void main(String[] args) {
            // start GUI on the Swing event thread
            SwingUtilities.invokeLater(() -> createAndShowGui());
        }
    }
    

    说完这一切之后,对于像延迟的简单计数这样的事情,我会使用Swing Timer,因为不用担心在EDT上打开或关闭代码,因为Timer保证所有的调用将在这个主题上。

    import java.awt.BorderLayout;
    import java.awt.FlowLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.event.KeyEvent;   
    import javax.swing.*;
    
    @SuppressWarnings("serial")
    public class UpdateLabel2 extends JPanel {
        // label to update
        private JLabel statusLabel = new JLabel("");
        private Timer timer;
    
        public UpdateLabel2() {
            JPanel topPanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 3, 3));
            topPanel.add(new JLabel("Counter:"));
            topPanel.add(statusLabel);
    
            JPanel bottomPanel = new JPanel();
            bottomPanel.add(new JButton(new StartTimerAction("Start Timer")));
    
            setLayout(new BorderLayout());
            add(topPanel, BorderLayout.PAGE_START);
            add(bottomPanel, BorderLayout.PAGE_END);
        }
    
        // Abstract Action for our JButton
        private class StartTimerAction extends AbstractAction {
            protected static final int MAX_COUNT = 10;
            private static final int TIMER_DELAY = 1000; // 1 second
            private int counter = 0;
    
            public StartTimerAction(String name) {
                super(name);
                putValue(MNEMONIC_KEY, KeyEvent.VK_S);
            }
    
            @Override
            public void actionPerformed(ActionEvent e) {
                if (timer != null && timer.isRunning()) {
                    return; // wait until timer finishes
                }
                timer = new Timer(TIMER_DELAY, new ActionListener() {
    
                    @Override
                    public void actionPerformed(ActionEvent e2) {
                        if (counter >= MAX_COUNT) {
                            timer.stop();
                            counter = 0;
                        } else {
                            counter++;
                            statusLabel.setText("" + counter);
                        }
                    }
                });
                timer.start();
            }
        }
    
        private static void createAndShowGui() {
            UpdateLabel2 mainPanel = new UpdateLabel2();
    
            JFrame frame = new JFrame("UpdateLabel");
            frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
            frame.getContentPane().add(mainPanel);
            frame.pack();
            frame.setLocationByPlatform(true);
            frame.setVisible(true);
        }
    
        public static void main(String[] args) {
            // start GUI on the Swing event thread
            SwingUtilities.invokeLater(() -> createAndShowGui());
        }
    }