简体   繁体   English

在Java Swing GUI中立即输出文本的正确方法

[英]A proper way to output text immediately in Java Swing GUI

Such a piece of code: 这段代码:

private void log(String message) {
    LogBox.append(message + "\n");
}

private void log(Exception e) {
    log(e.getMessage());
}

private void ConvertButtonActionPerformed(java.awt.event.ActionEvent evt) {
    String url = UrlBox.getText();
    if (url.isEmpty()) {
        log("Empty URL");
        return;
    }
    LogBox.setText("");
    try {
        log("URL "+url+" accepted. Trying to download...");
        String content = URLConnectionReader.getText(url);
        log("Downloaded. Parsing the content...");
        //
    } catch (Exception e) {
        log(e);
    }
}

should output each message to the LogBox ( JTextArea ) immediately after each log call, but outputs URL ... accepted only when URLConnectionReader.getText(url) finishes. 应该在每个log调用之后立即将每个消息输出到LogBoxJTextArea ),但是输出URL ... accepted仅在URLConnectionReader.getText(url)完成时才URL ... accepted

There were several ways do do an immediate output: 有几种方法可以立即输出:

  • Application.DoEvents in Visual Basic 6 and .NET Visual Basic 6和.NET中的Application.DoEvents
  • Application.ProcessMessages in Delphi Delphi中的Application.ProcessMessages

Is there some simple way to do an immediate output? 有一些简单的方法可以立即输出吗? I was studying questions about the DoEvents and how to do this in Java, but I think that starting to learn Java from multi-threading isn't a right approach. 我正在研究有关DoEvents以及如何在Java中执行此操作的问题,但我认为从多线程开始学习Java是不正确的方法。

Create a SwingWorker to do the download: http://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html 创建一个SwingWorker来进行下载: http : //docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html


The role of an ActionListener is just that: to listen for user action, and initiate a response to that action by the program. ActionListener的作用就是:侦听用户操作,并由程序启动对该操作的响应。

Sometimes, the program's response is very quick, and only involves the GUI. 有时,程序的响应非常快,仅涉及GUI。 For example, in a calculator app, you could have a listener attached to an "equals" button that calculates the result of the current expression and writes it to a textbox. 例如,在计算器应用程序中,您可以将一个侦听器附加到“等于”按钮上,该按钮用于计算当前表达式的结果并将其写入文本框。 This can all be done within the listener method (although you might want to separate behavior for testing). 所有这些都可以在侦听器方法中完成(尽管您可能希望将行为分开进行测试)。

If the response to an user action is to initiate some long-running process, like downloading and parsing the file, then you don't want to do this within the listener body, because it will freeze the UI. 如果对用户操作的响应是启动一些长时间运行的过程(例如下载和解析文件),则您不想在侦听器主体中执行此操作,因为它将冻结UI。 Instead, gather any information (in your case, the URL value) from within the listener, and spin up a SwingWorker to handle the program's response. 而是从侦听器内部收集所有信息(在您的情况下为URL值),然后旋转SwingWorker来处理程序的响应。

In my comment, I suggested moving everything after the getText() into a SwingWorker . 在我的评论中,我建议将getText()之后的所有内容移动到SwingWorker This is because, to me, the response is "download a file if you have a valid URL, and log the progress." 对我来说,这是因为响应是“如果您具有有效的URL,请下载文件并记录进度”。 And as I see it, testing for an empty string is part of that response. 正如我所看到的,测试空字符串是该响应的一部分。 If you want to leave the empty-string test inside the listener, that's fine, but imo it's less testable. 如果您想将空字符串测试留在侦听器中,那很好,但是imo的测试性较差。

You must leave the call to getText() inside the body of the listener, because you are only allowed to access Swing components from the event dispatch thread. 必须将对getText()的调用留在侦听器的主体内,因为只允许您从事件分发线程访问Swing组件。 If you moved that call into the worker, then it might access the textbox at the same time the textbox is updating itself, resulting in corrupt data. 如果将该呼叫移至工作程序中,则它可能会在文本框更新自身的同时访问该文本框,从而导致数据损坏。

Read up on Concurrency . 阅读并发

You should probably use a SwingWorker for the long running task, then you can publish results to the GUI as they become available. 您可能应该将SwingWorker用于长时间运行的任务,然后在结果可用时publish到GUI。

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

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