2015-05-08 14 views
7

Vì tôi đã cố gắng xem tôi có thể trả lời this question earlier today hay không. Tôi nhận ra rằng tôi không hoàn toàn hiểu được Event Dispatch Thread (EDT). Googling đều đã được xác nhận và trợ giúp với điều đó và làm rõ why I don't. (This cũng có thể liên quan đến sự hiểu biết.)Việc bỏ qua chuỗi gửi sự kiện cho phép chương trình này hoạt động như thế nào?

Mã thiết lập GUI và sau đó (như trong câu hỏi trước) cập nhật trường văn bản cho đến khi cờ không được đặt.

Tôi có một số câu hỏi/yêu cầu.

  • Xin giải thích tại sao đoạn code dưới đây chạy tốt nếu cả hai cuộc gọi (để swingInitdoIt) nằm ngoài invokeLater khối (như hình), vì cả hai cuộc gọi ảnh hưởng hoặc truy vấn GUI nhưng không được thực hiện trên EDT (là họ?) Đó không phải là sự mời gọi thất bại sao?

  • Mã cũng chạy nếu gọi đến swingInit nằm trong và doIt bên ngoài invokeLater. Vì vậy, swingInit được thực hiện trên EDT, nhưng không nên doIt không thực hiện trên EDT là một vấn đề? (Tôi đã rất ngạc nhiên rằng đây làm việc Tôi có nên có được.?)

  • Tôi đoán tôi hiểu tại sao nó bị treo nếu doIt là bên trong invokeLater không phân biệt nơi swingInit là: Mục đích của invokeLater chỉ dành khởi GUI (đúng?).

  • nên doIt chỉ được bắt đầu (có thể là từ một sự kiện xảy ra) trên EDT nhưng chắc chắn không bên invokeLater khối?

(Lịch sử của khái niệm EDT là thú vị. Nó không phải luôn luôn như vậy. Xem liên kết ở trên để "tại sao tôi không" hiểu nó.)

import static java.awt.EventQueue.invokeLater; 
import java.awt.event.*; 
import javax.swing.*; 

public class Whatever 
{ 
    static boolean flag = true; 
    static JTextField tf = new JTextField("Hi",20); 
    static JPanel p = new JPanel(); 
    static JFrame f = new JFrame(); 
    static JButton b = new JButton("End"); 

    public static void main(String[] args) 
    { 
    swingInit(); 

    invokeLater 
    (
     new Runnable() 
     { 
     @Override 
     public void run() 
     { 
    // swingInit(); 
    // doIt(); 
     } 
     } 
    ); 
    doIt();  
    } 

    static void swingInit() 
    { 
    b.addMouseListener 
    (
     new MouseAdapter() 
     { 
      @Override 
      public void mouseClicked(MouseEvent e) 
      { 
      flag = false; 
      JOptionPane.showMessageDialog(null,"Clicked... exiting"); 
      System.exit(0); 
      } 
     } 
    ); 

    p.add(tf); 
    p.add(b); 
    f.add(p); 
    f.setVisible(true); 
    f.pack(); 
    f.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); 
    } 

    static String getInfo(){ 
    return "Hello... " + Math.random(); 
    } 

    static void doIt(){ 
    while(flag)  
     tf.setText(getInfo()); 
    }; 
} 
+1

Như tôi nghĩ bạn hiểu, bạn không nên cập nhật GUI từ các chủ đề khác với EDT - tuy nhiên, làm như vậy không * nhất thiết * thất bại - nó chỉ là rất nguy hiểm. Vì vậy, đừng ngạc nhiên nếu mã như vậy đôi khi dường như làm việc. – DNA

Trả lời

3

Lấy mỗi điểm đạn của bạn:

  • Mã này được đưa ra trên thread chính - EDT được chạy song song. swingInit lợi nhuận sau khi xây dựng giao diện người dùng mà sau đó dưới kiểm soát của EDT, cho phép dotIt để làm điều này song song trên các chủ đề chính

  • tình huống tương tự như trên, nhưng ở đây bạn đang đảm bảo xây dựng các giao diện người dùng trên EDT (theo khuyến nghị của Oracle).

  • Nhiệm vụ chạy dài được đặt lên EDT, ngăn không cho nó hiển thị (nếu được đặt trước swingIt) hoặc vẽ và tương tác (nếu được đặt sau). the purpose of invokeLater is ONLY to initialize the GUI Mục đích là đặt các cuộc gọi Swing không an toàn vào trong EDT. Nếu trong phương pháp chính, tôi khuyên bạn nên sử dụng SwingUtilities.invokeAndWait

  • Nếu bạn muốn cập nhật giao diện người dùng như thế này, hãy cân nhắc làm như vậy với SwingTimer.

Chạy EDT cụ thể, không chủ đề đang an toàn bên ngoài EDT không đảm bảo thất bại, nhưng nó mời thất bại (thông qua mâu thuẫn khi hai (hoặc nhiều hơn) đề cố gắng để cập nhật dữ liệu ở cùng một lúc).

Tôi đã từng bỏ ra hàng giờ để theo dõi một số NullPointerException bí ẩn, chỉ để nhận ra đó là sự cố LookAndFeel có cuộc gọi không có trên EDT. Bài học kinh nghiệm.

+0

@ copeg - Cảm ơn bạn đã trả lời kỹ lưỡng. Chỉ một câu hỏi: Không nên "đảm bảo xây dựng giao diện người dùng trên EDT (* thực hành tốt *)" nói ".. trên EDT (* như hầu như được yêu cầu bởi Sun/Java edict về Swing không được an toàn thread *)"? – DSlomer64

+0

Bạn được chào đón - Tôi hy vọng nó làm rõ mọi thứ cho bạn ... trả lời chỉnh sửa dựa trên đề nghị của bạn – copeg

+0

Sự rõ ràng đang đến. – DSlomer64

2
static void doIt(){ 
    while(flag)  
    tf.setText(getInfo()); 
}; 

Đó bận rộn -loop bên trong doIt liên kết luồng GUI (quay trong vòng lặp đó), điều này sẽ làm cho GUI bị treo.

Bạn không thực sự giải thích ý bạn là "chạy tốt", nhưng tôi cho rằng đó là vấn đề bạn đang thấy.

Bạn có thể muốn sử dụng một số Swing Timer để làm điều gì đó giống như những gì bạn làm trong vòng lặp.

+0

Cảm ơn. "Chạy tốt" có nghĩa là trường văn bản được cập nhật liên tục "như mong đợi" với kết quả thay đổi hiển thị cho đến khi nút "Kết thúc" được nhấp. Mã nên chạy như là nếu bạn muốn xem những gì sẽ xảy ra. – DSlomer64

Các vấn đề liên quan