3

(Swing GUI を使用した私のアプリケーションでは) JButton をクリックした後に呼び出されるループまたはメソッドで実行される作業中に GlassPane を表示したいと考えています。

例: (ボタンをクリックした後に実行されるアクション)

if (item.equals(button)) {

    glassPane.setVisible(true);

    someTimeConsumingMethod();

    glassPane.setVisible(false);

}

このコードを実行すると、someTimeConsumingMethod() の実行中に glassPane が表示されなくなります。結果が表示される前に、GUI が一瞬フリーズします。そのループ (glassPane.setVisible(false);) の最後の行を削除すると、メソッドが完了した後 (GUI がフリーズしたとき)、glassPane が表示されます。

GUI がフリーズする前にその glassPane を表示する簡単な方法はありますか、それともここで高度な知識を使用する必要がありますか? (スレッド?)

更新1:

davidXYZの回答に従ってコードを更新しました(2つの変更があります):

(ボタンクリック後の動作)

if (item.equals(button)) {

    glassPane.setVisible(true);

        new Thread(new Runnable(){
            public void run(){
                someTimeConsumingMethod(); // 1st change: running the someTimeConsumingMethod in new Thread
                                           //             instead of setting glassPane to visible
            }
        }).start();

    // 2nd change: moved glassPane.setVisible(false); inside the someTimeConsumingMethod(); (placed at the end of it).

}

最初の変更のポイントは、GUI スレッドで someTimeConsumingMethod を実行する直前に新しいスレッドで glassPane を表示するように設定すると、someTimeConsumingMethod が終了した後に glassPane が明らかになることです (これを再確認しました)。

今では問題なく動作します。すべての回答に感謝します。スレッドを実際に理解するために、あなたが提供したすべてのリンクを必ず確認します!

UPDATE2: いくつかの詳細情報: someTimeConsumingMethod(); 私のアプリケーションでは、XML データに応じて新しい Swing コンポーネントを準備しています (カードは JButton と JLabel から構築され、必要に応じていくつかの JPanel を使用し、それらを正しい場所に追加します)。

UPDATE3: SwingWorker の invokeLater メソッドを使用して機能させようとしています。これで次のようになります。

(ボタンクリック後の動作)

if (item.equals(button)) {

    glassPane.setVisible(true);

    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() { 
            someTimeConsumingMethod();
            glassPane.setVisible(false);
        }
    });

}

UPDATE1のコードほどうまく機能しません(ただし、それでも機能します)。問題は次のとおりです。

  • glassPane は .gif アニメーションなしで読み込まれます (ファイルはカスタム glassPane クラスで設定されます - UPDATE1コードで動作します)

  • 「作業」プロセスの最後にわずかな遅延があります。最初のカーソルが (WAIT_CURSOR から) 通常に変わり、非常に短い時間後に glassPane が消えます。カーソルは、アクティブ化/非アクティブ化時にカスタム glassPane クラスによって変更されます (新しいスレッドの方法を使用して遅延はありません)。

SwingWorker の invokeLater メソッドを使用する正しい方法ですか?

編集:私の間違いです。SwingWorker と SwingUtilities.invokeLater() を混同しました。イメージの問題は、someTimeCONsumingMethod の開始時に GUI がフリーズしたことが原因だと思います。

4

4 に答える 4

5

結果が表示される前に、GUI が一瞬フリーズします。そのループ (glassPane.setVisible(false);) の最後の行を削除すると、メソッドが完了した後 (GUI がフリーズしたとき)、glassPane が表示されます。

これは に関する一般的な問題ですEvent Dispath Thread。 のすべてのイベントが に一瞬でEDTフラッシュされると、メソッド内のすべてが一度に実行される可能性があります。Swing GUIif (item.equals(button)) {

しかし、あなたの説明は、Swing の同時実行性に問題があること、EDT をブロックするコードの一部、これは小さな遅延Thread.sleep(intです。

GUI がフリーズする前にその glassPane を表示する簡単な方法はありますか、それともここで高度な知識を使用する必要がありますか? (スレッド?)

この質問は、なぜSwingWorkerそこにあるのか、または簡単な方法は予約の例ですRunnable#Thread

  • SwingWorker出力がEDTで行われることを完全に保証するように実装されたメソッド

  • Runnable#ThreadSwing GUI への出力はすべてラップする必要があります。invokeLater()

からの最も簡単な手順Jbuttons Action

  • 見せるGlassPane

  • からバックグラウンド タスクを開始するSwingWorker( でリッスンしていることを確認してくださいPropertyChangeListener) または呼び出すRunnable#Thread

  • この時点でActionListener実行が完了し、残りのコードはバックグラウンドタスクにリダイレクトされます

  • タスクが終了した場合、非表示にするGlassPane

  • forにラップsetVisibleして単純な void を作成するinvokeLater()Runnable#Thread

  • 使用する場合は、適切なイベントSwingWorkerを非表示にするか、非表示にするために任意の (別の) void を使用できます。GlassPanePropertyChangeListenerGlassPane

@camickr による GlassPaneの最適なコード、またはこのコードに基づく私の質問

于 2012-09-26T17:30:21.503 に答える
3

時間のかかるジョブで EDT (イベント ディスパッチ スレッド、すべての UI イベントが処理される単一のスレッド) をブロックしています。

2 つの解決策:

  1. への呼び出しをラップします:someTimeConsumingMethod();glassPane.setVisible(false);SwingUtilities.invokeLater()、これにより、フレームがもう一度自分自身を再描画できるようになります。ただし、これでも GUI がフリーズします。

  2. に移動someTimeConsumingMethod()しますSwingWorker(これは推奨されるオプションです)。これにより、GUI がフリーズするのを防ぐことができます。

SwingWorker の javadoc を読んで、何が起こっているのか、どのように使用するのかをよりよく理解してください。このチュートリアルでは、Swing とマルチスレッドについても多くのことを学ぶことができます

于 2012-09-26T17:29:43.610 に答える
2
 JButton startB = new JButton("Start the big operation!");
    startB.addActionListener(new ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent A) {
        // manually control the 1.2/1.3 bug work-around
        glass.setNeedToRedispatch(false);
        glass.setVisible(true);
        startTimer();
      }
    });

ここで使用されるガラス板は FixedGlassPane ガラスです。

参照: http://www.java2s.com/Code/Java/Swing-JFC/Showhowaglasspanecanbeusedtoblockmouseandkeyevents.htm

于 2012-09-26T16:45:47.763 に答える
0

ギヨームは正しいです。メインスレッドを使用している場合、各行は次の行の前に終了します。間違いなく別のスレッドが必要です。

問題を解決する簡単な方法は、別のスレッドでガラスペインの表示をスピンオフすることです(通常のスレッドまたはスイングスレッド-どちらも正常に機能します)。

if (item.equals(button)) {
    new Thread(new Runnable(){
        public void run(){
            glassPane.setVisible(true);
        }
    }).start();
    someTimeConsumingMethod();
    glassPane.setVisible(false);
}

そうすれば、メインスレッドで実行されてsetvisible(true)いる間、別のスレッドがブロックされます。someTimeConsumingMethod()完了すると、ガラス板が消えます。匿名スレッドはメソッドの最後に到達してrun停止します。

于 2012-09-26T18:13:22.367 に答える