5

読み込みに時間がかかるプログラムがあります。このため、何がロードされているかについてユーザーにフィードバックを提供できるスプラッシュ スクリーンを開発したいと考えました。画像、ラベル、JProgressBar を持つシンプルな JFrame。

私は実験してきましたが、これまでに得た最良の結果は、次のように実行していますmain()

SwingUtilities.invokeAndWait(new Runnable() {

    public void run() {

        new SplashScreen();
    }
});

SwingUtilities.invokeAndWait(new Runnable() {

    public void run() {

        //Code to start system
        new MainFrame();
        //.. etc
    }
});

SplashScreen と MainFrame はどちらも JFrame を拡張するクラスです。また、Substance をライブラリとして使用しています。

SplashScreen のコンストラクターは、JLabel と JProgressBar をそれ自体に追加し、パックして可視に設定します。JProgressBar は次のとおりですsetIndeterminate(true)

プログラムを実行すると、SplashScreen が表示されますが、ProgressBar はロックされており、プログラムの残りの部分が開始されるまで動かず、期待どおりに動き始めません。

ここで何が欠けていますか?私が行ったすべての検索では、この問題について言及されていないようであり、ほとんどの「カスタム スプラッシュ スクリーン」の実装は、私と非常によく似た方法で対処しています。

4

4 に答える 4

3

invokeAndWait は、指定された操作が完了するまで Swing スレッドをフリーズします。そのため、メインフレームが作成されるまで、プログレス バーは 100% 表示されます。

SwingUtilities.invoke(Later|AndWait) を使用してスプラッシュ スクリーンを更新する非スイング スレッドを生成する必要があります。

new Thread(new Runnable() { public void run() {
  // Create MainFrame here
  SwingUtilities.invokeLater(new Runnable() {
      public void run() {
         updateProgressHere();
      }
  });

  // Do other initialization
  SwingUtilities.invokeLater(new Runnable() {
      public void run() {
         updateProgressHere();
      }
  });
}).start(); 
于 2010-03-01T18:38:26.070 に答える
3

アランの正解よりももう少し一般的になろうとするだけです。

システムには、(合法的に) GUI を更新できるスレッドが 1 つあります。

そのスレッドを使用してシステムを初期化すると、guis は更新されません。

メイン スレッドから GUI を更新しようとすると、何もうまくいきません。

GUI がどのスレッド上にあるかを常に認識し、そのスレッドで作業を行わないようにしてください。

GUI の更新は、次のように考えてください。

  • 非 GUI スレッドは、表示している値を更新します (たとえば、完了した割合)。
  • これは、invokeLater を介して更新をポストし、その後、他の作業を続行します。
  • GUI スレッドは、非 GUI スレッドから渡されたデータで GUI を更新する invokeLater を実行します。
  • GUIスレッドが終了します!これにより、システムの他の無関係な部分が、必要に応じて GUI を更新できるようになります。

非 GUI スレッドは、ほとんどの場合、Thread.start からのスレッドであり、「main」に渡されたスレッドです。

GUI スレッドは、「invokeLater」と、GUI イベント (押されたボタン、GUI タイマー、任意の Swing リスナー) から渡されたすべてのものを実行するスレッドです。

このため、ほとんどの場合、GUI を更新するときはすでに GUI スレッドを使用しています。ただし、起動シーケンスと、スレッドが表示を更新する場所に注意してください。

于 2010-03-01T19:40:24.560 に答える
1

他の回答はこれのほとんどをカバーしていますが、簡単に言えば、問題はSwingイベントディスパッチスレッドで「システムを開始するコード」を実行していることです。すべての GUI 関連のコード (コンポーネントの作成を含む)は EDT で実行する必要がありますが、他のすべてのコードは EDT で実行しないでください。これを行うようにプログラムを変更してみてください。

SwingUtilities.invokeAndWait(new Runnable() {
    public void run() {
        new SplashScreen();
    }
});
// Code to start system (nothing that touches the GUI)
SwingUtilities.invokeAndWait(new Runnable() {
    public void run() {
        new MainFrame();
    }
});
//.. etc
于 2010-03-02T16:39:20.927 に答える
1

他の人は、プログレスバーがブロックされている理由について言及しています.Java6にはスプラッシュスクリーン処理がjavawおよびjavaランチャーに組み込まれている代替ソリューションを提案します...

スプラッシュ スクリーンは、JVM とアプリケーションのクラスがロードされる前でも表示されます。アプリケーションが開始されると、内部のロード状態を反映するようにスプラッシュ スクリーンを更新し、準備ができたら閉じることができます。

あるいは、Windows のみのソリューションの場合、Winrun4J Java ランチャーにもスプラッシュ スクリーン機能があります。

于 2010-03-01T19:27:25.177 に答える