2010-02-18 14 views
5

Zastanawiam się, czy SwingWorker musi być klasą zagnieżdżoną w moim głównym interfejsie GUI. Wolałbym uczynić z niej zewnętrzną klasę, aby zachować GUI z dala od logiki mojego programu.Czy SwingWorker musi być klasą zagnieżdżoną?

Próbowałem uczynić klasę SwingWorker zewnętrzną, co działa dobrze dla procesu, niestety nie mam dostępu do żadnego z moich pól GUI z klasy SwingWorker. Kiedykolwiek próbuję uzyskać dostęp do atrybutu, takiego jak etykieta lub cokolwiek innego z metody SwingWorker's done(), otrzymuję wyjątek nullPointer.

Każda rada byłaby mile widziana!


Przede wszystkim dziękuję bardzo Jeff! Działa do tej pory dobrze, mimo że nie mogłem pójść za tobą przy drugiej opcji, którą zaprezentowałeś. Jedno z moich zadań w tle oblicza określony rozmiar (długa wartość), więc byłoby miło uzyskać tę wartość z mojego GUI.

Zasugerowałeś, że będziesz pracować z programami pobierającymi i ustawiającymi, ale niestety nie mam pojęcia, jak je wdrożyć w klasie SwingWorker.

Próbowałem to tak:

public void setSize(long totalSize) { 
    this.totalSize = totalSize; 
} 
public long getTotalSize() { 
    return totalSize; 
} 

Setter jest wywoływana na końcu metody doInBackground(). Niestety nie mogę użyć metody get() z mojego GUI.

final MySwingWorker w = new MySwingWorker(); 
Runnable r = new Runnable() { 
    public void run() { 
     // do something with w.get() 
    } 
}; 
w.setRunnable(r); 
w.execute(); 

Tworzenie obiektu "w" nie działa w moim przypadku, ponieważ konstruktor wymaga obiektu Runnable. Czy czegoś brakuje? Proszę, nie przejmuj się, po raz pierwszy pracuję z SwingWorker. :) Jeszcze raz, dziękuję bardzo za pomoc!

Odpowiedz

6

Możesz uczynić SwingWorker klasą zewnętrzną. Jednakże, tak jak każda inna klasa, jeśli nie może zobaczyć zmiennych (np. Etykiety, którą chcesz ustawić), oczywiście nie będzie w stanie jej ustawić. Jedną rzeczą, którą możesz zrobić, to przekazać pracownikowi Runnable, który wykona, gdy jest kompletny.

public class MySwingWorker extends SwingWorker { 

    private final Runnable r; 
    public MySwingWorker(Runnable r) { 
     this.r = r; 
    } 
    public void doInBackground() {...} 
    public void done() { r.run(); } 
} 

teraz z GUI, można zrobić coś takiego

Runnable updateLabel = new Runnable() { 
     public void run() { 
      label.setText("myValue"); 
     } 
}; 
SwingWorker w = new MySwingWorker(updateLabel); 
w.execute(); 

To staje się trochę trudniejsze, jeśli chcesz używać wynik SwingWorker, choć jest to możliwe. Zamiast mijając Runnable do konstruktora pracownika huśtawka jest, to masz metody setter i to byłoby coś takiego:

final MySwingWorker w = new MySwingWorker(); 
Runnable r = new Runnable() { 
    public void run() { 
     // do something with w.get() 
    } 
}; 
w.setRunnable(r); 
w.execute(); 

W każdym przypadku, Runnable działa podobnie do zamknięcia, który jest wykonywany, gdy pracownik skończone.

+0

Możliwe byłoby również po prostu przekazanie etykiety do konstruktora, a nie do działania. Zdefiniowanie nowej podklasy pracowniczej dla każdej małej akcji prawdopodobnie byłoby jednak przesadą. Anonimowe klasy są świetne do rozwiązania tego konkretnego problemu złożenia bardzo małego, ściśle powiązanego obiektu. –

+0

To naprawdę zależy, czy jest to przypadek jednorazowy. Abstrakcja działa, jeśli robisz to w wielu miejscach. Och, jak będą pomocne zamknięcia. –

Powiązane problemy