2010-06-10 11 views
10

Czy istnieją biblioteki kodu narzędzi, które sprawdzają, czy metody wywoływane w komponentach Swing są wywoływane w wątku wywołania zdarzenia? Prawdopodobnie napisanie podstawowego kodu nie byłoby zbyt trudne, ale jestem pewny, że są przypadki skrajne i nie dotyczy to innych osób. Szukam tego w czasie wykonywania, nie dla testów jednostkowych.Kod sprawdzania Swing w wątku wysyłki zdarzeń w czasie wykonywania

Odpowiedz

11

Ramy FEST mają narzędzie do wykrywania użycia Swing poza EDT. Jest to w zasadzie program RepaintManager, który instalujesz. Struktura jest ukierunkowana na testowanie, ale program RepaintManager może być używany w czasie wdrażania.

Alternatywnie, aby sprawdzić wszystkie metody, takie jak pobierające i ustawiające dostępu tylko na EDT, można użyć AspectJ i obciążenia w czasie tkania dodać SwingUtilities.isDisaptchThread() rada do każdej metody z elementami skrzydłowych

@Aspect 
public class EDTCheck { 

    @Pointcut("call (* javax.swing..*+.*(..)) || " + 
       "call (javax.swing..*+.new(..))") 
    public void swingMethods() {} 

    @Pointcut("call (* com.mystuff.swing..*+.*(..)) || " + 
       "call (com.mystuff.swing..*+.new(..))") 
    public void mySwingMethods() {} 


    @Pointcut("call (* javax.swing..*+.add*Listener(..)) || " + 
       "call (* javax.swing..*+.remove*Listener(..)) || " + 
       "call (void javax.swing.JComponent+.setText(java.lang.String))") 
    public void safeMethods() {} 

    @Before("(swingMethods() || mySwingMethods()) && !safeMethods()") 
    public void checkCallingThread(JoinPoint.StaticPart thisJoinPointStatic) { 
     if(!SwingUtilities.isDispatchThread()) { 
      System.out.println(
        "Swing single thread rule violation: " 
        + thisJoinPointStatic); 
      Thread.dumpStack(); 
      // or you might throw an unchecked exception 
     } 
    } 

} 

(nieco zmodyfikowany z artykułu (i komponentów Swing JDK.). - dodaje mySwingMethods punktu przekroju i używać SwingUtiliites.isDispatchThread() w praktyce jest th e same jak EventQueue.isDispatchThread(), ale abstrakcji jest czystsze.)

+0

Dzięki. Widziałem FEST, ale widziałem to jedynie w kontekście testów jednostkowych. Chyba mógłbym go użyć na zewnątrz. –

0

Wszystko czego potrzebujesz jest następujący kod:

void method() { 
    if (!SwingUtilities.isEventDispatchThread()) { 
     SwingUtilities.invokeAndWait(new Runnable() { public void run() { method(); }); 
     return; 
    } 

    // do method code here, guaranteed to be in EDT 
} 

Ponadto, korzystając Substance jako swoją LAF pomoże wypracować gdzie rzeczy związanych Swing-nie jest wykonywany na EDT. Ma sprawdzenia, aby upewnić się, że wszystkie rzeczy Swinga zostały wykonane na właściwym wątku lub nie powiedzie się z wyjątkiem.

+0

„kod instrumentu” wskazuje, że chce to zrobić kompilacji, nie starcie. – aioobe

+4

Ergh. Wyjaśnij, czy korzystasz z EDT, czy nie. Kod nie powinien sprawdzać, a następnie wykonywać 'invokeLater'. Z pewnością unikaj 'invokeAndWait', jeśli nie lubisz zakleszczeń. 'assert java.awt.EventQueue.isDispatchThread();' - done. –

+0

@aioobe dunno, mówi "instrument", a następnie mówi, że chce go w czasie wykonywania. Przypuszczam, że szuka adnotacji, które dekorują kod, aby sprawdzić bezpieczeństwo nitki. Ardor3D robi coś podobnego z adnotacją @ main_read. –

2

Z punktu widzenia kodowania wyraźnie oddzielić kod EDT od kodu innego niż EDT. Unikaj SwingWorker jak ognia.

twierdzić, że jesteś na EDT (wstawić ! na starcie), należy dodać linię:

assert java.awt.EventQueue.isDispatchThread(); 

Będziesz potrzebować -ea/-enableassertions za to do niczego. Jednak najczęściej działa jako komentarz wykonywalny.

+3

Jaka jest Twoja alternatywa dla długich zadań zamiast SwingWorker? –

+2

Wysyła zadania do innego wątku [pool], który wysyła zadania z powrotem (bezpośrednio lub pośrednio) przez 'invokeLater'. –

2

natknąłem prosty i mądry (choć nie do końca kuloodporne) metodą Scott Delap w http://today.java.net/pub/a/today/2005/04/19/desktoplive.html .

Jak zasugerował odpowiedź FEST przez MDMA powyżej niestandardowego RepaintManger można stosować, po prostu zastąpić metody

addInvalidComponent(JComponent component) 

i

addDirtyRegion(JComponent component, int x, int y, int w, int h) 

i używać

SwingUtilities.isEventDispatchThread() 

do sprawdź czy jesteśmy na AWT, możesz to całkiem łatwo zintegrować z JUnit, dodając

org.JUnit.Assert.fail("AWT Thread Violation") 

w swojej procedurze sprawdzania.

Logika jest taka, że ​​większość (ale nie wszystkie) operacji Swing powoduje odświeżenie, które ostatecznie wywołuje te metody w aplikacji RepaintManager, dzięki czemu możemy je przechwycić i wykonać nasze sprawdzanie.

Alexander Potochkin ma dobrą rundę się z różnych metod tutaj: http://weblogs.java.net/blog/alexfromsun/archive/2006/02/debugging_swing.html

+0

Jeden krok opisano tylko w połączonym blogu (dostępnym tylko po pobraniu w archive.org: [tutaj jest.] (Https://web.archive.org/web/20070315213731/http://www.clientjava .com/blog/2004/08/20/1093059428000.html) Aby * użyć * Twojego niestandardowego menedżera odświeżania, potrzebujesz tego połączenia statycznego: 'OdświeżManager.setCurrentManager (new MyRepaintManager());' –

Powiązane problemy