2012-08-06 70 views
9

Tôi có một vài câu hỏi liên quan đến Swing và sử dụng EDT để cập nhật GUI. Tôi mới bắt đầu đọc về nội dung này vì vậy tôi là người mới bắt đầu đầy đủ trong lĩnh vực này:Java Swing - chạy trên EDT

  1. Hoạt động nào bắt buộc phải chạy trên EDT? Nếu họ không, chỉ đơn giản là một ngoại lệ lớn lên?
  2. Có thời điểm cụ thể nào khi chúng tôi thực sự ở trên EDT tự động không?
  3. nếu chúng tôi lên lịch một tác vụ bằng cách sử dụng SingUtilities.invokeLater, chúng tôi sẽ đưa nó vào hàng đợi hiện tại của các tác vụ cập nhật GUI ngay?
  4. Truy cập vào hàng đợi ở trên tôi đoán là đã đồng bộ hoặc một số bộ sưu tập đồng thời được sử dụng, nhưng nếu tôi lên lịch hai tác vụ cập nhật GUI, từ hai chủ đề nền, không thể nói cái nào sẽ được thêm trước? Ví dụ, nếu Thread 1 FIRST đệ trình một nhiệm vụ thiết lập văn bản của một JLable thành "yes", và sau đó, thời gian ngắn sau đó, chuỗi thứ hai xuất hiện và gửi nhiệm vụ thiết lập giá trị đó tới "no", chúng tôi có đảm bảo rằng kết quả sẽ là "có", hoặc chỉ đơn giản là vấn đề làm thế nào những điều này được lên lịch bởi hệ điều hành?
  5. Làm thế nào chính xác SwingWorker đảm bảo rằng phương pháp done() được chạy trên EDT? Nó đặt đoạn mã sau:

    future = new FutureTask<T>(callable) { 
           @Override 
           protected void done() { 
            doneEDT(); 
            setState(StateValue.DONE); 
           } 
          }; 
    

vì vậy tôi đã tự hỏi liệu FutureTask bằng cách nào đó làm cho chắc chắn rằng invokeLater được gọi là?

Cảm ơn mọi câu trả lời của bạn.

Trả lời

14
  1. Nguyên tắc tốt là tất cả các hoạt động (truy cập/cập nhật/...) sẽ xảy ra trên EDT. Có một vài ngoại lệ được đề cập trong javadoc (một số phương thức nhất định của các lớp nhất định), nhưng chúng rất khó để nhớ rằng nó dễ dàng hơn để gắn bó với phương pháp 'làm mọi thứ trên EDT'. Ngoại lệ sẽ không được nâng lên (may mắn thay, JavaFX đã sửa lỗi này). Bạn có thể sử dụng tùy chỉnh RepaintManager để phát hiện hầu hết các vi phạm sau: xem this article.
  2. Mọi thứ được kích hoạt bởi người dùng được xử lý trên EDT. Ví dụ: nếu người dùng nhấp vào nút, thì actionPerformed của số Action hoặc ActionListener tương ứng sẽ được gọi trên EDT.
  3. Chính xác
  4. Điều bạn lên lịch trước tiên sẽ được thực thi trước. Cuộc gọi invokeLater chỉ cần thêm Runnable vào cuối hàng đợi. Sử dụng invokeLater lần thứ hai sau đó một chút sẽ thêm Runnable mới này sau số Runnable được lập lịch trước đó.
  5. Hãy nhìn vào mã cho doneEDT

    private void doneEDT() { 
        Runnable doDone = 
         new Runnable() { 
          public void run() { 
           done(); 
          } 
         }; 
        if (SwingUtilities.isEventDispatchThread()) { 
         doDone.run(); 
        } else { 
         doSubmit.add(doDone); 
        } 
    } 
    
+0

Hai câu hỏi: 4. Vì vậy, đây là luồng đầu tiên thực hiện cuộc gọi sau phải không? Vì vậy, nó có thể là trường hợp mà hệ điều hành sẽ lên lịch các chủ đề nền thứ hai invokeLater gọi FIRST và thứ tự sẽ được điều sai lầm? 5. Tôi vẫn không thấy làm thế nào mà đạt được EDT. do Submit thêm Runnable vào AccumulativeRunnable ... – Bober02

+0

