简体   繁体   中英

Updating message in JOptionPane with JSpinner stateChanged method

I have made a JOptionPane with JSpinner component in it. I have a String called skillMessage that will be the message shown in the JOptionPane. I've combined the researches I made online to make such an option pane (with message and spinner along with it's overridden stateChanged method). This is my code:

skillMessage = "Current skill level: " + currLevel + "\n";

if (skillPoint > 0) {
    skillMessage += "Do you want to upgrade this skill to level " + (currLevel + 1)  + "?\n";
} else {
    skillMessage += "You do not have enough skill point to upgrade this skill!\n";
}

skillMessage += "Cost: 1 skill point\nYou have: " + skillPoint + " skill point(s) left";

if (skillPoint > 0) {
    Object[] options = {"Upgrade", "Cancel"};

    JSpinner spinner = new JSpinner(new SpinnerNumberModel(currLevel, currLevel, maxLevel, 1));
    JComponent comp = spinner.getEditor();
    JFormattedTextField field = (JFormattedTextField)comp.getComponent(0);
    DefaultFormatter formatter = (DefaultFormatter)field.getFormatter();
    formatter.setCommitsOnValidEdit(true);
    ((JSpinner.DefaultEditor)comp).getTextField().setEditable(false);
    ((JSpinner.DefaultEditor)comp).getTextField().setFocusable(false);

    spinner.addChangeListener(new ChangeListener() {
        @Override
        public void stateChanged(ChangeEvent ce) {
            int valueChanged = (Integer)spinner.getValue() - currLevel;
            skillMessage = "Current skill level: " + spinner.getValue() + "\n";

            if ((skillPoint - valueChanged) > 0) {
                skillMessage += "Do you want to upgrade this skill to level " + (currLevel + 1)  + "?\n";
            } else {
                skillMessage += "You do not have enough skill point to upgrade this skill!\n";
            }

            skillMessage += "Cost: 1 skill point\nYou have: " + (skillPoint - valueChanged) + " skill point(s) left";
            repaint();
        }
    });

    if (JOptionPane.showOptionDialog(null, new Object[] {skillMessage, spinner}, "Upgrade Skill", 1, 3, null, options, options[0]) == 0) {
        if ((skillPoint - (Integer)spinner.getValue() - currLevel) >= 0) {
            currLevel++;
            JOptionPane.showMessageDialog(null, "You've successfully upgraded this skill to level " + currLevel);
        } else {
            JOptionPane.showMessageDialog(null, "You do not have enough skill point!");
        }
    }
}

What I want to do now is to make the skillMessage in JOptionPane got "updated" along with every time the spinner's stateChanged method got called. Repainting it doesn't seem to do the work. Thanks in advance!

You're not actually triggering a repaint on the JOptionPane , even if you did, I'm not sure it would update anyway.

A better solution would be to encapsulate the functionality you're trying to perform into it's own class/component, this way, you gain control over the view itself and can update the components as you see fit

As an example:

public class SkillPane extends JPanel {

    private JSpinner spinner;
    private JLabel[] messages;
    private int skillPoints;
    private int currLevel;

    public SkillPane(final int currLevel, final int maxLevel, final int skillPoint) {
        spinner = new JSpinner(new SpinnerNumberModel(currLevel, currLevel, maxLevel, 1));
        this.skillPoints = skillPoint;
        this.currLevel = currLevel;

        messages = new JLabel[]{new JLabel(), new JLabel(), new JLabel()};
        updateMessages();

        setBorder(new EmptyBorder(4, 4, 4, 4));
        setLayout(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.insets = new Insets(4, 4, 4, 4);
        gbc.gridwidth = GridBagConstraints.REMAINDER;
        gbc.anchor = GridBagConstraints.LINE_START;
        add(messages[0], gbc);
        add(messages[1], gbc);
        add(messages[2], gbc);
        add(spinner, gbc);

        spinner.addChangeListener(new ChangeListener() {
            @Override
            public void stateChanged(ChangeEvent ce) {
                updateMessages();
            }
        });
    }

    public int getValue() {
        return (int) spinner.getValue();
    }

    public void updateMessages() {
        int valueChanged = (Integer) spinner.getValue() - currLevel;
        messages[0].setText("Current skill level: " + spinner.getValue());

        if ((skillPoints - valueChanged) > 0) {
            messages[1].setText("Do you want to upgrade this skill to level " + (currLevel + 1) + "?");
        } else {
            messages[1].setText("You do not have enough skill point to upgrade this skill!");
        }

        messages[2].setText("Cost: 1 skill point\nYou have: " + (skillPoints - valueChanged) + " skill point(s) left");
    }

}

nb: My original design had a single label and use HTML to format the text, but I found that kept breaking the dialog, you could also use a non-editable JTextArea or similar component to generate a similar effect

Which you can call using something like...

    int skillPoint = 10;
    int currLevel = 0;

    Object[] options = {"Upgrade", "Cancel"};
    SkillPane pane = new SkillPane(currLevel, 100, skillPoint);

    if (JOptionPane.showOptionDialog(null, pane, "Upgrade Skill", 1, 3, null, options, options[0]) == 0) {
        int value = pane.getValue();

        if ((skillPoint - value - currLevel) >= 0) {
            currLevel++;
            JOptionPane.showMessageDialog(null, "You've successfully upgraded this skill to level " + currLevel);
        } else {
            JOptionPane.showMessageDialog(null, "You do not have enough skill point!");
        }
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM