java - 从单独的线程持续更新循环内的 JLabel

标签 java multithreading swing

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

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

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

我尝试在循环内提​​供 Thread.sleep(300) 但没有成功。

最佳答案

Please do correct me if am wrong, I think this is because the Event Dispatcher Thread is on halt till the other thread finishes executing.

这是错误的。如果另一个线程确实在 Swing 事件线程之外运行,则两个线程应该同时运行。您遇到以下错误:

  1. 您认为自己正在脱离 Swing 事件线程,但事实并非如此
  2. 您认为正在更新 Swing 事件线程上的 GUI,但事实并非如此。

底线是您的代码中存在未显示的错误,为了获得更好的答案,请显示相关代码。

例如,

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

关于java - 从单独的线程持续更新循环内的 JLabel,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41250944/

相关文章:

java - 如何写带引号的SQL语句?

java - 即使 GetPrimitiveArrayCritical 失败,我是否应该始终调用 ReleasePrimitiveArrayCritical?

java - 使用 Swing Timer 和 invokeLater 更新 Swing 组件时如何防止死锁?

java - 使用 java.applet 类在 Java 中播放声音

java - 将多个对象添加到 JPanel 后,仅绘制最后一个 JComponent

java - Jersey 2 多部分/表单数据问题。输入流为空(可用=0)

c++ - 被连续迭代的线程安全无序映射

Python flask 如何避免同时访问多个文件(文件互斥)?

c - 实现交错多线程执行

swing - 没有 JMenuBar 的下拉菜单