簡體   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