2011-01-04 15 views
5

Często używam SwingUtilities.invokeLater(). Wykonanie tej czynności utrudnia jednak debugowanie w niektórych przypadkach: nie można wyświetlić śladu stosu kodu o nazwie SwingUtilities.invokeLater(), ponieważ kod ten zakończył już jego wykonywanie.Java: debugowanie za pomocą SwingUtilities.invokeLater()

Czy są jakieś sugestie dotyczące sposobu ustawienia kontekstu (tylko do debugowania) podczas wywoływania SwingUtilities.invokeLater(), aby można było dowiedzieć się, co spowodowało zdarzenie interfejsu użytkownika?

+1

Znaleźliście jakieś akceptowalnych rozwiązań?Naprawdę zainteresowani, aby dowiedzieć się, co w końcu zrobiłeś :) – Twister

Odpowiedz

1

Zastąp metodę, dodaj wywołanie dziennika, a następnie zadzwoń do prawdziwego ... Zastrzeżenie: musisz zastąpić wszystkie swoje połączenia oryginalną metodą.

Można nawet zawinąć działające i dodać numer kontekstu (na przykład znacznik czasu połączenia, aby wywołać później). Gdy Runnable rozpoczyna się zaczęło drukować numer kontekstowe

public static void myInvokeLater(final Runnable runnable) { 
    long ts = System.currentTimeMillis(); 
    Log.info("call to invoke later, context :" + ts); 
    Runnable r = new Runnable() { 
      public void run() { 
       Log.info("start runnable of invokeLater with context :" + ts); 
       runnable.run(); 
      } 
     }; 
    SwingUtilities.invokeLater(r); 
} 
+0

Jeśli System.out.println (działający) i System.out.println (this) w metodzie run z runnable, powinieneś być w stanie je dopasować :) –

+0

nie System.out.println, proszę! –

+0

Niełatwo dezaktywować. tam możesz po prostu dodać, jeśli (DEBUG) to robisz magię, albo po prostu naprzód do prawdziwego InvokeLater. – Twister

1

chciałbym mają tendencję do zastąpienia „Standard” swingUtilites metodę # invokeLater przez bardziej zaawansowanych jeden, być może osadzony w niektórych „localUtilities”, do którego dają zarówno po stronie kod do wykonania z, jako argument, zdarzeniem źródłowym lub jego bezpieczną dla wątku kopią (przypuszczam, że masz zdarzenie źródłowe, niezależnie od jego typu).

1

Jeśli często dzwonisz pod numer invokeLater, możesz rozważyć uproszczenie nawlekania.

invokeLater skutecznie wykorzystuje zmienną statykę i dlatego jest najczystszym złem. Testowanie i więcej będzie łatwiejsze, jeśli przełączysz się z połączenia EventQueue.invokeLater na interfejs z invokeLater i isDispatchThread.

To niefortunne, że ogólnie nie można zastąpić używanych bibliotek przez invokeLater i isDispatchThread.

+0

Czy mógłbyś wyjaśnić swój komentarz na temat "zmiennego statyki"? Nie widzę powodu, dla którego musisz przekazywać zmienne dane przez granicę UI/UI. – Anon

+0

@Anon Implementacja statycznego 'invokeLater' musi wybrać [zmienną] statyczną kolejkę zdarzeń gdzieś wzdłuż linii. –

+0

Więc sugerujesz zastąpienie statycznych wywołań 'SwingUtilities' instancją (wstrzykiwaną)? – Anon

2

Większość innych odpowiedzi tutaj jest dobra, ale chcę dodać kolejną sugestię. Jeśli bardzo często wywołujesz SwingUtilities.invokeLater, prawdopodobnie robisz to niepotrzebnie przez jakiś czas, zwłaszcza jeśli jedynym celem połączenia jest zapewnienie, że zmiany Swing zostaną wprowadzone w wątku zdarzenia. Spróbuj tego, gdy właściwe:

if (SwingUtilities.isEventDispatchThread()) { 
    myRunnable.run(); 
} else { 
    SwingUtilities.invokeLater(myRunnable); 
} 
+0

Więc SwingUtilities nie robi tego w ramach implementacji invokeLater()? –

+0

Nie, ponieważ funkcja invokeLater wykonuje tylko "później", po przetworzeniu wszystkich oczekujących zdarzeń. Oczywiście, jeśli potrzebujesz tego zachowania, nie możesz użyć tej sztuczki. invokeAndWait może również działać jako alternatywa. – DJClayworth

1

Czy przechodząc anonimowych Runnable s do invokeLater()?

Jeśli tak, sugerowałbym zastąpienie ich nieanonimowymi klasami, które dodadzą kilka linii kodu, ale da ci przynajmniej pewien poziom identyfikowalności (np .: TableUpdateFromQuery). Działa to najlepiej, jeśli wywołujesz określony typ aktualizacji tylko z jednego miejsca w aplikacji. Prowadzi cię to również drogą "działań w tle", które można przetestować poza interfejsem użytkownika.

2

Możesz spróbować zastąpić EventQueue i wydrukować stos dla opublikowanych wydarzeń. Również w poniższym przykładzie unikalny numer zostanie przypisany do każdego wysłanego wydarzenia. Kiedy invokeLater byłyby należne od innych invokeLaterpostEvent 9 from 7 wtedy tekst będzie drukowany w dzienniku

  // Place this code somewhere in the main class to override queue 
     EventQueue eventQueue = Toolkit.getDefaultToolkit().getSystemEventQueue(); 
     eventQueue.push(new MyEventQueue()); 

Gdzie klasa MyEventQueue może wyglądać następująco:

import java.awt.AWTEvent; 
import java.awt.EventQueue; 
import java.awt.event.InvocationEvent; 
import java.util.WeakHashMap; 

public class MyEventQueue extends EventQueue { 

    int currentNumber = 0; 
    WeakHashMap<AWTEvent,Integer> eventIdMap = new WeakHashMap<AWTEvent,Integer>(); 
    AWTEvent currentEvent = null; 

    protected void dispatchEvent(AWTEvent event) { 
     if (event instanceof InvocationEvent) { 
      currentEvent = event; 
     } 
     super.dispatchEvent(event); 
     currentEvent = null; 
    } 

    public void postEvent(AWTEvent event) { 
     if (event instanceof InvocationEvent) { 
      currentNumber = currentNumber + 1; 
      eventIdMap.put(event, currentNumber); 
      System.out.println("postEvent " + currentNumber + " " + 
        (currentEvent != null ? "from " + eventIdMap.get(currentEvent) : "")); 
      for(StackTraceElement element : new RuntimeException().getStackTrace()) { 
       System.out.println("\t" + element); 
      } 
     } 
     super.postEvent(event); 
    } 
} 
+0

Jako wyjaśnienie, jeden 'rozszerza EventQueue' i zastępuje żądaną metodę, np. 'invokeLater()'. Oto pokrewny przykład: http://stackoverflow.com/questions/3158409 – trashgod

Powiązane problemy