ActionListener никогда не срабатывает, если предыдущий слушатель вызывает revalidate () - PullRequest
0 голосов
/ 20 мая 2019

Итак, я создал базовый пользовательский интерфейс, который отображает текстовые поля, которые будут предупреждать пользователя, если содержимое выходит за пределы заданных границ, вызывая появление над ним метки. Это происходит, если пользователь нажимает клавишу возврата или вкладки вдали от поля.

Также есть кнопка, которая будет продвигать программу, если все поля введены правильно. Если это не так, текстовые поля будут мигать (фон анимации снова станет белым).

Это работает хорошо, за исключением одной маленькой ошибки - если пользователь вводит неверные данные и сразу нажимает кнопку, не покидая поля, слушатель фокуса срабатывает и добавляет метку под текстовым полем, но действие кнопки щелчка никогда не срабатывает (без вспышки ). По-видимому, это связано с тем, что событие FocusListener вызывает revalidate () на панели и / или pack () на включающем jframe.

Вот минимальный рабочий пример, демонстрирующий проблему

import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

/**
 * Demonstration that running revalidate() or JFrame.pack() in FocusListener
 * (on a textField) causes the action listener for a JButton to never fire.
 * 
 * This is only a problem if the contents of the frame are changed (ie. only 
 * happens once when label is added).
 */
public final class App {
    private App() {
        JFrame jFrame = new JFrame();
        JPanel main = new JPanel();
        MyPanel myPanel = new MyPanel();
        JButton button = new JButton("Click");
        button.addActionListener(event->{
            /* with the code as it is  this will never print if 
                the button is pressed while textField has focus
                and label is not yet displayed  */
            System.out.print("\n Click has been pressed");  
        });
        main.add(myPanel);
        main.add(button);
        jFrame.add(main);
        jFrame.pack();
        jFrame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(()-> new App());
    }

    /**
     * Creates a panel containing a text box.
     * when this text box looses focus it causes 
     * a label to be added and the frame to resize (.pack())
     */
    class MyPanel extends JPanel{
        JLabel label;
        JTextField textField;
        public MyPanel(){
            label = new JLabel("hello");
            textField = new JTextField(10);
            this.add(textField);
            textField.addFocusListener(new Handler(this));
        } 
        private class Handler implements FocusListener{
            JPanel panel;
            public Handler(JPanel panel){
                this.panel = panel;   
            }
            @Override
            public void focusGained(FocusEvent e) {

            }
            @Override
            public void focusLost(FocusEvent e) {
                // if this line is removed
                panel.add(label);
                // if the below two lines are removed 
                // button ActionListener will fire 
                panel.revalidate();
                SwingUtilities.getWindowAncestor(panel).pack(); // side note if this is called is revalidate() needed?
            }
        }
    }
}

Любой совет, как это исправить, был бы великолепен. Следует отметить, что в реальной программе класс MyPanel был бы в своем собственном файле, если это влияет на какие-либо решения.

Приветствие.

=============== РЕДАКТИРОВАТЬ =====================

Я запускал его в своей IDE (vscode), где возникла проблема. Когда я скомпилировал его и запустил из терминала, он работал нормально. Я предполагаю, что это немного причуды IDE.

...