问题描述
是否有一种方法可以从单独的线程连续更新循环内的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:
- 您认为您正在用完Swing事件线程,但事实并非如此
- 您认为您正在更新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的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!