如何刷新到Java的JTextArea?

时间:2015-09-02 21:56:06

标签: java swing user-interface concurrency jtextarea

我正在用按钮编写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输出运行一个单独的线程。基于此的一些解决方案是否可行?

由于

2 个答案:

答案 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);
    }

}