6

OK、ウェブ全体で検索を読みましたが、問題の解決策をまだ見つけていません。おそらく単純なものが欠けているため、ここにいます...

修理事業の作業指示を処理するかなり大規模なプロジェクトがあります。それはすべてデータベースに接続されており、多くのページのコードとクラスです。しかし、基本的にノート領域で新しいメッセージをチェックする短いコードをフロント エンドに追加しただけです。

とにかく、2 つのJLabelを持つ単純なJFrameを表示し、別のスレッドがデータベースにクエリを実行します。これはすべて、プログラムの開始時に発生します。問題は、私の小さな「お待ちください」JFrameがフレームを表示しますが、待機中 (データベーススレッドではなく、プログラムの残りのロードです)、ガッツもバックグラウンドもJLabelも表示されないことです。しかし、それまでにはその要点がありません。

以下のサンプルプログラムを書きました。単純なJFrame (CheckingMessagesGUI: 2 つのJLabelを持つJFrame、それ以上のものは何もない) を表示し、5 秒間スリープしてから、サンプル (メイン プログラム) JFrameを表示し、この例では即座に閉じます ( )。もっとたくさん。私が見つけたのは、それが問題を引き起こしているようだということです。スリープタイマーが切れるとウィンドウが表示されますが、それを表示するコードはコマンドの前に与えられており、その順序で実行する必要がありましたか?System.exit(0)invokeLaterThread.sleep

私の質問は、なぜJFrameinvokeLaterが正しく表示されないのですか?

その目的はinvokeLater、項目が正しい AWT イベント スレッドで実行されるようにすることであると理解しています。これにより、このウィンドウが正しく描画されると思います。とにかく、明らかな何かが欠けていると確信しています。以下のコードの一部をコメントアウトしましたinvokeLaterが、正しく実行されますが、元に戻すと...

よろしくお願いします。

package javaapplication6;

public class Example extends javax.swing.JFrame {          
    public Example() {
        System.out.println("Example started");
        setBounds(100,100,200,200);

        System.out.println("cmGUI instantiated");
        CheckingMessagesGUI cmGUI = new CheckingMessagesGUI();
        System.out.println("Set cmGUI visible");
        cmGUI.setVisible(true);
        cmGUI.validate();
        try {
            System.out.println("timer started");
            Thread.sleep(5000);
            System.out.println("timer done");
        } catch(InterruptedException e){
        }
        System.exit(0);
    }

    public static void main(String[] args) {
        /*java.awt.EventQueue.invokeLater(new Runnable() {
        @Override
        public void run() { */
        System.out.println("Started");
        System.out.println("example Instantiated");
        Example example = new Example();
        System.out.println("example visible");
        example.setVisible(true);
        /*      }
        });
        */
    }
}

更新: 明確にするために、Thread.sleep()すべてをブロックすることを認識していますが、スリープを呼び出す前に CheckingMessagesGUI が既に完全に描画されているべきではありませんか? それが問題です。

4

5 に答える 5

4

invokeLater は、GUI の更新にも使用される Event Dispatch Thread で Runnable を実行します。
スリープがこのスレッドをブロックしているため、GUI もサービスを受けられず、invokeLater コードから戻るまで更新を行うことができませ
そのため、このスレッドで長い (時間のかかる) 計算を行うべきではありません。それらは別の (新しい) スレッドで実行する必要があります。

イベント ディスパッチ キューの状態

イベント ディスパッチ スレッドのタスクはすぐに終了する必要があります。そうしないと、未処理のイベントがバックアップされ、ユーザー インターフェイスが応答しなくなります。

コードを次のように変更できます (テストされていません)。

public Example(){
    System.out.println("Example started");
    setBounds(100,100,200,200);

    System.out.println("cmGUI instantiated");
    CheckingMessagesGUI cmGUI = new CheckingMessagesGUI();
    System.out.println("Set cmGUI visible");
    cmGUI.setVisible(true);
    cmGUI.validate();

    Thread thread = new Thread(new Runnable() {
        try {
            System.out.println("timer started");
            Thread.sleep(5000);
            System.out.println("timer done");
        } catch(InterruptedException e) {
        }
        System.exit(0);
    });
    thread.start();
}

