2009-04-23 33 views
41

Liên quan đến câu hỏi trước của tôi: Call repaint from another class in Java?.Làm cách nào để sử dụng SwingWorker trong Java?

Tôi mới sử dụng Java và tôi đã xem một số hướng dẫn về SwingWorker, nhưng tôi không chắc chắn cách triển khai nó bằng mã ví dụ mà tôi đã đưa ra trong câu hỏi trước.

Bất cứ ai có thể giải thích làm thế nào để sử dụng SwingWorker liên quan đến chút ít mã của tôi và hoặc chỉ cho tôi hướng tới một hướng dẫn phong nha xin vui lòng? Tôi đã nhìn nhưng tôi không chắc mình đã hiểu chưa.

Trả lời

98

Nói chung, SwingWorker được sử dụng để thực hiện các tác vụ chạy trong Swing.

Chạy các tác vụ dài trên Chủ đề sự kiện (EDT) có thể khiến GUI bị khóa, vì vậy một trong những điều đã được thực hiện là sử dụng SwingUtilities.invokeLaterinvokeAndWait để giữ GUI đáp ứng ưu tiên AWT khác sự kiện trước khi chạy tác vụ mong muốn (dưới dạng Runnable).

Tuy nhiên, sự cố với SwingUtilities là nó không cho phép trả lại dữ liệu từ phương thức thực thi Runnable đã thực thi. Đây là những gì SwingWorker được thiết kế để giải quyết.

Hướng dẫn Java có một phần trên SwingWorker.

Dưới đây là ví dụ trong đó SwingWorker được sử dụng để thực hiện tác vụ tốn thời gian trên một chuỗi riêng biệt và hiển thị hộp thông báo sau một giây với câu trả lời.

Trước hết, một lớp mở rộng SwingWorker sẽ được thực hiện:

class AnswerWorker extends SwingWorker<Integer, Integer> 
{ 
    protected Integer doInBackground() throws Exception 
    { 
     // Do a time-consuming task. 
     Thread.sleep(1000); 
     return 42; 
    } 

    protected void done() 
    { 
     try 
     { 
      JOptionPane.showMessageDialog(f, get()); 
     } 
     catch (Exception e) 
     { 
      e.printStackTrace(); 
     } 
    } 
} 

Kiểu trả về của doInBackgroundget phương pháp được quy định như các loại đầu tiên của SwingWorker, và loại thứ hai là loại dùng để trả về cho các phương thức publishprocess, không được sử dụng trong ví dụ này.

Sau đó, để gọi SwingWorker, phương thức execute được gọi. Trong ví dụ này, chúng tôi sẽ treo một ActionListener đến một JButton để thực hiện AnswerWorker:

JButton b = new JButton("Answer!"); 
b.addActionListener(new ActionListener() { 
    public void actionPerformed(ActionEvent e) 
    { 
     new AnswerWorker().execute(); 
    } 
}); 

Nút trên có thể được thêm vào một JFrame, và nhấp vào để có được một hộp thông báo một giây sau đó. Sau đây có thể được sử dụng để khởi tạo GUI cho ứng dụng Swing:

private void makeGUI() 
{ 
    final JFrame f = new JFrame(); 
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    f.getContentPane().setLayout(new FlowLayout()); 

    // include: "class AnswerWorker" code here. 
    // include: "JButton" b code here. 

    f.getContentPane().add(b); 
    f.getContentPane().add(new JButton("Nothing")); 
    f.pack(); 
    f.setVisible(true); 
} 

Khi ứng dụng được chạy, sẽ có hai nút. Một nhãn có nhãn "Trả lời!" và một "Không có gì". Khi một cú nhấp chuột vào "Trả lời!" nút, không có gì sẽ xảy ra lúc đầu, nhưng nhấp vào nút "Không có gì" sẽ làm việc và chứng minh rằng GUI là đáp ứng.

Và, một giây sau, kết quả của AnswerWorker sẽ xuất hiện trong hộp thư.

+0

Tôi không tin những gì tôi đang làm là một nhiệm vụ chạy dài. Tôi đã nghĩ ra một cách khác để giải quyết vấn đề này, và sẽ hỏi trong một câu hỏi khác. Cảm ơn – Relequestual

+3

+1 cảm ơn rất nhiều! :) – coder9

+0

@ coder9 Bạn được chào đón :) – coobird

7

Đồng ý:

Chạy nhiệm vụ dài chạy trên Dispatch Event Thread (EDT) có thể gây GUI để khóa lên.

Không đồng ý:

vì vậy một trong những điều mà đã được thực hiện là sử dụng SwingUtilities.invokeLater và invokeAndWait mà giữ GUI đáp ứng ..

invokeLater vẫn chạy mã trên EDT và có thể đóng băng giao diện người dùng của bạn !! Hãy thử điều này:

SwingUtilities.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        Thread.sleep(100000); 
       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 
      } 
     }); 

Ít nhất là tôi, không thể di chuyển chuột khi tôi nhấp vào nút kích hoạt hành độngĐược tạo bằng mã ở trên. Tui bỏ lỡ điều gì vậy?

+0

Bạn nói đúng. Nói chung invokeLater sẽ được gọi bên ngoài chuỗi gửi sự kiện để chạy một thứ gì đó trên chuỗi gửi sự kiện, ví dụ: một tác vụ chạy dài có thể gọi invokeLater để thay đổi hiển thị. Điều này là do các hành động trên các đối tượng swing phải xảy ra từ chuỗi sự kiện để duy trì an toàn luồng. – dhorn

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