简体   繁体   English

实时输出到jTextArea

[英]Output to jTextArea in realtime

I have some code which takes a few minutes to process, it has to connect to the web for each string in a long array, each string is a url. 我有一些代码需要花几分钟的时间来处理,它必须为长数组中的每个字符串连接到网络,每个字符串都是一个url。 I want to make it so that everytime it connects, it should refresh the jtextarea so that the user is not staring into a blank page that looks frozen for 20 min. 我想这样做,以便每次连接时都应刷新jtextarea,以使用户不会盯着看起来冻结20分钟的空白页。 or however long it takes. 或需要多长时间 here is an example of something i tried and didnt work: 这是我尝试但没有成功的示例:

try {
            ArrayList<String> myLinks = LinkParser.getmyLinksArray(jTextArea1.getText());
            for (String s : myLinks) {
                jTextArea2.append(LinkChecker.checkFileStatus(s) + "\n");
            }
        } catch (IOException ex) {
            JOptionPane.showMessageDialog(jTextArea1, "Parsing Error", "Parsing Error", JOptionPane.ERROR_MESSAGE);
            Logger.getLogger(MYView.class.getName()).log(Level.SEVERE, null, ex);
        }

The problem is that you need to perform the computation asynchronously. 问题是您需要异步执行计算。 You should create a background thread that performs the computation, and then use SwingUtilities.invokeLater to update the JTextArea. 您应该创建一个执行计算的后台线程,然后使用SwingUtilities.invokeLater更新JTextArea。

final ArrayList<String> myLinks = //...
(new Thread()
{
    public void run(){
        for (String s : myLinks) {
            try{
               final String result = LinkChecker.checkFileStatus(s) + "\n";
               SwingUtilities.invokeLater(new Runnable(){ 
                    public void run(){    
                      jtextArea2.append(result);
                    }
                });
             }catch(IOException error){
                // handle error
             }
        }
    }
}).start();

Edit 编辑
It has been pointed out that JTextArea's append function actually is thread safe (unlike most Swing functions). 已经指出,JTextArea的append函数实际上是线程安全的(不同于大多数Swing函数)。 Therefore, for this particular, case it is not necessary to update it via invokeLater. 因此,对于这种情况,不需要通过invokeLater更新它。 However, you should still do you processing in a background thread so as to allow the GUI to update, so the code is: 但是,您仍然应该在后台线程中进行处理,以允许GUI更新,因此代码为:

final ArrayList<String> myLinks = //...
(new Thread()
{
    public void run(){
        for (String s : myLinks) {
            try{
               jtextArea2.append(LinkChecker.checkFileStatus(s) + "\n");
             }catch(IOException error){
                // handle error
             }
        }
    }
}).start();

However, for pretty much any other operation that modifies a Swing object, you will need to use invokeLater (to ensure the modification occurs in the GUI thread), since almost all the Swing functions aren't thread safe. 但是,几乎所有其他修改Swing对象的操作都需要使用invokeLater(以确保修改发生在GUI线程中),因为几乎所有的Swing函数都不是线程安全的。

You need to investigate threading and its relationship to GUI updates in Swing. 您需要研究线程及其在Swing中与GUI更新的关系 Anything that affects or makes use of GUI components in Swing must done on a special thread called the Event Dispatch Thread (EDT) . 影响或使用Swing中GUI组件的任何事情都必须在称为事件调度线程(EDT)的特殊线程上完成。

If your code snippet, if it's freezing the GUI, I imagine that it is being run in the EDT. 如果您的代码段冻结了GUI,那么我想它正在EDT中运行。 Performing a long-running action on the EDT will make the GUI unresponsive, because no further updates can be done while your long-running process is using the thread. 在EDT上执行长时间运行的操作会使GUI无响应,因为长时间运行的进程正在使用线程时无法进行进一步的更新。

There is a helper class called SwingWorker that allows you to offload long-running computations to a background thread, and then make updates to the GUI thread when it is complete. 有一个名为SwingWorker的帮助程序类,它允许您将长时间运行的计算卸载到后台线程,然后在完成时对GUI线程进行更新。 The SwingWorker looks after the context switches between the GUI thread and the background thread. SwingWorker负责上下文在GUI线程和后台线程之间切换。 You can also display progress bars to let the user know the state of the long-running process, so they know your application hasn't hung. 您还可以显示进度条,以使用户知道长时间运行的进程的状态,以便他们知道您的应用程序尚未挂起。

swing/awt is a single threaded library, so once a component is shown, just changing it's appearance won't work correctly. swing / awt是一个单线程库,因此一旦显示了组件,仅更改其外观将无法正常工作。 You need to change the component on the GUI Thread, not from your thread. 您需要更改GUI线程上的组​​件,而不是从线程中更改。 To do this wrap any code that updates a component with SwingUtilities.invokeLater... as in 为此,请包装所有使用SwingUtilities.invokeLater ...更新组件的代码,如下所示:

SwingUtilities.invokeLater(new Runnable()
{
    public void run()
    {
        jTextArea2.append(LinkChecker.checkFileStatus(s) + "\n");
    }
});

also you want to limit what you do on the gui thread to avoid the gui from becoming sluggish, so if checkFileStatus is time consuming, execute it outside the run method and store the result in a final local variable, and just access the variable in the run() code. 另外,您还想限制对gui线程的操作,以避免gui变慢,因此,如果checkFileStatus很耗时,请在run方法外执行它,并将结果存储在最终的局部变量中,然后在run()代码。

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

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