Để giúp chúng tôi trong việc đảm bảo rằng tất cả các sự kiện mà xử lý mã được thực hiện chỉ từ trong các chủ đề sự kiện-lập, Swing cung cấp một lớp học rất hữu ích đó, trong số những thứ khác, cho phép chúng tôi để thêm các đối tượng Runnable vào hàng đợi sự kiện hệ thống. Lớp này được gọi là SwingUtilities và nó có hai phương pháp mà chúng tôi đang quan tâm đến ở đây: invokeLater() và invokeAndWait(). Phương pháp đầu tiên thêm một Runnable vào hàng đợi sự kiện hệ thống và trở lại ngay lập tức. Phương pháp thứ hai cho biết thêm một Runnable và chờ đợi cho nó để được gửi đi, sau đó trở về sau khi nó kết thúc. Cú pháp cơ bản của mỗi sau: Runnable trivialRunnable = mới Runnable() {} khu vực void Run {} doWork(); làm một số công việc } }; SwingUtilities.invokeLater(trivialRunnable); thử {} Runnable trivialRunnable2 = mới Runnable() {} khu vực void Run {} doWork(); làm một số công việc } }; SwingUtilities.invokeAndWait(trivialRunnable2); } bắt (InterruptedException ví dụ) {} System.out.println ("... chờ đợi thread gián đoạn!"); } bắt (InvocationTargetException ite) {} System.out.println) ".. .uncaught ngoại lệ trong vòng Runnable của run()"); }Bởi vì những Runnables được đặt vào hàng đợi sự kiện hệ thống để thực hiện trong các sự kiện-lập chủ đề, chúng ta cần phải chỉ là cẩn thận rằng họ thực hiện một cách nhanh chóng, như bất kỳ sự kiện khác mà xử lý mã. Trong hai ví dụ trên, nếu các phương pháp doWork() đã làm một cái gì đó mà phải mất một thời gian dài (như tải một tập tin lớn) chúng tôi sẽ tìm thấy rằng các ứng dụng sẽ đóng băng cho đến khi tải hoàn tất. Trong thời gian chuyên sâu các trường hợp như thế này, chúng tôi nên sử dụng thread riêng biệt của riêng của chúng tôi để duy trì phản ứng.Mã sau đây cho thấy một cách điển hình để xây dựng riêng của chúng tôi chủ đề để làm một số công việc thời gian chuyên sâu. Để an toàn Cập nhật trạng thái của bất kỳ thành phần từ bên trong chủ đề này, chúng ta phải sử dụng invokeLater() hoặc invokeAndWait(): Chủ đề workHard = mới Thread() {} khu vực void Run {} doToughWork(); làm một số công việc thực sự thời gian chuyên sâu SwingUtilities.invokeLater (mới Runnable () {} khu vực void Run {} updateComponents(); Cập nhật trạng thái của sự } }); } }; workHard.start();Lưu ý: invokeLater() nên thay vì invokeAndWait() bất cứ khi nào có thể. Nếu chúng tôi có thể sử dụng invokeAndWait(), chúng tôi sẽ đảm bảo rằng không có không có ổ khóa (i.e.synchronized khối) được tổ chức bởi các chủ đề gọi chủ đề khác có thể cần trong thời gian hoạt động.Điều này giải quyết vấn đề của phản ứng, và nó gọi khẩn cấp liên quan đến thành phần mã chủ đề sự kiện-lập, nhưng nó vẫn không thể được coi là hoàn toàn thân thiện. Thông thường, người dùng có thể làm gián đoạn một thủ tục thời gian chuyên sâu. Nếu chúng tôi đang chờ đợi để thiết lập kết nối mạng, chúng tôi chắc chắn không muốn tiếp tục chờ vô thời hạn nếu đích không còn tồn tại. Trong hầu hết trường hợp người sử dụng nên có thể chọn để làm gián đoạn chủ đề của chúng tôi. Mã giả mã sau đây minh hoạ một cách điển hình để thực hiện việc này, nơi stopButton gây ra các chủ đề để bị gián đoạn, Cập Nhật thành phần nhà nước cho phù hợp: Chủ đề workHarder = mới Thread() {} khu vực void Run {} doTougherWork(); SwingUtilities.invokeLater (mới Runnable () {} khu vực void Run {} updateMyComponents(); Cập nhật trạng thái của sự } }); } }; workHarder.start(); khu vực vô hiệu doTougherWork() {} thử {} [một số loại vòng lặp] ... nếu, tại bất kỳ điểm nào, điều này liên quan đến việc thay đổi thành phần nhà nước chúng tôi sẽ cần phải sử dụng invokeLater ở đây bởi vì đây là một chủ đề riêng biệt. // Chúng ta phải thực hiện ít nhất một trong các thao tác sau: // 1. Định kỳ kiểm tra Thread.interrupted() // 2. Định kỳ ngủ hoặc chờ đợi Nếu (Thread.interrupted()) {} ném InterruptedException() mới; } Thread.Wait(1000); } bắt (InterruptedException e) {} Hãy để ai đó biết chúng tôi đã bị ngắt .. .nếu điều này liên quan đến việc thay đổi trạng thái thành phần chúng tôi sẽ cần phải sử dụng invokeLater ở đây. } } JButton stopButton = mới JButton("Stop"); ActionListener stopListener = mới ActionListener() {} khu vực vô hiệu actionPerformed (ActionEvent sự kiện) {} làm gián đoạn các chủ đề và cho phép người dùng biết các chủ đề đã bị gián đoạn bởi vô hiệu hoá các nút dừng. .. đây sẽ xảy ra trên các chủ đề công văn thường xuyên sự kiện workHarder.interrupt(); stopButton.setEnabled(false); } }; stopButton.addActionListener(stopListener);Chúng tôi stopButton ngắt các chủ đề workHarder khi ép. Có hai cách đó doTougherWork() sẽ biết cho dù workHarder, các chủ đề mà nó được thực hiện trong, đã bị ngắt. Nếu nó hiện đang ngủ hoặc chờ đợi, một InterruptedException sẽ được ném mà chúng tôi có thể nắm bắt và xử lý cho phù hợp. Chỉ khác cách để phát hiện sự gián đoạn là định kỳ kiểm tra nhà nước bị gián đoạn bằng cách gọi Thread.interrupted().Cách tiếp cận này thường được sử dụng để xây dựng và hiển thị hộp thoại phức tạp, I/O xử lý mà kết quả trong thành phần nhà nước thay đổi (chẳng hạn như tải một tài liệu vào một thành phần văn bản), lớp chuyên sâu tải hoặc tính toán, chờ đợi cho thư hoặc thiết lập một kết nối mạng, vv. Tham khảo: Các thành viên của đội Swing đã viết một vài bài viết về việc sử dụng các chủ đề với Swing, và đã cung cấp một lớp gọi là SwingWorker mà làm cho việc quản lý loại đa luồng mô tả ở đây thuận tiện hơn. Xem http://java.sun.com/products/jfc/tsc/archive/tech_topics_arch/threads/threads.html2.3.1 trường hợp đặc biệtCó là một số trường hợp đặc biệt mà chúng tôi không cần phải phân bổ mã ảnh hưởng đến trạng thái của các thành phần chủ đề sự kiện-lập: 1. một số phương pháp trong Swing, mặc dù ít và xa giữa, được đánh dấu là chủ đề, an toàn và không cần xem xét đặc biệt. Một số phương pháp chủ đề an toàn nhưng không được đánh dấu như vậy: repaint(), revalidate(), và invalidate().2. một thành phần có thể được xây dựng và chế tác ở bất kỳ thời trang mà chúng tôi thích, mà không liên quan cho các chủ đề, miễn là nó đã không được được thực hiện (tức là của nó đã được hiển thị hoặc một yêu cầu repaint đã được xếp hàng đợi). Đồ đựng bằng cấp cao nhất (JFrame, JDialog, JApplet) được thực hiện sau khi bất kỳ của setVisible(true), show(), hoặc pack() đã được gọi là trên chúng. Cũng lưu ý rằng một thành phần được coi là nhận ra ngay sau khi nó được đưa vào một thùng chứa nhận ra.3. khi giao dịch với Swing applet (JApplets) tất cả các thành phần có thể được xây dựng và chế tác bất kể chủ đề cho đến khi các phương pháp start() đã được gọi là, mà xảy ra sau khi các phương pháp init.2.3.2 làm thế nào để chúng tôi xây dựng phương pháp an toàn chủ đề riêng của chúng tôi?Điều này là khá dễ dàng. Dưới đây là một phương pháp an toàn chủ đề mẫu chúng tôi có thể sử dụng để đảm bảo mã phương pháp này chỉ thực hiện trong sự kiện-lập chủ đề: khu vực vô hiệu doThreadSafeWork() {} Nếu (SwingUtilities.isEventDispatchThread()) {} // Tất cả làm việc ở đây... // } khác {} Runnable callDoThreadSafeWork = mới Runnable() {} khu vực void Run {} doThreadSafeWork(); } }; SwingUtilities.invokeLater(callDoThreadSafeWork); } } 2.3.3 làm thế nào để invokeLater() và invokeAndWait() làm việc? lớp javax.swing.SystemEventQueueUtilities [gói riêng]Khi SwingUtilities nhận được một đối tượng Runnable thông qua invokeLater(), nó đã vượt qua nó ngay lập tức với phương pháp postRunnable() của một lớp gọi là SystemEventQueueUtilities. Nếu một Runnable nhận được thông qua invokeAndWait(), lần đầu tiên các chủ đề hiện tại được kiểm tra để đảm bảo rằng nó không phải là chủ đề sự kiện-lập. (Nó sẽ gây tử vong cho phép invokeAndWait() được kích hoạt từ các chủ đề sự kiện công văn chính nó!) Lỗi được ném nếu đây là trường hợp. Nếu không, chúng tôi xây dựng một đối tượng để sử dụng như ổ khóa trên một phần quan trọng (tức là một khối được đồng bộ hóa). Khối này chứa hai báo cáo. Người đầu tiên gửi Runnable phương pháp postRunnable() SystemEventQueueUtilities', cùng với một tham chiếu đến đối tượng khóa. Chờ đợi thứ hai trên đối tượng khóa để các chủ đề cuộc gọi sẽ không tiến hành cho đến khi đối tượng này thông báo - do đó "gọi và chờ đợi."Phương pháp postRunnable() đầu tiên liên lạc với SystemEventQueue riêng, một lớp bên trong của SystemEventQueueUtilities, để trở về một tham chiếu đến hàng đợi sự kiện hệ thống. Sau đó chúng tôi quấn Runnable trong một thể hiện của RunnableEvent, một lớp học riêng bên trong. Các nhà xây dựng RunnableEvent mất một Runnable và một đối tượng đại diện cho đối tượng khóa (null nếu invokeLater() được gọi là) dưới dạng tham số.Các lớp học RunnableEvent là một phân lớp của AWTEvent, và xác định riêng của mình ID sự kiện tĩnh int - EVENT_ID. (Lưu ý rằng bất cứ khi nào chúng tôi xác định sự kiện riêng của chúng tôi chúng tôi sẽ sử dụng một ID sự kiện lớn hơn giá trị của AWTEvent.RESERVED_ID_MAX.) RunnableEvent của EVENT_ID là AWTEvent.RESERVED_ID_MAX + 1000. RunnableEvent cũng có một trường hợp tĩnh của một RunnableTarget, thêm một lớp riêng bên trong. RunnableTarget là một phân lớp của thành phần và mục đích duy nhất của nó là để hoạt động như nguồn và mục tiêu của RunnableEvents.RunnableTarget làm điều này như thế nào? Nhà xây dựng của nó cho phép sự kiện với tổ chức sự kiện ID kết hợp của RunnableEvent ID: enableEvents(RunnableEvent.EVENT_ID);Nó cũng sẽ ghi đè của thành phần bảo vệ processEvent() phương pháp để nhận được RunnableEvents. Bên trong phương pháp này lần đầu tiên nó kiểm tra để xem nếu sự kiện này thông qua dưới dạng tham số trong thực tế là một thể hiện của RunnableEvent. Nếu nó là, nó được thông qua để SystemEventQueueUtilities' processRunnableEvent() phương pháp (điều này xảy ra sau khi RunnableEvent đã được gửi đến từ hàng đợi sự kiện hệ thống.)Bây giờ trở lại RunnableEvent. Các nhà xây dựng RunnableEvent gọi nhà xây dựng lớp cha (AWTEvent) đi qua trường hợp tĩnh của RunnableTarget như là sự kiện nguồn, và EVENT_ID như là sự kiện của bạn.
đang được dịch, vui lòng đợi..
