2009-04-23 12 views
41

Podobne do mojego poprzedniego pytania: Call repaint from another class in Java?.Jak korzystać z SwingWorker w Javie?

Jestem nowy Java i miałem spojrzeć na kilka tutoriali na SwingWorker, ale jestem pewien, jak wdrożyć je z przykładowym kodem dałem w poprzednim pytaniu.

Czy ktoś może wyjaśnić, jak używać SwingWorker w odniesieniu do mojego małego kawałka kodu lub skierować mnie do przyzwoitego samouczka? Wyglądałem, ale nie jestem jeszcze pewien, czy rozumiem.

Odpowiedz

98

Ogólnie rzecz biorąc, SwingWorker służy do wykonywania długotrwałych zadań w Swing.

Running długo uruchomionych zadań przy wysyłce Event wątek (EDT) może spowodować, że GUI aby zamknąć, więc jedną z rzeczy, które zostały zrobione jest użycie SwingUtilities.invokeLater i invokeAndWait który utrzymuje GUI reagujący przez który priorytetów drugi AWT zdarzenia przed uruchomieniem żądanego zadania (w postaci Runnable).

Jednak problem z SwingUtilities polega na tym, że nie zezwalało to na powracanie danych z wykonanego Runnable do oryginalnej metody. To właśnie zaprojektowano pod adres SwingWorker.

Samouczek języka Java zawiera sekcję o numerze SwingWorker.

Oto przykład zastosowania SwingWorker do wykonania czasochłonnego zadania w osobnym wątku, a następnie wyświetlenie komunikatu z odpowiedzią.

pierwsze klasa rozszerzenie SwingWorker będą:

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(); 
     } 
    } 
} 

typu powrót metod doInBackground i get określono jako pierwszy typ SwingWorker, a drugi rodzaj jest typu stosowanego do powrót dla metod publish i process, które nie są używane w tym przykładzie.

Następnie, w celu wywołania SwingWorker, wywoływana jest metoda . W tym przykładzie będziemy zaczepić się ActionListener do JButton wykonanie europejskiego AnswerWorker:

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

Powyższy przycisk może być dodany do JFrame i kliknąć, aby uzyskać okno komunikatu sekundę później. Podczas pożaru mogą być wykorzystane do zainicjowania GUI dla aplikacji 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); 
} 

Po uruchomieniu aplikacji, będą dwa przyciski. Jeden oznaczony jako "Odpowiedz!" i inne "Nic". Kiedy klikniesz "Odbierz!" przycisk, nic się nie stanie na początku, ale kliknięcie przycisku "Nic" będzie działało i pokazało, że GUI reaguje.

I sekundę później wynik z AnswerWorker pojawi się w oknie komunikatu.

+0

Nie wierzę, że to, co robię, jest długotrwałym zadaniem. Zastanowiłem się nad alternatywnym sposobem radzenia sobie z tym problemem i zapytam w innym pytaniu. Dzięki – Relequestual

+3

+1 bardzo dziękuję! :) – coder9

+0

@ coder9 Nie ma za co :) – coobird

7

Zgadzam:

Running długo uruchomionych zadań przy wysyłce Event wątek (EDT) może spowodować, że GUI aby zamknąć.

Nie zgadzam:

więc jedną z rzeczy, które zostały zrobione jest użycie SwingUtilities.invokeLater i invokeAndWait który utrzymuje GUI czułe ..

invokeLater nadal działa kod na EDT i może zamrozić twój interfejs użytkownika !! Spróbuj tego:

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

Przynajmniej ja, nie można przenieść moje myszy po kliknięciu przycisku wyzwalającego actionPerformed z powyższym kodzie. Czy czegoś brakuje?

+0

Masz rację. Zwykle funkcja invokeLater zostanie wywołana poza wątkiem wysyłki zdarzeń, aby uruchomić coś w wątku wywołania zdarzenia, np. długo działające zadanie może wywoływać funkcję invokeLater w celu zmiany wyświetlania. Dzieje się tak, ponieważ działania na obiektach huśtanych muszą wystąpić z wątku zdarzenia, aby zachować bezpieczeństwo wątków. – dhorn