简体   繁体   中英

How can a component on a panel alert other components outside the panel when a value changes?

I am writing a Swing program in which all panels are declared as separate classes and a JFrame that holds the panels. The input panel has a subpanel that has a number of buttons on it. When when one of those buttons is clicked and a value is calculated, I would like to pass that value back to the JFrame holding the input panel, so that the value can be used in a number of other calculations.

I know that I can just use the JFrame ActionListener to be directly responsible for the buttons on the sub panel, but that seems to violate either portability, encapsulation, or both. I want the sub panel to be able to work on its own and let the JFrame using it be aware when a certain value changes.

I would prefer to keep the value as a primitive, but if only an object works, I can go with that.

The program has already been written as one class and it worked fine, but a beast to edit. When I was done, I realized that it was a mistake not to break it down into six panels each as their own class. A lesson for future projects. So, I am rewriting it and running into the problem that the JFrame is dependent on knowing when one of its panels (actually a panel on that panel) recalculates a value. The value calculation isn't a problem, but the JFrame needs to know when it changes.

I hope that is clear. It seemed pretty clear to me! :-)

The following code is a simplification of what I'm trying to do.

import java.awt.BorderLayout;
import java.awt.event.*;
import javax.swing.*;

public class ChangeState extends JFrame {
    // This is to receive the value when changed in ButtonPanel
    private JTextField answer = new JTextField(5);

    private InputPanel inputPanel = new InputPanel();

    public ChangeState() {
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    add(inputPanel, BorderLayout.CENTER);
    add(answer, BorderLayout.SOUTH);
    pack();
    setVisible(true);
    }

    public static void main(String[] args) {
    ChangeState mf = new ChangeState();
    }
}

class InputPanel extends JPanel {
    private ButtonPanel buttonPanel = new ButtonPanel();

    InputPanel() {
    add(buttonPanel);
    }
}

class ButtonPanel extends JPanel implements ActionListener {
    private int value;

    JButton b1 = new JButton("Value *2");
    JButton b2 = new JButton("Value *3");

    public ButtonPanel() {
    value = 1;
    b1.addActionListener(this);
    add(b1);
    b2.addActionListener(this);
    add(b2);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
    if (e.getSource() == b1) {
            value *= 2;
    }
    if (e.getSource() == b2) {
        value *= 3;
    }
    System.out.println("Value: " + value);
/*
 * How do I let ChangeState.answer know VALUE has changed and needs
 * to be updated?
 */
    }
}

You can make ChangeState an observer of your ButtonPanel, by being an ActionListener listening to the ButtonPanel, or by being some other custom observer that's more abstract which you can create.

I'd recommend a more abstract custom observer when the class observing is not another GUI class with only one event, but in this case since it is perhaps you can just use an ActionListener (on the other hand, ChangeState is not much of a GUI class, you could have made it be composed of a JFrame).

If you have more than one event that could be passed through that ActionListener, you will probably then need to make ChangeState implement a more abstract observer implementation so you can better distinguish between events. Otherwise you'll need to have ChangeState know the name of some of the different GUI components that created the event's, or have a reference to them which would not be that great design wise.

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