开发者

How do I change the value of a JOptionPane from a PropertyChangeListener without triggering the listener?

开发者 https://www.devze.com 2023-03-27 19:38 出处:网络
I am trying to make a program to manage a group of sports players. Each player has an enum Sport, and SportManager has convenient factory methods. What I am trying to do is open a dialog that has a JT

I am trying to make a program to manage a group of sports players. Each player has an enum Sport, and SportManager has convenient factory methods. What I am trying to do is open a dialog that has a JTextField for a name and a combo box to choose a sport. However, I want to stop the user from closing the dialog while the text field is blank, so I wrote a PropertyChangeListener so that when the text field is blank, it would beep to let the user know. However, if the user puts in something in the text after setting off the beep, it doesn't trigger the listener and you can't close the dialog without pressing cancel because the value is already JOptionPane.OK_OPTION, and cancel is the only way to change JOptionPane.VALUE_PROPERTY. So I tried to add

message.setValue(JOptionPane.UNITIALIZED_VALUE);

within the listener. However this just closes the window right away without giving the user a chance to fill in the text field, presumably because it triggers the listener I just registered. How do I make it so that it will beep more than once and give the user a chance to fill in the field?

FYI newPlayer is the component I'm registering the action to.

Code:

    newPlayer.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e){
                Object[] msg = new Object [4];
                msg[0]  = new JLabel("Name:");
                final JTextField nameField = new JTextField();
                msg[1]=nameField;
                msg[2] = new JLabel("Sport: ");
                JComboBox<Sport> major = new JComboBox<Sport>(SportManager.getAllSports());
                msg[3]=major;
                final JOptionPane message = new JOptionPane();
                message.setMessage(msg);
                message.setMessageType(JOptionPane.PLA开发者_运维知识库IN_MESSAGE);
                message.setOptionType(JOptionPane.OK_CANCEL_OPTION);
                final JDialog query = new JDialog(gui,"Create a new player",true);
                query.setContentPane(message);
                query.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
                message.addPropertyChangeListener(
                        new PropertyChangeListener() {
                            public void propertyChange(PropertyChangeEvent e) {
                                String prop = e.getPropertyName();


                                if (query.isVisible()&& (e.getSource() == message)&& (prop.equals(JOptionPane.VALUE_PROPERTY))) {
                                    if(nameField.getText().equals("")&&message.getValue().equals(JOptionPane.OK_OPTION)){
                                        Toolkit.getDefaultToolkit().beep();
                                        message.setValue(JOptionPane.UNINITIALIZED_VALUE);
                                        return;
                                    }
                                    query.dispose();
                                }
                            }

                        });
                query.pack();
                query.setVisible(true);
                if(Integer.parseInt(message.getValue().toString())==JOptionPane.OK_OPTION){
                    players.add(new Player(nameField.getText(),(Sport)major.getSelectedItem()));
                    edited=true;
                }
                gui.show(players);
            }
        });


I don't think you can do it with JOptionPane but you can using using TaskDialog framework and few others.

You can also create a dialog yourself, attach change listeners to your fields and enable/disable OK button based on content of your fields. This process is usually called "form validation"


However, I want to stop the user from closing the dialog while the text field is blank

I get where you are going, but Java Swing is not very good at this. There is no way you can prevent the listener from being called. A solution would be to ignore the call, but this is complicated to implement.

The way I solved this issue is to let the pop-up disappear, check the returned value and if it is null/empty, beep and re-open it until user fills something.


JOptionPane does not internally support validation of inputs (Bug Reference). Your best bet is to create your own custom JDialog which supports disabling the OK button when the input data is invalid.

I'd recommend reading the bug report since other people talk about it and give workarounds.


However, I want to stop the user from closing the dialog while the text field is blank

The CustomDialog example from the section in the Swing tutorial on Stopping Automatic Dialog Closing has a working example that does this.

After taking a quick look at your code and the working example I think your code should be something like:

if (query.isVisible()
&& (e.getSource() == message)
&& (prop.equals(JOptionPane.VALUE_PROPERTY)))
{
    if (message.getValue() == JOptionPane.UNINITIALIZED_VALUE)
        return;

    if (nameField.getText().equals("")
    && message.getValue().equals(JOptionPane.OK_OPTION))
    {
        Toolkit.getDefaultToolkit().beep();
        message.setValue(JOptionPane.UNINITIALIZED_VALUE);
    }
    else
        query.dispose();
}

Otherwise, I'll let you compare your code with the working code to see what the difference is.


One way to solve this problem is to add a Cancel and Ok button to your dialog. Then, disable closing the popup via the X in the corner, forcing the user to click either Cancel or Ok to finish/close the dialog. Now, simply add a listener to the text field that will disable the Ok button if the text field is blank.

Judging from your code I assume you can figure out how to implement these steps, but if you have trouble let us know! Good luck!

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号