6

Javaでアプリケーションを作ろうとしています。Swingを正しく機能させるために、私はこれを行いました。

public static void main(String[] array){ 

String outerInput;
SwingUtilities.invokeLater(new Runnable(){
    @Override
    public void run() {
        // I want this string input.
        String input = JOptionPane.showInputDialog(
            null,"Stop ?", JOptionPane.QUESTION_MESSAGE);  
});
// How can I get this input value in String outerInput?
}

この入力文字列を本体で取得するにはどうすればよいですか?

4

7 に答える 7

6

AtomicReference<String>スレッドセーフな方法でスレッド間で値を渡すために使用できます。

Hemalが指摘したように、スレッドがすでに実行されていることを確認するには、2つのスレッド間で同期をとる必要があります。たとえば、CountDownLatchを使用したり、SwingUtilities.invokeAndWaitを使用したりできます(Swingスレッドから呼び出さないように注意してください)。

更新:これは、AtomicReferenceCountDownLatchを使用した完全な例です。

public class Main {
    public static void main(String[] args) throws InterruptedException {
        final AtomicReference<String> result = new AtomicReference<String>();
        final CountDownLatch latch = new CountDownLatch(1);

        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                String input = JOptionPane.showInputDialog(null, "Stop?", "Stop?", JOptionPane.QUESTION_MESSAGE);
                result.set(input);

                // Signal main thread that we're done and result is set.
                // Note that this doesn't block. We never call blocking methods
                // from Swing Thread!
                latch.countDown();
            }
        });

        // Here we need to wait until result is set. For demonstration purposes,
        // we use latch in this code. Using SwingUtilities.invokeAndWait() would
        // be slightly better in this case.

        latch.await();

        System.out.println(result.get());
    }
}

GUI(およびSwing)アプリケーションの一般的な設計に関するこの回答もお読みください。

于 2011-09-14T15:41:03.490 に答える
5

この入力文字列を本体で取得するにはどうすればよいですか?

あなたはそうしません。「メイン」がSwingダイアログボックスを呼び出して結果を処理するという考えは、グラフィカルユーザーインターフェイスの全体的な考えとは反対です。

GUIでは、ユーザーが開始した一連のイベントを処理するようにプログラムを設計します。これらのイベントは、一般的なワードプロセッサのキーストローク、選択、メニュー選択など、完全に非同期である場合があります。または、「ウィザード」の質問と回答の形式など、スクリプト化することもできます。

後者のようなことをしたいと仮定すると、次のシーケンスを使用してそれを実装します。

  1. ユーザーは、おそらくメニュー選択を選択するなど、何らかのアクションを開始します。これは、の呼び出しにActionListener変換され、ユーザーからの入力がさらに必要であると判断します。
  2. イベントディスパッチスレッドで実行される、は、ダイアログのActionListener表示など、UIに対して必要なすべてのことを実行できます。そのダイアログはモーダルでも非モーダルでもかまいません。ある場合には、出力は元のリスナーが利用できますが、別の場合には、後続のアクションを実行するために新しいリスナーを作成する必要があります。
  3. 十分な情報が得られたら、バックグラウンド操作を呼び出すことを選択できます。通常、これらの要求を処理するためのスレッドプールがあります。「メイン」スレッドでリクエストを実行しようとはしません。実際、すべてのインテントで、メインスレッドは実行されていません。
  4. 操作の実行が完了すると、を使用してデータをイベントディスパッチスレッドにプッシュバックしますSwingUtilities.invokeLater()。バックグラウンド操作の途中でSwingに結果を送信するために使用することはできますがinvokeAndWait()、それが良いアイデアになることはめったにありません。代わりに、一連の操作を作成します。できれば、ユーザーが簡単にキャンセルできる操作を作成します。

バックグラウンドスレッドで操作を開始する「標準的な」方法は、SwingWorkerを使用することです。選択肢があります。たとえば、を使用して、BlockingQueue実行時間の長い単一のバックグラウンドスレッドに操作を送信し、を使用invokeLater()して結果を返すことができます。

とにかく、破りたくないルールが1つあります。それは、イベントディスパッチスレッドでブロック操作を実行しないことです。これを行うと、アプリケーションが壊れます。