@ Bober02 Xem javax.swing.SwingWorker.DoSubmitAccumulativeRunnable runnable, được thực thi trên EDT do sử dụng Swing 'Timer'. Đối với 4: có, bạn sẽ phải đảm bảo rằng một thread nền của bạn lên lịch chạy trước khi thread khác lên lịch runnable của nó nếu bạn muốn kiểm soát thứ tự – Robin

+1

Tại một thời điểm, mọi thứ được gửi tới doSubmit() được chạy trong EDT. Bạn không cần phải quan tâm làm thế nào và nơi nó được thực hiện: lớp này đã được thử nghiệm, và nó hoạt động như tài liệu. –

-1

1. Trong Java ứng dụng GUI, main() phương pháp không được tồn tại lâu dài, sau khi lên kế hoạch xây dựng GUI trongEvent Dispatcher Thread, các main()phương pháp bỏ ... và Bây giờ trách nhiệm EDT của nó để xử lý các GUI.

2. Vì vậy, chúng tôi không cần phải bắt đầu ứng dụng của mình trên EDT, tự động hoàn thành.

Luôn giữ giao diện người dùng hoạt động trên chuỗi giao diện người dùng và không hoạt động trên giao diện người dùng trên chuỗi không phải UI.

Vì vậy, Luôn luôn giữ chuỗi EDT của bạn, đó là chủ đề GUI chỉ dành cho GUI.

Ví dụ:

public static void main(String[] args){ 
    EventQueue.invokeLater(new Runnable(){ 
      public void run(){  
      myframe.setVisible(true); 
     } 
    } 
} 

4. Tạo một sợi Non-UI riêng biệt để xử lý thời gian đó dài dùng phương pháp.

5. Bạn chỉ cần sử dụng Thread hoặc sử dụng SwingWorker được giới thiệu đặc biệt vào Java để đồng bộ hóa giao diện người dùng và chuỗi không phải UI.

6. SwingWorker không đảm bảo rằng phương thức done() được chạy trên EDT, nhưng đồng bộ hóa đầu ra của nó với chuỗi EDT, là luồng GUI.

+2

Đối với quan điểm của bạn 6: xem lớp javadoc của SwingWorker: Sự kiện văn Ðề tài: Tất cả các hoạt động liên quan Swing xảy ra trên chủ đề này. SwingWorker gọi quá trình và thực hiện() phương pháp và thông báo cho bất kỳ PropertyChangeListeners về chủ đề này. – Robin

8
  1. Về cơ bản, mỗi khi bạn sử dụng thành phần Swing hoặc mô hình của thành phần Swing, nó phải được thực hiện trong EDT. Nếu bạn không, không có ngoại lệ sẽ được nâng lên. Nó có thể hoạt động, nhưng nó cũng có thể không hoạt động, có hành vi thất thường, dữ liệu bị hỏng, v.v.
  2. Mọi trình nghe sự kiện Swing đều được gọi trong EDT. Về cơ bản, ngoại trừ phương pháp chính, mỗi dòng mã của một ứng dụng Swing được thực hiện trong EDT theo mặc định, trừ khi bạn bắt đầu một cách rõ ràng một chủ đề, sử dụng một SwingWorker, hoặc một cái gì đó như thế.
  3. có.
  4. Các tác vụ được gửi tới SwingUtilities.invokeLater() được thực hiện theo cùng thứ tự như thứ tự chúng đã được gửi.
  5. Nội bộ, nó sử dụng SwingUtilities.invokeLater() hoặc phương pháp tương tự. FutureTask không liên quan gì đến Swing. Đó là SwingWorker đảm bảo rằng phương thức thực hiện của nó được thực hiện trong EDT. Phương thức doneEDT() có nhận xét sau: Các lời mời được thực hiện trên EDT.
0

SwingWorker đảm bảo rằng phương pháp thực hiện() được chạy trên EDT qua bên dưới mã:

Runnable doDone = 
     new Runnable() { 
      public void run() { 
       done(); 
      } 
     }; 
    if (SwingUtilities.isEventDispatchThread()) { 
     doDone.run(); 
    } else { 
     doSubmit.add(doDone); 
    } 

Trên thực tế nó thêm biến doDone vào AccumulativeRunnable doSubmit,

Xem mã nguồn của AccumulativeRunnable.java bạn sẽ tìm thấy ở đó có một mã dưới đây

khoảng trống bảo vệ nộp() {

SwingUtilities.invokeLater (this);

}

Đó là lý do SwingWorker đảm bảo phương pháp thực hiện() chạy trên EDT