2011-08-25 33 views
51

Câu hỏi của tôi có liên quan đến SwingUtilities.invokeLater. Khi nào tôi nên sử dụng? Tôi có phải sử dụng mỗi khi tôi cần cập nhật các thành phần GUI không? Nó chính xác làm gì? Có một thay thế cho nó vì nó không âm thanh trực quan và thêm mã dường như không cần thiết?SwingUtilities.invokeLater

+2

Nó tương đương với 'Control.BeginInvoke'. – SLaks

+0

@SLaks Điều đó có nghĩa là nếu tôi có một chủ đề, tôi không phải sử dụng nó? – FadelMS

+4

@FadelMS, Vì khung công tác Swing tạo ra một chuỗi của riêng nó (EDT), bạn sẽ luôn có chuỗi đó. (* Bạn * không có một "thông báo kiểm tra" -loop mà xử lý người dùng nhấp chuột vv, phải không? Vậy làm thế nào để các phương pháp 'actionPerformed' khác nhau được gọi là? Bởi EDT!) Vì vậy, khi bạn nói rằng bạn có * một * thread, tôi sẽ phải intepret rằng như bạn * chỉ * có EDT (tức là, bạn đã ném một GUI và rơi ra khỏi cạnh của phương pháp chính). Trong trường hợp đó, NO, bạn * sẽ không * cần sử dụng 'invokeLater'. Tuy nhiên, bạn sẽ không thể thực hiện bất kỳ quá trình xử lý nền nào. Nếu bạn làm như vậy, bạn sẽ khóa hoàn toàn GUI ... – aioobe

Trả lời

52

Tôi có phải sử dụng mỗi lần tôi cần cập nhật các thành phần GUI không?

Không, không phải nếu bạn đã trên thread sự kiện văn (EDT) mà luôn luôn là trường hợp khi trả lời người dùng khởi tạo các sự kiện như nhấp chuột và lựa chọn. (Các phương pháp actionPerformed vv, luôn gọi bằng EDT.)

Nếu bạn không trên tuy nhiên EDT và muốn làm cập nhật giao diện (nếu bạn muốn cập nhật giao diện từ một số timer chủ đề, hoặc từ một số chuỗi mạng v.v.), bạn sẽ phải lịch bản cập nhật sẽ được thực hiện bởi EDT. Đó là những gì phương pháp này là dành cho.

Swing về cơ bản là chuỗi không an toàn. Tức là, tất cả sự tương tác với API đó cần được thực hiện trên một chuỗi đơn (EDT). Nếu bạn cần cập nhật GUI từ một luồng khác (chuỗi hẹn giờ, chuỗi nối mạng, ...), bạn cần sử dụng các phương thức như là bạn đã đề cập (SwingUtilities.invokeLater, SwingUtilities.invokeAndWait, ...).

+0

@ Jens: Điều đó có nghĩa là tôi có thể làm mà không có nó nếu tôi ở trên cùng một luồng (Swing) hoặc làm những việc trong thời gian chạy. – FadelMS

+1

Vâng, "hoặc làm những việc trong thời gian chạy" không phải là rất chính xác. Nếu bạn làm mọi thứ trong thời gian chạy, trong, ví dụ, một chuỗi thời gian, sau đó không, bạn không thể làm mà không có các loại phương pháp này. – aioobe

+0

Cảm ơn aioobe, hiểu rồi. – FadelMS

7

Mỗi ứng dụng Swing có ít nhất 2 chủ đề:

  1. Các chủ đề chính mà thực hiện việc áp dụng
  2. Các EDT (tổ chức sự kiện dispatching thread) là một chủ đề mà cập nhật giao diện người dùng (do đó giao diện người dùng sẽ không đóng băng).

Nếu bạn muốn cập nhật giao diện người dùng, bạn nên thực thi mã trong EDT. Các phương thức như SwingUtilities.invokeLater, SwingUtilities.invokeAndWait, EventQueue.invokeLater, EventQueue.invokeAndWait cho phép bạn thực thi mã bằng EDT.

