2010-08-23 102 views
40

Tại sao cần đặt mã cập nhật GUI ở SwingUtilities.invokeLater()?SwingUtilities.invokeLater() tại sao cần thiết?

Tại sao bản thân nó không thể được Swing tự chăm sóc? Tại sao người gọi phải quan tâm đến cách swing xử lý cập nhật giao diện người dùng?

+1

Thực ra phương pháp đó là chính xác cho nhà phát triển ** chứ không phải lo lắng về việc đồng bộ hóa chuỗi, vì bạn chỉ cần cho Swing biết đó là khoảng thời gian cập nhật và công việc nặng được thực hiện sau cảnh. – OscarRyz

Trả lời

35

Đối tượng xoay are not thread safe. SwingUtilities.invokeLater() cho phép thực hiện một nhiệm vụ tại một số thời điểm sau này, như tên cho thấy; nhưng quan trọng hơn, nhiệm vụ sẽ được thực hiện trên chuỗi gửi sự kiện AWT. Khi sử dụng invokeLater, tác vụ được thực hiện không đồng bộ; cũng có invokeAndWait, sẽ không trở lại cho đến khi tác vụ đã hoàn thành việc thực thi.

Một số thông tin về quyết định không làm Swing thread-safe có thể được tìm thấy ở đây: Multithreaded toolkits: A failed dream?

+2

Tại sao nó không thể được chăm sóc nội bộ bởi Swing chính nó? Tại sao người gọi phải quan tâm đến cách swing xử lý cập nhật giao diện người dùng? –

+4

@pure: Bởi vì rất khó để có được quyền mà không cần phun khóa tất cả các nơi (AWT đã làm điều này, và bị nó). Yêu cầu rằng tất cả các cập nhật hiển thị được thực hiện trong luồng công văn - khá dễ dàng ở cấp ứng dụng - làm cho hầu hết các kho lưu trữ biến mất. –

14

Do cập nhật GUI phải được thực hiện trong chuỗi gửi sự kiện. Nếu bạn đang hoạt động trong một chủ đề khác, thực hiện cập nhật trong invokeLater sẽ đưa nó ra khỏi chuỗi của bạn và vào chuỗi sự kiện.

Nhiều lời giải thích ở đây: http://www.oracle.com/technetwork/java/painting-140037.html

Điều thông minh để làm với bản cập nhật lớn (như repopulating một JTable từ cơ sở dữ liệu) trên Swing là để có được các mô hình cơ bản, làm các bản cập nhật trên mô hình trong chủ đề của bạn, sau đó kích hoạt thông báo bằng cách sử dụng invokeLater. Điều đó giúp gui của bạn phản hồi các sự kiện và vẽ lại. Nếu bản cập nhật sẽ rất rộng, bạn thậm chí có thể kích hoạt các thông báo này với invokeLater trong khoảng thời gian đều đặn trong khi bạn đang cập nhật, như sau mỗi hai giây.

+1

có vẻ như liên kết của bạn bị hỏng –

+1

@pavelrappo - Oracle đã xóa bài viết tôi liên kết tới. Tôi tìm thấy một cái khác, nhưng cũng bao gồm một chút giải thích. –

2

SwingUtilities.invokeLater()

Nguyên nhân doRun.run() được thực hiện đồng bộ trên thread sự kiện AWT cử. Điều này sẽ xảy ra sau khi tất cả các sự kiện AWT đang chờ xử lý đã được xử lý. Phương thức này nên được sử dụng khi một luồng ứng dụng cần cập nhật GUI.
...

7

Swing là đơn luồng. Mọi cập nhật đối với giao diện người dùng phải xảy ra từ cái gọi là EDT - chuỗi sự kiện-dispather là chủ đề GUI chính Swing (và tôi nghĩ AWT) sử dụng. Nếu bạn không làm điều này, sau đó những điều kỳ lạ có thể hoặc sẽ xảy ra (mặc dù tôi thích Windows FOrms tốt hơn ở đây mà chỉ ném một ngoại lệ nếu bạn làm điều đó sai).

Điều đó đang được nói, bạn không cần phải quấn mọi hoạt động giao diện người dùng đơn lẻ vào SwingUtilities.invokeLater() - nếu mã bạn đang viết đã được thực hiện bởi EDT, điều này là không cần thiết. Vì vậy, ActionListener cho một nhấp chuột vào nút không cần điều này. Nhưng một người nghe trên một đối tượng bên ngoài, chạy trong một số chủ đề khác, cập nhật một số JLabel ở đâu đó - ở đó bạn cần nó.

5

Swing không được viết thành bộ công cụ GUI an toàn cho luồng nên tất cả các bản cập nhật GUI sẽ xảy ra từ một chuỗi đơn lẻ để tránh bất kỳ khóa chết nào. Trong Swing, đây là Event Dispatcher Thread (EDT).

Xem Concurrent in Swing từ hướng dẫn Java để biết thêm chi tiết. Nó cũng tham khảo mục nhập blog this về lý do tại sao khó viết một bộ công cụ GUI đa luồng.

3

Tất cả các bức tranh của các thành phần phải được thực hiện trong một chủ đề duy nhất, do đó, chúng được hiển thị đúng cách. Bằng cách đó, thành phần sẽ biết, phần nào đã được sơn và phần nào không có.

Nếu bạn gọi phương pháp liên quan "sơn" (sơn, cập nhật, paintComponent, hiển thị, setVisible, gói, vv) bên ngoài EDT, bạn sẽ cố gắng vẽ theo hai chủ đề khác nhau và có thể gây ra sự cố.

Khi bạn cần sử dụng một chuỗi khác để cập nhật giao diện người dùng, bạn nên gọi nó bằng cơ sở invokeLater, lần lượt sẽ đặt nó trong EDT cho bạn, vì vậy bạn vẫn vẽ trong cùng một chuỗi.

Bạn không cần sử dụng nó, nếu bạn đang mã hóa phương thức chạy trong EDT (ví dụ: actionPerformed hoặc paint hoặc một trong số đó) Hoặc nếu bạn đang thực thi mã không liên quan đến giao diện người dùng (đối với Ví dụ, các file xử lý ở chế độ nền, vv)

để hiểu rõ hơn tất cả những khái niệm đọc: The single thread rule

1

người khác lặp lại: Swing không phải là thread an toàn để một thread phải làm tất cả các bản cập nhật để tránh các vấn đề đồng thời. invokeLater là một phương thức tiện ích để thực thi một cái gì đó bên trong luồng xử lý sự kiện.

Tại sao Swing không thực hiện nội bộ: đây là ấn tượng của tôi ... Tôi nghĩ vì nó sẽ quá mức cần thiết để kiểm tra mọi nơi cập nhật đang diễn ra. Nó sẽ sưng lên mã Swing, dificult xem xét và bảo trì của mã.

Mặt khác, không phải là ứng dụng để biết nếu nó không thực thi bên trong luồng GUI và gọi invokeLater. Nó sẽ được khi ứng dụng của riêng đưa ra một số chủ đề trước.

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