2

私は現在、Java のマルチスレッドについて学習していて、興味深い問題に遭遇しました。CSVファイルを読み取る「ローダー」クラスがあります。

public class LoaderThread implements Runnable{

@Override
public void run(){
//do some fancy stuff
}
}

さらに、データの読み込み中に表示したい SplashScreen があります。

import javax.swing.JLabel;
import javax.swing.JWindow;
import javax.swing.SwingConstants;

public class SplashScreen extends JWindow{

JWindow jwin = new JWindow();

public SplashScreen(){

jwin.getContentPane().add(new JLabel("Loading...please wait!",SwingConstants.CENTER));
jwin.setBounds(200, 200, 200, 100);

jwin.setLocationRelativeTo(null);

jwin.setVisible(true);

try {
  Thread.sleep(3000);
} catch (InterruptedException e) {
  Thread.currentThread().interrupt(); 
 }

jwin.setVisible(false);
jwin.dispose();

}
}

ユーザーがボタンをクリックすると、メイン クラスからコードが実行されます。

private void jButton1ActionPerformed(java.awt.event.ActionEvent evt)   {                                         


    final Thread t = new Thread() {

           @Override
           public void run() {  

              LoaderThread myRunnable = new LoaderThread();
              Thread myThread = new Thread(myRunnable);
              myThread.setDaemon(true); 
              myThread.start();
              while(myThread.isAlive()==true)
              {
                  SplashScreen ss = new SplashScreen();
              }


           }
        };
        t.start();  // call back run()
        Thread.currentThread().interrupt();         

}                  

この設定は機能していますが、読み込みに 3 秒以上かかるとメッセージが「点滅」し、読み込みプロセスが短くても 3 秒以上表示されます。

ロードスレッドが実行されている限り、メッセージを表示できるかどうか疑問に思っています。長くも短くもない。

前もって感謝します!

4

3 に答える 3

5

ループ内で新しいインスタンスを作成しているため、点滅しています。1つのインスタンスを作成して表示し、もう1つのスレッドの実行が終了したら、それを破棄します。

于 2012-11-21T21:15:30.470 に答える
5

これは、オブザーバー パターンがうまく機能する完璧な例です。Swing でこれを簡単に行う 1 つの方法は、バックグラウンド スレッドに SwingWorker を使用することです。SwingWorker の実行時にスプラッシュ画面を表示します。SwingWorker を実行する前に PropertyChangeListener を追加し、SwingWorker.StateValue.DONE で返されたときにスプラッシュ画面を取り除きます。

また、Thread.sleep(...)あなたがやっているようにSwingイベントスレッドを呼び出さないでください。これは災害の保証です.

編集 1
コメントについて --

「Swing イベントスレッドで Thread.sleep も呼び出さないでください...」とはどういう意味ですか? 「Swing イベントスレッドで Thread.sleep も呼び出さないでください...」とはどういう意味ですか?

これはSwingイベントスレッド( EDTまたはイベント ディスパッチスレッドとも呼ばれます) で呼び出されます。

try {
  Thread.sleep(3000);
} catch (InterruptedException e) {
  Thread.currentThread().interrupt(); 
}

Thread.sleep(...)これにより、アプリケーション全体がスリープ状態になり、完全に応答しなくなるため、EDTを呼び出さないことをお勧めします。


2例のコードを編集します。

import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import javax.swing.*;

public class SwingWorkerEg extends JPanel {
   private static final int PREF_W = 300;
   private static final int PREF_H = 200;

   public SwingWorkerEg() {
      add(new JButton(new ButtonAction("Press Me")));
   }

   @Override
   public Dimension getPreferredSize() {
      return new Dimension(PREF_W, PREF_H);
   }

   private static void createAndShowGui() {
      JFrame frame = new JFrame("SwingWorkerEg");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(new SwingWorkerEg());
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

class ButtonAction extends AbstractAction {
   public ButtonAction(String title) {
      super(title);
   }

   @Override
   public void actionPerformed(ActionEvent actEvt) {
      final JButton source = (JButton)actEvt.getSource();
      source.setEnabled(false);
      MySwingWorker mySw = new MySwingWorker();
      final MySplashScreen mySplash = new MySplashScreen();
      mySplash.setVisible(true);

      mySw.addPropertyChangeListener(new PropertyChangeListener() {

         @Override
         public void propertyChange(PropertyChangeEvent pcEvt) {
            if (SwingWorker.StateValue.DONE == pcEvt.getNewValue()) {
               mySplash.setVisible(false);
               mySplash.dispose();
               source.setEnabled(true);
            }
         }
      });
      mySw.execute();
   }
}

class MySwingWorker extends SwingWorker<Void, Void> {
   private static final long SLEEP_TIME = 5 * 1000;

   @Override
   protected Void doInBackground() throws Exception {
      Thread.sleep(SLEEP_TIME); // emulate long-running task
      return null;
   }
}

class MySplashScreen extends JWindow {
   private static final String LABEL_TEXT = "Loading, ... please wait...";
   private static final int PREF_W = 500;
   private static final int PREF_H = 300;

   public MySplashScreen() {
      add(new JLabel(LABEL_TEXT, SwingConstants.CENTER));
      pack();
      setLocationRelativeTo(null);
   }

   @Override
   public Dimension getPreferredSize() {
      return new Dimension(PREF_W, PREF_H);
   }
}
于 2012-11-21T21:24:18.720 に答える
1

モニターを使用できますhttp://en.wikipedia.org/wiki/Monitor_(synchronization

これにより、タスクが完了したときにスレッドが終了し、任意のスリープを待たないようにすることができます。

基本的にあなたはこれをしたいです(拡張する必要があります):

public class Monitor {
  private boolean task = false;

  public void synchronized waitForTask(){
     while(!task){
        wait();
     }
  }

  public void synchronized taskIsDone(){
     task = true;
     notifyAll();
  } 
}

両方のオブジェクトは、このモニターへの参照を必要とします。ビューはwaitForTaskを呼び出す必要があり、タスクはtaskIsDoneを呼び出します。

于 2012-11-21T21:27:01.237 に答える