+0

đơn giản và dễ hiểu, cảm ơn bạn – Yahya

3

Hầu hết các sự kiện do người dùng khởi tạo (lần nhấp, bàn phím) sẽ có trên EDT nên bạn sẽ không phải sử dụng SwingUtilities cho điều đó. Điều đó bao gồm rất nhiều trường hợp, ngoại trừ chủ đề chính và chuỗi công việc của bạn cập nhật EDT.

+0

không nhất, _all_ – kleopatra

+0

Vâng, người dùng có thể cập nhật tệp đang được theo dõi bởi một luồng cập nhật GUI. –

+1

hmm ...không được tính là sự kiện bắt đầu do người dùng khởi tạo: người dùng cập nhật tệp (bên trong swing, trên EDT) và lưu nó (bằng cách nhấp vào nút, trên EDT), kích hoạt hệ điều hành tập tin cập nhật sự kiện (bên ngoài swing, off EDT) thông báo, thông báo đó đạt đến màn hình (tắt EDT) có trách nhiệm cập nhật GUI trên EDT – kleopatra

7

Câu hỏi của tôi lần này có liên quan đến SwingUtilities.invokeLater: Khi nào tôi nên sử dụng?

Điều quan trọng cần hiểu là Java có một chuỗi riêng biệt (EDT) xử lý các sự kiện liên quan đến Swing.

Bạn nên sử dụng invokeLater() để hiển thị chính JFrame của ứng dụng dành cho máy tính để bàn (ví dụ), thay vì cố gắng thực hiện trong luồng hiện tại. Nó cũng sẽ tạo ra bối cảnh cho việc đóng ứng dụng duyên dáng sau này.

Đó là về nó cho hầu hết các ứng dụng.

Tôi có phải sử dụng mỗi khi tôi cần cập nhật các thành phần GUI không? Nó chính xác làm gì?

No.Nếu bạn sửa đổi một thành phần GUI, nó sẽ kích hoạt một sự kiện được đăng ký để gửi đi sau đó bởi Swing. Nếu có một người nghe cho sự kiện này, chủ đề EDT sẽ gọi nó ở đâu đó trên đường. Bạn không cần sử dụng invokeLater(), chỉ cần đặt người nghe của bạn trên các thành phần chính xác.

Hãy nhớ rằng chủ đề này là cùng một chuỗi khung vẽ vv ... trên màn hình của bạn. Do đó, người nghe không nên thực hiện các tác vụ phức tạp/dài/CPU, nếu không màn hình của bạn sẽ bị đóng băng.

Có cách nào khác vì nó không nghe trực quan và thêm mã dường như không cần thiết?

Bạn không cần phải viết nhiều mã hơn hiển thị ứng dụng của mình với invokeLater() + trình nghe bạn quan tâm đến thành phần. Phần còn lại được xử lý bởi Swing.

12
Swing is single threaded and all changes to the GUI must be done on EDT 

sử dụng cơ bản cho invokeLater()

  1. phương pháp chính nên luôn luôn được bọc trong invokeLater()

  2. chậm (nhưng không đồng bộ) hành động/sự kiện vào cuối EventQueue,

  3. Nếu EDT không tồn tại thì bạn phải tạo một EDT mới bằng cách sử dụng invokeLater(). Bạn có thể thử nghiệm nó với if (SwingUtilities.isEventDispatchThread()) {...

  4. Có tồn tại invokeAndWait(), nhưng cho đến hôm nay tôi (chỉ quan điểm của tôi) không thể tìm thấy một lý do cho việc sử dụng invokeAndWait() thay vì invokeLater(), ngoại trừ những thay đổi khó khăn vào GUI (JTree & JTable), nhưng chỉ với Substance L&F (tuyệt vời để thử nghiệm tính nhất quán của các sự kiện trên EDT)

  5. Basic thứ: Concurrency in Swing

  6. Tất cả các đầu ra từ các nhiệm vụ nền phải được bọc trong invokeLater()

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