繁体   English   中英

Java Swing Concurrency显示JTextArea

[英]Java Swing Concurrency display JTextArea

我需要执行/显示从Arraylist到JTextArea的一系列事件,但是,每个事件都会以不同的时间执行。 以下是我的目标的一个简单示例:

public void start(ActionEvent e)
 {
  SwingUtilities.invokeLater(new Runnable()
  {
   public void run()

   {
    jTextArea.append("Test" + "\n");
    try
    {
     Thread.sleep(3000);
    } catch (InterruptedException e1)
    {
     e1.printStackTrace();
    }
    jTextArea.append("Test1" + "\n");
   }
  });
 }

所以现在,整个执行完成后,“Test”和“Test1”会显示在JTextArea上。 如何首先显示“测试”,然后3秒后显示“Test1”

提前谢谢你们

invokeLater计划runnable在Event Dispatch Thread上运行。 你不应该睡在它里面,否则你会使调度线程饿死。 请尝试使用单独的工作线程:

Thread worker = new Thread(new Runnable(){
    public void run(){
        jTextArea.append("Test" + "\n");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }
        jTextArea.append("Test1" + "\n");

    }
});
worker.start();

如果您的任务是时间/ CPU密集型,那么肯定是使用后台线程来执行此操作,例如SwingWorker对象或线程中的Runnable运行。 但是,如果您需要做的是错开某些东西的显示,而您正在寻找的是Swing等效的Thread.sleep(3000),那么您最好的选择是使用Swing Timer。 有一个很好的教程如何使用这些,你可以在这里找到: http//download.oracle.com/javase/tutorial/uiswing/misc/timer.html

例如:

 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import javax.swing.*;

 public class Fu extends JPanel {
      private static final int TIMER_DELAY = 600;
      protected static final int MAX_COUNT = 20;
      private JTextArea jTextArea = new JTextArea(10, 10);
      private JButton startBtn = new JButton("Start");
      private Timer timer;

      public Fu() {
           startBtn.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                     startAction(e);
                }
           });

           add(new JScrollPane(jTextArea, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, 
                     JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED));
           add(startBtn);
      }

      private void startAction(ActionEvent e) {
           if (timer != null && timer.isRunning()) {
                // prevent multiple instances of timer from running at same time
                return;
           }
           timer = new Timer(TIMER_DELAY, new ActionListener() {
                private int count = 0;
                public void actionPerformed(ActionEvent e) {
                     if (count < MAX_COUNT) {
                          count++;
                          jTextArea.append("Test " + count + "\n");
                     } else {
                          jTextArea.append("Done! \n");
                          timer.stop();
                          timer = null;
                     }
                }
           });
           timer.setInitialDelay(0);
           timer.start();
      }

      public static void main(String[] args) {
           SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                     JFrame frame = new JFrame("Foo");
                     frame.getContentPane().add(new Fu());
                     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                     frame.pack();
                     frame.setLocationRelativeTo(null);
                     frame.setVisible(true);
                }
           });
      }
 }

正如所指出的,这是一个坏主意,因为您将阻止事件线程。

但是,了解其原因也很重要。 您似乎知道,影响Swing组件状态的所有代码都需要在事件处理线程中发生(这就是为什么应该始终使用invokeLater和朋友的原因)。

更不为人知的是,痛苦代码也在事件处理线程中执行。 当您对Thread.sleep的调用正在执行时,它不仅会阻塞事件线程,还会阻止任何组件绘制。 这就是全面更新似乎一次性发生的原因 - JTextArea已更新,但在run方法返回之前无法重新绘制。

这里提供了大量信息: http//java.sun.com/products/jfc/tsc/articles/threads/threads1.html

暂无
暂无

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

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