我正在用按钮编写GUI。当用户点击按钮时,我希望开始工作......"消息立即出现在JTextArea中,并且"已完成。"工作完成时显示的消息。 GUI包含一些形式的代码
private void buttonActionPerformed(java.awt.event.ActionEvent evt) {
myJTextArea.append("Beginning work...\n");
<more lines of code>
myJTextArea.append("Finished.\n");
}
不幸的是,直到最后都没有出现任何消息。有没有办法将消息刷新到JTextArea?在另一个论坛上,我看到有人提到为JTextArea输出运行一个单独的线程。基于此的一些解决方案是否可行?
由于
答案 0 :(得分:5)
不幸的是,直到最后都没有出现任何消息。有没有办法将消息刷新到JTextArea?在另一个论坛上,我看到提到为JTextArea输出运行一个单独的线程。基于此的一些解决方案是否可行?
这与“刷新”JTextArea无关,而是与确保您的代码遵循Swing线程规则有关。输出到JTextArea的长时间运行的代码应该在后台线程中调用,例如使用SwingWorker。然后它会间歇性地将其结果输出到JTextArea,但确保在Swing事件线程上小心地。如果您使用SwingWorker,可以使用发布/处理方法对完成此操作。
请查看:Tutorial: Concurrency in Swing。
例如:
import java.util.List;
import javax.swing.*;
public class SwingThreadingEg extends JPanel implements MyAppendable {
private JTextArea area = new JTextArea(30, 50);
public SwingThreadingEg() {
JScrollPane scrollPane = new JScrollPane(area);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
add(scrollPane);
}
@Override
public void append(String text) {
area.append(text);
}
private static void createAndShowGui() {
SwingThreadingEg mainPanel = new SwingThreadingEg();
MyWorker myWorker = new MyWorker(mainPanel);
// add a Prop Change listener here to listen for
// DONE state then call get() on myWorker
myWorker.execute();
JFrame frame = new JFrame("SwingThreadingEg");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class MyWorker extends SwingWorker<Void, String> {
private static final long SLEEP_TIME = 500;
private MyAppendable myAppendable;
public MyWorker(MyAppendable myAppendable) {
this.myAppendable = myAppendable;
}
@Override
protected Void doInBackground() throws Exception {
publish("Beginning Work");
// simulate some long-running task:
for (int i = 0; i < 20; i++) {
publish("From SwingWorker: " + i);
Thread.sleep(SLEEP_TIME);
}
publish("Finished!");
return null;
}
@Override
protected void process(List<String> chunks) {
for (String text : chunks) {
myAppendable.append(text + "\n");
}
}
}
interface MyAppendable {
public void append(String text);
}
根据我的代码改编的代码来自previous similar question的答案。
注意,如果您要使用标准的Runnable和没有SwingWorker的后台线程,正如Lars所建议的那样,您首先要实现Runnable而不是扩展Thread,并且必须< / strong>注意大多数所有Swing调用都排队到事件线程,因此类似于:
@Override
public void actionPerformed(ActionEvent e) {
textarea.append("Start...");
new Thread(new Runnable(){
@Override
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
textarea.append("End");
}
});
}
}).start();
}
对于所有嵌套的匿名内部类,这看起来有点复杂,事实上这是SwingWorker在这种情况下可以更好地工作的主要原因之一,因为使用的代码更简单,减少了创建看不见的机会错误。
答案 1 :(得分:2)
另一个没有Worker的例子,只使用Thread:
package swingexperiments;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
public class SwingExperiment {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
private static void createAndShowGui() {
JFrame jFrame = new JFrame("Test");
jFrame.setLayout(new BorderLayout());
JTextArea textarea = new JTextArea();
jFrame.add(textarea, BorderLayout.CENTER);
jFrame.add(new JButton(new AbstractAction("Test") {
@Override
public void actionPerformed(ActionEvent e) {
textarea.append("Start..."); // here we are on the event dispatcher thread
new Thread() {
@Override
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
textarea.append("End");
}
});
}
}.start();
}
}), BorderLayout.SOUTH);
jFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
jFrame.pack();
jFrame.setSize(1000, 800);
jFrame.setVisible(true);
}
}