2011-01-04 17 views
5

Uso spesso SwingUtilities.invokeLater(). In questo modo, tuttavia, è difficile eseguire il debug in alcuni casi: non è possibile visualizzare una traccia stack del codice che ha chiamato SwingUtilities.invokeLater(), poiché tale codice ha già terminato la sua esecuzione.Java: debugging con SwingUtilities.invokeLater()

Ci sono dei suggerimenti su come impostare una sorta di contesto (solo a scopo di debug) quando si chiama SwingUtilities.invokeLater(), in modo da poter capire cosa ha causato l'evento UI in questione?

+1

Avete trovato soluzioni accettabili?Davvero interessato a sapere cosa hai fatto alla fine :) – Twister

risposta

1

Ignorare il metodo, aggiungere una chiamata di registro e quindi chiamare quella reale ... Avvertenza: è necessario sostituire tutte le chiamate al metodo originale.

È anche possibile eseguire il wrap del runnable e aggiungere un numero di contesto (ad esempio il timestamp della chiamata da richiamare in seguito). Quando inizia eseguibili ha cominciato a stampare il numero di contesto

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

Se System.out.println (eseguibile) e System.out.println (questo) nel metodo run del runnable, dovresti essere in grado di abbinarli :) –

+0

no System.out.println per favore! –

+0

E non facilmente disattivabile. lì puoi semplicemente aggiungere if (DEBUG) quindi eseguire la magia, altrimenti semplicemente inoltrare il vero InvokeLater. – Twister

1

tenderei a sostituire il metodo # invokeLater swingUtilites "standard" da uno più avanzato, forse incorporato in alcuni "localUtilities", a cui si dà sia la codice da eseguire con, come argomento, l'evento di origine o una copia thread-safe di esso (suppongo tu abbia un evento di origine, qualunque sia il suo tipo).

1

Se si chiama invokeLater frequentemente, si consiglia di prendere in considerazione la semplificazione della filettatura.

invokeLater utilizza in modo efficace la statica mutevole ed è quindi il male più puro. I test e altro diventeranno più semplici se si passa dalla chiamata EventQueue.invokeLater all'utilizzo di un'interfaccia con invokeLater e isDispatchThread.

E 'un peccato che non si può, in generale, sostituire il invokeLater e isDispatchThread utilizzato dalle biblioteche.

+0

Puoi spiegare il tuo commento su "statica mutabile"? Non vedo alcun motivo per cui è necessario passare dati mutabili attraverso il limite dell'interfaccia utente/non-UI. – Anon

+0

@Anon L'implementazione di 'invokeLater' statico deve selezionare una coda di eventi statici [mutabili] da qualche parte lungo la linea. –

+0

Quindi stai suggerendo di sostituire le chiamate statiche a 'SwingUtilities' con un'istanza (iniettabile)? – Anon

2

La maggior parte delle altre risposte qui sono buone, ma voglio aggiungere un altro suggerimento. Se chiami SwingUtilities.invokeLater molto frequentemente, probabilmente lo stai facendo inutilmente un po 'di tempo, specialmente se l'unico scopo della chiamata è quello di garantire che le modifiche di Swing siano fatte sul thread dell'evento. Prova questo se del caso:

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

Quindi SwingUtilities non lo fa già come parte della sua implementazione invokeLater()? –

+0

No, perché invokeLater esegue solo "dopo", dopo che tutti gli eventi in sospeso sono stati elaborati. Ovviamente se hai bisogno di questo comportamento non puoi usare questo trucco. invokeAndWait può anche funzionare come alternativa. – DJClayworth

1

Si sta passando anonimi Runnable s per invokeLater()?

Se sì, suggerirei di sostituirli con classi non anonime, che aggiungeranno un paio di righe di codice, ma forniranno almeno un certo livello di tracciabilità (ad esempio: TableUpdateFromQuery). Funziona meglio se invochi un particolare tipo di aggiornamento da un solo punto nell'app. Inoltre, ti conduce lungo il percorso delle "attività in background", che possono essere testate al di fuori dell'interfaccia utente.

2

È possibile provare a ignorare EventQueue e stampare stacktrace per gli eventi pubblicati. Anche nell'esempio qui sotto un numero univoco verrebbe assegnato a ogni evento pubblicato. Quando invokeLater sarebbe stato chiamato da altri invokeLater allora il testo postEvent 9 from 7 sarebbe stampato nel registro

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

Dove classe MyEventQueue potrebbe essere simile a questo:

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

Come chiarimento, uno 'estende EventQueue' e sovrascrive il metodo desiderato, ad es. 'InvokeLater()'. Ecco un esempio correlato, http://stackoverflow.com/questions/3158409 – trashgod