5

I use SwingUtilities.invokeLater() frequently. Doing so, however, makes it difficult to debug in certain cases: you can't see a stack trace of the code that called SwingUtilities.invokeLater(), because that code has already ended its execution.

Are there any suggestions for how to set some sort of context (for debugging purposes only) when calling SwingUtilities.invokeLater(), so that you can figure out what caused the UI event in question?

4

6 に答える 6

2

ここでの他の答えのほとんどは良いですが、私は別の提案を追加したいと思います。SwingUtilities.invokeLaterを頻繁に呼び出す場合、特に呼び出しの唯一の目的がイベントスレッドでSwingの変更が行われるようにすることである場合は、おそらく不必要に呼び出すことがあります。必要に応じてこれを試してください。

if (SwingUtilities.isEventDispatchThread()) {
  myRunnable.run();
} else {
  SwingUtilities.invokeLater(myRunnable);
}
于 2011-01-04T16:41:59.713 に答える
2

EventQueue投稿されたイベントのスタックトレースをオーバーライドして出力することができます。また、以下の例では、投稿された各イベントに一意の番号が割り当てられます。invokeLater他から呼び出されるとinvokeLater、テキストpostEvent 9 from 7がログに出力されます

        // このコードをメイン クラスのどこかに配置して、キューをオーバーライドします
        EventQueue eventQueue = Toolkit.getDefaultToolkit().getSystemEventQueue();
        eventQueue.push(新しい MyEventQueue());

クラス MyEventQueue は次のようになります。

import java.awt.AWTEvent;
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 イベント) {
        if (InvocationEventのイベントインスタンス) {
            currentEvent = イベント;
        }
        super.dispatchEvent(イベント);
        currentEvent = null;
    }

    public void postEvent(AWTEvent イベント) {
        if (InvocationEventのイベントインスタンス) {
            現在の番号 = 現在の番号 + 1;
            eventIdMap.put(イベント、現在の番号);
            System.out.println("postEvent " + currentNumber + " " +
                    (currentEvent != null ? "from " + eventIdMap.get(currentEvent) : "") );
            for(StackTraceElement要素: new RuntimeException().getStackTrace()) {
                System.out.println("\t" + 要素);
            }
        }
        super.postEvent(イベント);
    }
}
于 2011-01-04T20:48:55.943 に答える
1

invokeLater頻繁に呼び出す場合は、スレッド化を簡素化することを検討してください。

invokeLater変更可能な静的を効果的に使用しているため、最も純粋な悪です。呼び出しから とEventQueue.invokeLaterを使用したインターフェイスの使用に切り替えると、テストなどがより簡単にinvokeLaterなりますisDispatchThread

残念ながら、一般に、ライブラリで使用されるinvokeLaterとを置き換えることはできません。isDispatchThread

于 2011-01-04T16:19:55.103 に答える
1

メソッドをオーバーライドし、ログ呼び出しを追加してから、実際の呼び出しを呼び出します... 警告: すべての呼び出しを元のメソッドに置き換える必要があります。

ランナブルをラップしてコンテキスト番号を追加することもできます (たとえば、後で呼び出す呼び出しのタイムスタンプ)。ランナブルが開始すると、コンテキスト番号の出力が開始されました

 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);
}
于 2011-01-04T15:33:06.650 に答える
1

Runnableに匿名の s を渡していinvokeLater()ますか?

はいの場合、それらを非匿名クラスに置き換えることをお勧めします。これにより、コードが数行追加されますが、少なくともある程度のトレーサビリティが得られます (例: TableUpdateFromQuery)。これは、アプリ内の 1 か所だけから特定の種類の更新を呼び出す場合に最適です。また、UI の外部でテストできる「バックグラウンド アクティビティ」への道筋も示します。

于 2011-01-04T16:53:10.397 に答える
1

「標準」の swingUtilites#invokeLater メソッドをより高度なメソッドに置き換える傾向があります。おそらく、いくつかの「localUtilities」に埋め込まれており、実行するコードの両方を引数として、ソース イベントまたはスレッドセーフなコピーの両方で指定します。それの(タイプが何であれ、ソースイベントがあると思います)。

于 2011-01-04T15:36:49.597 に答える