How to wait for JOptionPane to be closed before dispatching any more events

白昼怎懂夜的黑 提交于 2019-12-08 07:16:32

问题


I have a couple text fields that I'm tabbing between. On focusLost() I am opening a JOptionPane. I would like the code in focusGained() to be executed AFTER the JOptionPane has been closed. Even though the dialog is modal, focusGained() is being called before the JOptionPane is closed. Is there any way around this?

Found this similar question, but it doesn't seem to have been solved either. Postpone Event Queue after Focus Lost

Here's a code sample. You'll notice "Focus Gained" is printed before the JOptionPane is closed.

import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class ShortTest implements FocusListener
{
private void go()
{
    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    JPanel panel = new JPanel();
    panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));

    JTextField text1 = new JTextField();
    text1.setName("text1");
    text1.addFocusListener(this);

    JTextField text2 = new JTextField();
    text2.setName("text2");
    text2.addFocusListener(this);

    panel.add(new JLabel("tex1"));
    panel.add(text1);

    panel.add(new JLabel("text2"));
    panel.add(text2);

    frame.setContentPane(panel);
    frame.pack();
    frame.setVisible(true);
}

public static void main(String [] args)
{
    ShortTest test = new ShortTest();
    test.go();
}

@Override
public void focusGained(FocusEvent e)
{
    if (!e.isTemporary() && (e.getSource() instanceof JTextField))
    {
        System.out.println("Focus Gained: " + ((JTextField)e.getSource()).getName());
    }
}

@Override
public void focusLost(FocusEvent e)
{
    if (!e.isTemporary() && (e.getSource() instanceof JTextField))
    {
        JOptionPane.showOptionDialog(null, ((JTextField)e.getSource()).getName() + " lost focus", "Title", JOptionPane.DEFAULT_OPTION, 0, null, null, null);
    }
}
}

回答1:


Perhaps what you want is not a focus listener (a very low-level construct) but rather an input verifier (a higher level construct). This should respond before the focus has shifted. For example, in the code below the verifier reacts if the user tries to enter non-numeric data into the text field. Yes this can also be done using a DocumentFilter.

import javax.swing.*;

public class VerifierEg extends JPanel {
   private static final int FIELD_COUNT = 3;

   public VerifierEg() {
      InputVerifier inputVerifier = new InputVerifier() {

         @Override
         public boolean verify(JComponent input) {
            final JTextField textField = (JTextField) input;
            String text = textField.getText();
            for (char c : text.toCharArray()) {
               if (!Character.isDigit(c)) {
                  textField.setText("");
                  JOptionPane.showMessageDialog(VerifierEg.this, "Text: \""
                        + text + "\" must hold only digits", "Text Field Error",
                        JOptionPane.ERROR_MESSAGE);
                  return false;
               }
            }
            return true;
         }
      };
      for (int i = 0; i < FIELD_COUNT; i++) {
         JTextField field = new JTextField(6);

         field.setInputVerifier(inputVerifier);
         add(field);
      }
   }

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

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

Edit:
The InputVerifier could work for your purpose, even if you're not verifying the input in any specific way. For example, to modify your code:

import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import javax.swing.BoxLayout;
import javax.swing.InputVerifier;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class ShortTest2 {
   private void go() {
      final JFrame frame = new JFrame();
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

      JPanel panel = new JPanel();
      panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));

      InputVerifier inputVerifier = new InputVerifier() {

         @Override
         public boolean verify(JComponent input) {
            JOptionPane.showMessageDialog(frame,
                  "Focus Lost on " + input.getName());
            return true;
         }
      };

      FocusListener focusListener = new FocusListener() {

         @Override
         public void focusLost(FocusEvent e) {
            String name = ((JComponent)e.getSource()).getName();
            System.out.println("Focus Lost: " + name );
         }

         @Override
         public void focusGained(FocusEvent e) {
            String name = ((JComponent)e.getSource()).getName();
            System.out.println("Focus Gained: " + name );
         }
      };

      JTextField[] textFields = new JTextField[2];
      for (int i = 0; i < textFields.length; i++) {
         JTextField textField = new JTextField(10);
         String name = "text " + (i + 1);
         textField.setName(name);
         textField.setInputVerifier(inputVerifier);
         textField.addFocusListener(focusListener);

         panel.add(new JLabel(name));
         panel.add(textField);         
      }

      frame.setContentPane(panel);
      frame.pack();
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      ShortTest2 test = new ShortTest2();
      test.go();
   }
}

1+ for your SSCCE by the way!



来源:https://stackoverflow.com/questions/11091457/how-to-wait-for-joptionpane-to-be-closed-before-dispatching-any-more-events

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!