2010-04-02 22 views
13

Sự hiểu biết của tôi là nếu tôi bắt đầu một chuỗi khác để thực hiện một số hành động, tôi cần phải SwingUtilities.invokeAndWait hoặc SwingUtilities.invokeLater để cập nhật GUI trong khi tôi đang ở trong chuỗi đã nói. Nêu tôi sai vui long chân chỉnh tôi.Java's Swing Threading

Điều tôi đang cố gắng thực hiện tương đối đơn giản: khi người dùng nhấp vào gửi, tôi muốn (trước khi thực hiện bất kỳ hành động nào) vô hiệu hóa nút gửi, thực hiện tác vụ và vào cuối hành động bật lại nút. Phương pháp của tôi để thực hiện hành động cập nhật GUI trực tiếp (hiển thị kết quả) khi nó nhận được kết quả.

Hành động này về cơ bản sẽ truy vấn máy chủ và nhận lại một số kết quả.

Những gì tôi có cho đến nay là:

boolean isRunning = false; 

synchronized handleButtonClick() { 
    if (isRunning == false) { 
    button.setEnabled(false); 
    isRunning = true; 
    doAction(); 
    } 
} 

doAction() { 
    new Thread() { 
    try { 
     performAction(); // Concern A 
    } catch (...) { 
     displayStackTrace(...); // Concern B 
    } finally { 
     SwingUtilities.invokeLater (/* simple Runnable to enable button */); 
     isRunning = false; 
    } 
    } 
} 

Đối với cả hai mối quan tâm của tôi ở trên, tôi sẽ phải sử dụng SwingUtilities.invokeAndWait kể từ khi cả hai đều sẽ cập nhật giao diện? Tất cả các bản cập nhật GUI xoay quanh việc cập nhật JTextPane. Tôi có cần phải kiểm tra thread của tôi nếu tôi đang trên EDT và nếu như vậy tôi có thể gọi mã của tôi (bất kể nó cập nhật GUI hay không) và không sử dụng SwingUtilities.invokeAndWait?

EDIT: Đây là những gì tôi đang làm bây giờ:

handleButtonClick() { 
    if (isRunning == true) 
    return; 
    disable button; 
    SwingWorker task = new MyTask(); 
    task.execute(); 
} 

...inside MyTask 
doInBackground() { 
    return performAction(); 
} 

done() { 
    result = get(); 
    enable button; 
    isRunning = false; 
    interpret result (do most of the GUI updates here); 
} 

Trong khi performAction() hiện một số cập nhật giao diện, tôi đã quấn những người trong:

if (SwingUtil.isEDT()) 
    doGUIupdate() 
else 
    SwingUtil.invokeLater(new Runnable() { 
    run() { 
     doGUIupdate(); 
    } 
    }); 

Hy vọng rằng đây là một bước đi đúng hướng , xin vui lòng bình luận nếu bạn tin rằng có những cách tốt hơn để xử lý tình hình của tôi.

+1

Sử dụng SwingWorker. http://java.sun.com/javase/6/docs/api/javax/swing/SwingWorker.html –

+0

Tôi đã ấn tượng rằng SwingWorker nên được sử dụng cho một cái gì đó "dài" trong khi SwingUtilities được sử dụng cho một cái gì đó "nhanh" ? – nevets1219

+0

Bởi vì SwingUtilities thực hiện trên luồng "UI", nó sẽ phải được sử dụng cho một cái gì đó nhanh chóng để được thực tế; nếu không nó có thể chặn giao diện người dùng. Sẽ không thực thi trong "chuỗi khác". –

Trả lời

18

Theo tôi bạn nên hầu như không bao giờ sử dụng invokeAndWait(). Nếu có điều gì đó sẽ mất một lúc để khóa giao diện người dùng của bạn.

Sử dụng một SwingWorker cho loại điều. Hãy xem Improve Application Performance With SwingWorker in Java SE 6.

+0

Liên kết tuyệt vời, một nửa thông qua và nó đã tiết lộ khá một chút với tôi! – nevets1219

+1

invokeAndWait() không chặn giao diện người dùng - nó chặn chuỗi trình trợ giúp cho đến khi giao diện người dùng đã có cơ hội chạy Runnable đã qua. invokeAndWait() thực sự kiểm tra để chắc chắn rằng nó không được gọi từ EDT (mà có thể gây ra khóa). Tất nhiên tôi nên nói rằng việc sử dụng invokeAndWait() thường có nghĩa là lập trình viên không đúng cách sử dụng lập trình hướng sự kiện (quan sát) ... –

+1

Sử dụng 'invokeAndWait' thường dẫn đến bế tắc. –

5

Bạn nên cân nhắc sử dụng SwingWorker vì nó sẽ không chặn chuỗi giao diện người dùng, trong khi cả hai phương pháp SwingUtilities sẽ thực thi trên chuỗi EDT, do đó chặn giao diện người dùng.

+1

SwingWorker thực hiện phương thức done() trên EDT. Nó giống như bắt đầu chuỗi không phải EDT của riêng bạn mà gọi SwingWorker.invokeLater() để cập nhật giao diện người dùng khi bạn hoàn tất. SwingWorker chỉ là một chút thuận tiện hơn để sử dụng hơn là lăn nó cho mình. –

+0

Điểm tốt; Tôi vẫn khuyên bạn nên sử dụng 'SwingWorker'. –

+1

@Scott bạn có nghĩa là SwingUtilities không? – nevets1219

0

tôi giữ đơn giản Thread bên EventQueue.invokeLater(...) và làm việc trơn tru ...

java.awt.EventQueue.invokeLater(new Runnable() { 
    public void run(){ 

     new Thread(new Runnable(){ 
      public void run(){ 

       try{ 
        EdgeProgress progress = EdgeProgress.getEdgeProgress(); 
        System.out.println("now in traceProgressMonitor..."); 
        while(true){ 
         // here the swing update 
         if(monitor.getState() == ProgressMonitor.STATE_BUSY){ 
          System.out.println(monitor.getPercentDone()/2); 
          progress.setProgress(monitor.getPercentDone()/2); 
         }else{ 
          break; 
         } 
         Thread.sleep(5); 
        } 
       }catch(InterruptedException ie){} 

      } 
     }).start(); 

    } 
});