編集: もう少し「深く」行きましょう (これが Swing/AWT の動作に対する私の見解です)。
「お待ちください」(コメントを参照) が CheckingMessagesGUI クラスに表示されるはずですが、そうではありません。
これは、GUI の動作に関連しています。対応する (Swing) メソッド (draw、setText、setLocation など) を呼び出すと、ディスプレイ上の何も直接変更されません。イベントをイベント キューに入れるだけです。イベント ディスパッチ スレッドは、このキューを読み取ってイベントを処理する唯一のスレッドです (そうあるべきです)。ブロックされている限り (この場合はスリープによって)、GUI への変更は表示されません。GUI がフリーズします。

EDIT2:
invokeLaterRunnable がキューの末尾に追加され、保留中のすべてのイベントが処理された後に EDT によって実行されます。invokeLater 呼び出しの後の次のコマンドが実行されます。
invokeAndWait上記と同じですが、実際のスレッドは、Runnable が EDT によって (保留中のイベントの後) 実行されるまでブロックされます。つまり、invokeAndWait に続くコマンドは、送信された Runnable が実行された後にのみ開始されます。

于 2009-12-04T00:03:30.913 に答える
1

これは、Swingチュートリアルで必要なものを見つけるのに問題がある私のような初心者のための一般的な解決策です。

public void method(){
    final PleaseWaitWindow window = new PleaseWaitWindow();

    Thread thread = new Thread(new Runnable() {
        @Override
        public void run() {
            //stuff that you want to do that is preventing window to display

            window.dispose();
        }
    }
    thread.start();
}
于 2010-01-26T11:42:06.333 に答える
1

InvokeLater の目的は、アイテムが正しい AWT イベント スレッドで実行されるようにすることであるという私の理解

それは正しいです。

ただし、これは Thread.sleep() が EDT で実行されていることも意味します。これは、EDT にスリープするように指示したため、GUI 自体を再描画できないことを意味します。長時間実行されるタスクには別のスレッドを使用する必要があります。

EDT の詳細については、同時実行に関するSwing チュートリアルのセクションを参照してください。

しかし、私のポイントは、スリープを呼び出す前に、「お待ちください」(CheckingMessagesGUI) がすでに完全に描画されている必要があるということでした。これは真実であるべきではありませんか?

これが私のプロセスの単純化された理解です。OSネイティブのコンポーネントなのでフレームが作成されて表示されます。ただし、contentPane と子コンポーネントは軽量コンポーネントです。つまり、Swing Repaint Manager がいつ再描画する必要があるかをスケジュールします。そのため、再描画がスケジュールされる前に EDT がスリープ状態になり、スリープが完了するまで再描画を実行できません。

Repaint Manager の詳細については、 Paintng in AWT and Swingに関する記事を参照してください。

于 2009-12-04T00:00:07.673 に答える
0

目に見えないコンポーネントは塗装されません。

于 2009-12-15T12:58:54.693 に答える
0

私の答えは、GUI が構築されたときにその時点で自動的に描画されず、代わりに描画の呼び出しが EDT キューに配置されるというものでした。同じメソッドで GUI オブジェクトを作成し、setVisible(true) を作成し、次の数行で集中的な処理を行うと、それ以降のペイント呼び出しがブロックされます。これは、そのメソッドまで EDT キューに配置されないためです (集中的なもので)終了します。また、前述のように、フレームまたはボーダーは方程式のプラットフォーム側にあり (したがって描画されます)、残り (Jlabel、コンテナー、背景など) は Java 側にあり、ペイントが実際に実行されるまで発生しません (つまり、EDT キューがそれに到達します)。私のサンプル コードは、InvokeLater 呼び出しなしで動作しました。これは、init スレッドで集中的な処理を実行し、EDT スレッドがまだペイントできるようにしたためです。

于 2009-12-04T03:41:11.660 に答える