从单独的线程中不断更新循环内的JLabel

从单独的线程中不断更新循环内的JLabel

本文介绍了从单独的线程中不断更新循环内的JLabel的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否有一种方法可以从单独的线程连续更新循环内的JLabel.现在,仅在循环结束后才更新Jlabel.

Is there a way to continuously update a JLabel inside a loop from a separate thread. Right now the Jlabel gets only updated once the loop is over.

如果错了,请纠正我,我认为这是因为Event Dispatcher线程暂停,直到另一个线程完成执行.

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.

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

Is there any way that I can run both threads at the same time?

我尝试在循环中提供Thread.sleep(300),但是没有用.

I tried giving a Thread.sleep(300) inside the loop but didn't work.

推荐答案

这是错误的.如果另一个线程确实在Swing事件线程之外运行,则两个线程应同时运行.您有一个错误,其中一个:

This is wrong. If the other thread is truly running off of the Swing event thread, both should run simultaneously. You've got a bug where either:

  1. 您认为您正在用完Swing事件线程,但事实并非如此
  2. 您认为您正在更新Swing事件线程上的GUI,但不是.

最重要的是,您的代码中有一个未显示的错误,为了获得更好的答案,请显示相关的代码.

Bottom line is that you've got a bug in code not shown, and for better answers, show pertinent code.

例如

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上或在EDT上调用代码,因为Timer保证所有调用都将在此线程上进行.

Having said all this, for something like a simple count with delay, I'd use a Swing Timer because there's no worries about calling code on or off the EDT, since the Timer guarantees that all calls will be on this thread.

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

这篇关于从单独的线程中不断更新循环内的JLabel的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-21 12:33