于 2011-09-14T19:33:58.240 に答える
3

現在、メインスレッドとEDT(イベントディスパッチスレッド)の2つのスレッドがあります。SwingUtilities.invokeLater(runnable)EDTでタスクを実行していることをご存知だと思います。

スレッド間でデータを共有するには、両方のスレッドのスコープ内にある変数が必要です。これを実現する最も簡単な方法は、volatileデータメンバーを宣言するかAtomicReference、mainメソッドを含むクラスで宣言することです。

によって返されたを確実に読み取るためにJOptionPane、ここで実行できる最も簡単な方法は、invokeLater呼び出しを呼び出しに変更することですinvokeAndWait。これにより、EDTに設定した内容が完了するまで、メインスレッドの実行が停止します。

元:

public class MyClass {
  private static volatile String mySharedData;
  public static void main(String[] args) throws InterruptedException {
    SwingUtilities.invokeAndWait(new Runnable() {
      public void run() {
        mySharedData = JOptionPane.showInputDialog(null, "Stop ?", JOptionPane.QUESTION_MESSAGE);
      }
    });
// main thread is blocked, waiting for the runnable to complete.

   System.out.println(mySharedData);
  }
}

オプションペインが表示されている間は停止してはならないタスクをメインスレッドが実行している場合、メインスレッドで定期的に(つまり、タスクを実行しているループの外側で)停止していないかどうかを確認できmySharedDataます。設定されています。タスクがループせず、代わりにI / Oを実行している、または待機している場合は、Thread.interruptmySharedDataを使用して、InterruptedExecptionハンドラーをチェックインできます。

于 2011-09-14T15:42:28.463 に答える
1

これには、おそらくPropertyChangeListenerを使用して、オブザーバー/オブザーバブルパターンを使用することをお勧めします。その後、Swingアプリは、重要な変数の状態が変化した場合に、すべてのリスナーに通知できるようになります。

例えば:

import java.awt.*;
import java.beans.*;
import javax.swing.*;
import javax.swing.event.*;

public class ListenToSwing  {
   public static final String STATE = "state";
   private static final int STATE_MAX = 10;
   private static final int STATE_MIN = -10;
   private JPanel mainPanel = new JPanel();
   private int state = 0;
   private JSlider slider = new JSlider(STATE_MIN, STATE_MAX, 0);

   public ListenToSwing() {
      mainPanel.add(slider);
      slider.setPaintLabels(true);
      slider.setPaintTicks(true);
      slider.setMajorTickSpacing(5);
      slider.setMinorTickSpacing(1);

      slider.addChangeListener(new ChangeListener() {

         @Override
         public void stateChanged(ChangeEvent e) {
            setState(slider.getValue());
         }
      });
   } 

   public void addPropertyChangeListener(PropertyChangeListener listener) {
      mainPanel.addPropertyChangeListener(listener);
   }

   public Component getMainPanel() {
      return mainPanel;
   }

   public void setState(int state) {
      if (state > STATE_MAX || state < STATE_MIN) {
         throw new IllegalArgumentException("state: " + state);
      }
      int oldState = this.state;
      this.state = state;

      mainPanel.firePropertyChange(STATE, oldState, this.state);
   }

   public int getState() {
      return state;
   }

   public static void main(String[] args) {
      final ListenToSwing listenToSwing = new ListenToSwing();

      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            JFrame frame = new JFrame("ListenToSwing");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.getContentPane().add(listenToSwing.getMainPanel());
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
         }
      });

      listenToSwing.addPropertyChangeListener(new PropertyChangeListener() {

         @Override
         public void propertyChange(PropertyChangeEvent evt) {
            if (evt.getPropertyName().equals(ListenToSwing.STATE)) {
               System.out.println("New state: " + listenToSwing.getState());
            }
         }
      });
   }

}
于 2011-09-14T16:56:34.027 に答える
0

ランナブルが値を設定する a を宣言することで、それを外部クラスに簡単に公開できString[]ます。ただし、 によって割り当てられているかどうかを知るには、何らかの同期メカニズムが必要になることに注意してくださいRunnable

于 2011-09-14T15:31:15.567 に答える