2017-08-16 109 views
1

我有一个系统,我需要能够问一个简单的“继续?”风格的问题。有一个文本字段和一个按钮。无论是单独修改文本字段还是单独按下按钮,我都需要能够让用户确认。所以,这给了我一个关于文本字段的焦点侦听器和一个按钮上的动作侦听器。但是,如果我编辑该字段,并立即单击该按钮,将弹出两个确认对话框 - 一个来自焦点侦听器,另一个来自紧跟其后的动作侦听器。现在,我显然只需要确认一次,所以我试着同步抛出JOptionPane的函数,所以它不会输入两次,但这似乎没有效果。JOptionPane如何不尊重同步?

一些代码演示此:

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如何能够绕行同步关键字有所解释,我很乐意。

至于如何处理,我的想法是,我需要实现一个线程,等待确认对话框的答案。然后,我需要检查线程是否处于活动状态(如果对话框已经启动,那就是),如果它已经启动,我需要添加一个监听器来给出答案。我已经提前完成了这个任务,但感觉就像是过度设计解决问题的方案,特别是因为我对这个问题首先发生的原因缺乏了解。此外,我已经可以想象至少有几个不同的情况下,我最终会陷入困境,使其可能更容易出错。

===编辑===

需要明确的是,这些消息框弹出的同时,没有先后顺序。例如:

Two panes

回答

1

同步意味着2个线程不能在同一时间输入块,而不是永远。他们只会等待其他线程释放对该方法的锁定,然后调用它。因此你的2个对话框。

无论如何,这可能是不相关的,因为我认为UI渲染是相同的线程,所以你只是从2个独立的UI事件(我可能是错误的)调用两次相同的方法。

至于让它工作,不用担心线程,而是看看DocumentListener

+0

那么,什么是令人困惑的是,JOptionPane.showConfirmDialog()被认为是阻挡功能。对话框不会按顺序弹出(这很有意义),它们并行打开!如果您尝试使用该代码,您会看到按下任何按钮之前弹出“验证”消息两次。 –

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