【问题标题】:How do I flush to Java's JTextArea?如何刷新到 Java 的 JTextArea?
【发布时间】:2015-09-02 21:56:05
【问题描述】:

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

谢谢

【问题讨论】:

    标签: java swing user-interface concurrency jtextarea


    【解决方案1】:

    不幸的是,直到最后都没有出现任何消​​息。有没有办法将消息刷新到 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,并且您必须 请注意大多数 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 在这种情况下可能会更好地工作的主要原因之一,因为使用的代码更简单,减少了创建看不见的机会错误。

    【讨论】:

      【解决方案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);
          }
      
      }
      

      【讨论】:

      • 谢谢。请注意,textarea.append("Start...") 不需要排队到事件线程上,因为它已经被调用了。只有后台线程代码需要这个,但这已经足够了。 1+。
      • 是的,我也意识到了这一点。感谢您的反馈意见!还有点赞:)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-09
      • 1970-01-01
      • 2011-09-18
      • 2011-11-24
      • 1970-01-01
      相关资源
      最近更新 更多