简体   繁体   English

如何刷新Java的JTextArea?

[英]How do I flush to Java's JTextArea?

I am writing a GUI with a button. 我正在用一个按钮编写一个GUI。 When the user clicks the button, I would like a "Beginning work..." message to appear in a JTextArea immediately, and a "Finished." 当用户单击该按钮时,我希望立即在JTextArea中显示“Beginning work ...”消息,并显示“已完成”。 message to appear when the work is done. 工作完成时显示的消息。 The GUI contains some code of the form GUI包含表单的一些代码

private void buttonActionPerformed(java.awt.event.ActionEvent evt) {
    myJTextArea.append("Beginning work...\n");

    <more lines of code>

    myJTextArea.append("Finished.\n");
}

Unfortunately, neither message appears until the end. 不幸的是,直到最后才会出现任何消​​息。 Is there a way to flush messages to JTextArea? 有没有办法将消息刷新到JTextArea? On another forum, I saw people mention running a separate thread for the JTextArea output. 在另一个论坛上,我看到有人提到为JTextArea输出运行一个单独的线程。 Would some solution based on that be possible? 基于此的一些解决方案是否可行?

Thanks 谢谢

Unfortunately, neither message appears until the end. 不幸的是,直到最后才会出现任何消​​息。 Is there a way to flush messages to JTextArea? 有没有办法将消息刷新到JTextArea? On another forum, I saw mention running a separate thread for the JTextArea output. 在另一个论坛上,我看到提到为JTextArea输出运行一个单独的线程。 Would some solution based on that be possible? 基于此的一些解决方案是否可行?

This has nothing to do with "flushing" the JTextArea, and all to do with making sure that your code follows Swing threading rules. 这与“刷新”JTextArea无关,而是与确保您的代码遵循Swing线程规则有关。 The long running code that is outputting to the JTextArea should be called in a background thread such as with a SwingWorker. 输出到JTextArea的长时间运行的代码应该在后台线程中调用,例如使用SwingWorker。 Then it would intermittently output its results to the JTextArea, but making sure to do so carefully on the Swing event thread . 然后它将间歇性地将其结果输出到JTextArea,但确保在Swing事件线程上小心地这样做。 If you use a SwingWorker, this could be done using the publish/process method pair. 如果您使用SwingWorker,可以使用发布/处理方法对完成。

Have a look at: Tutorial: Concurrency in Swing . 看看: 教程:Swing中的并发

For example: 例如:

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

Code adapted from my code from an answer to a previous similar question . 代码改编自我的代码,回答了以前的类似问题


Note, if you're going to use a standard Runnable and a background Thread without a SwingWorker, as Lars recommends, you'll first of all want to implement a Runnable and not extend Thread, and you must take care that most all Swing calls are queued onto the event thread, thus something like: 注意,如果您打算使用标准的Runnable和没有SwingWorker的后台线程,正如Lars所建议的那样,您首先要实现Runnable而不是扩展Thread,并且您必须注意大多数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();
}

This looks a bit complicated what with all the nested anonymous inner classes, and in fact this is one of the main reasons why a SwingWorker may work better in this situation, since the code used is simpler, reducing the chances of creating unseen bugs. 对于所有嵌套的匿名内部类,这看起来有点复杂,事实上这是SwingWorker在这种情况下可以更好地工作的主要原因之一,因为使用的代码更简单,减少了创建看不见的错误的机会。

Another example without a Worker, just using Thread: 另一个没有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);
    }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM