2017-08-16 12 views
1

私はシンプルな「続行」を聞くことができる必要があるシステムを持っています。スタイルの質問。テキストフィールドとボタンがあります。孤立してテキストフィールドを変更するか、ボタンを単独で押してください。ユーザーに確認を依頼する必要があります。これは、テキストフィールドのフォーカスリスナーと、ボタンのアクションリスナーを提供します。JOptionPaneはどのように同期されていませんか?

ただし、フィールドを編集してすぐにボタンをクリックすると、フォーカスリスナーからの確認ダイアログボックスと、直後のアクションリスナーからの確認ダイアログボックスが表示されます。今は確認が一度だけ必要なので、JOptionPaneをスローする関数を同期させてみましたので、2回入力しなくても効果はないようです。

これを証明するいくつかのコード:

public class Main extends JFrame { 
    static public void main(String [] args) { 
     SwingUtilities.invokeLater(() -> { 
      Main m = new Main(); 
      m.setVisible(true); 
     }); 
    } 

    private JTextField field; 
    private JButton button; 

    private boolean isValid; 

    public Main() { 
     isValid = false; 

     setLayout(new BorderLayout()); 

     field = new JTextField(15); 
     field.addFocusListener(new FocusListener() { 
      @Override 
      public void focusGained(FocusEvent arg0) {} 

      @Override 
      public void focusLost(FocusEvent e) { 
       doValidate(); 
      } 
     }); 
     add(field, BorderLayout.CENTER); 

     button = new JButton("Push Me"); 
     button.addActionListener((ActionEvent e) -> { 
      doValidate(); 
      doAction(); 
     }); 
     add(button, BorderLayout.SOUTH); 

     pack(); 
    } 

    private synchronized void doValidate() { 
     System.out.println("Validating"); 
     if(!isValid) { 
      int answer = JOptionPane.showConfirmDialog(this, "Really do it?"); 
      if(answer == JOptionPane.YES_OPTION) 
       isValid = true; 
     } 
    } 

    private void doAction() { 
     System.out.println("Action done!"); 
    } 
} 

まず第一に、これはやや意外な動作です。 Swing/JOptionPaneがsynchronizedキーワードをどのように巡回することができるかについて誰かが説明してくれれば幸いです。

対処方法については、私は確認ダイアログへの答えを待つスレッドを実装する必要があると考えています。次に、スレッドがアクティブかどうかを確認する必要があります(ダイアログがすでに起動している場合)。もしそれが起動している場合は、応答が与えられたときにリスナーを追加する必要があります。私はすでに先に行ってこれをやっていましたが、問題の解決策のオーバーエンジニアリングのように感じます。なぜこれが最初に起こったのかについての限られた理解があるからです。さらに、私はすでに少なくともいくつかの異なるケースを想像することができます。問題が発生すると、エラーが発生しやすくなります。

===編集===

を明確にするために、これらのメッセージボックスはない順序で、同時にポップアップします。たとえば:

Two panes

答えて

1

同期は、2つのスレッドがないこれまで、同時にブロックに入ることができないことを意味します。彼らは単に、他のスレッドがそのメソッドに対するロックを解除してから呼び出すのを待つだけです。したがって、あなたの2つのダイアログ。

私はUIレンダリングが同じスレッドだと思うので、おそらくこれは関係ありません.2つの別々のUIイベントから同じメソッドを2回呼び出すだけです(私は間違っているかもしれません)。

スレッドを心配する必要はありませんが、代わりにDocumentListenerを参照してください。

+0

だから何混乱していますがJOptionPane.showConfirmDialog()がブロッキング機能することになっているということです。ダイアログは順番にポップアップしません(それは理にかなっています)。それらは並行して開きます!コードを試してみると、いずれかのボタンを押す前に「検証中」というメッセージが2回ポップアップすることがわかります。 –

0

赤いxをクリックするとプログラムが終了するように、次のように追加することをおすすめします。

setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); //new 

ボタンリスナーを取り外すだけで、希望の動作が得られると考えてください。ここで

は、私はあなたが望む行動を取得すると考えているコードは次のとおりです。

package swingdemo1; 

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

public class SwingDemo1 extends JFrame { 
    static public void main(String [] args) { 
     SwingUtilities.invokeLater(() -> { 
      SwingDemo1 m = new SwingDemo1(); 
      m.setVisible(true); 
     }); 
    } 

    private JTextField field; 
    private JButton button; 

    private boolean isValid; 
    private boolean validationDone; 
    String state; 

    public SwingDemo1() { 

     setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); //new 

     isValid = false; 

     setLayout(new BorderLayout()); 

     field = new JTextField(15); 
     field.addFocusListener(new FocusListener() { 
      @Override 
      public void focusGained(FocusEvent arg0) { 

      } 
      @Override 
      public void focusLost(FocusEvent e) {    
        doValidate(); 
        doAction();          
      } 
     }); 
     add(field, BorderLayout.CENTER); 

     button = new JButton("Push Me"); 
     /*               //new 
     button.addActionListener((ActionEvent e) -> { 
      System.out.println("ActionEvent: " + e.getActionCommand());    
       doValidate(); 
       doAction(); 
      }); 
     */               //new 
     add(button, BorderLayout.SOUTH); 

     pack(); 
    } 

    private synchronized void doValidate() { 
     System.out.println("Validating"); 
     if(!isValid) { 
      int answer = JOptionPane.showConfirmDialog(this, "Really do it?"); 
      if(answer == JOptionPane.YES_OPTION) 
       isValid = true; 
     }   
    } 

    private void doAction() { 
     System.out.println("Action done!"); 
    } 
} 
+0

プロダクションシステムでは複数のフィールドがあるので、いずれかのフィールドにフォーカスを失うとアクションを完了することは望ましくありません。さらに、いずれのフィールドにも触れていない場合(ファイルロードからデータが入力されたと仮定します)、アクションを実行する前に検証ステップが必要です。 –

+0

フォーカスを失うときにはアクションを完了させないことをお勧めします。私はちょうどあなたの質問と例から、これが要件であると思った。ボタンリスナーのみを使用してアクションを完了する方が理にかなっています。 – Charles

関連する問題