Frage

Hello I have something like this

public class GUI{
    public JCheckBox box;
    public boolean value;

    void init(){
        box.addActionListener(new BoxListener(this));
    }
}

public class BoxListener implements ActionListener{
    GUI gui;
    public BoxListener(GUI gui){
         this.gui = gui;
    }

    @override
    public void actionperformed(ActionEvent a){
         gui.value = true; 
    }

}

Now I want to change the value of the bool when the checkbox gets clicked. I am looking for better solutions than to pass Class GUI as input parameter for a self written listener.

Are there any better solutions?

War es hilfreich?

Lösung

I would throw in some MVC it's a lot more work, but it makes for more flexible coding.

First a ModelBean with a boolean checked and propertyChangeSupport for firing property change events

import java.beans.*;
import java.io.Serializable;

public class ModelBean implements Serializable {

    private boolean checked;

    private PropertyChangeSupport propertySupport;

    public ModelBean() {
        propertySupport = new PropertyChangeSupport(this);
    }

    public boolean getChecked() {
        return checked;
    }

    public void setChecked(boolean checked) {
        boolean oldValue = this.checked;
        this.checked = checked;
        propertySupport.firePropertyChange("checked", oldValue, this.checked);
    }

    public void addPropertyChangeListener(PropertyChangeListener listener) {
        propertySupport.addPropertyChangeListener(listener);
    }

    public void removePropertyChangeListener(PropertyChangeListener listener) {
        propertySupport.removePropertyChangeListener(listener);
    }  
}

Then you have your main GUI class that takes the ModelBean as an argument

class GUI extends JFrame {
    private ModelBean model;
    private JCheckBox cbox;

    public GUI(ModelBean model) {
        this.model = model;
        cbox = new JCheckBox("Check and watch me print");
        cbox.addItemListener(new CheckListener(model));

        setLayout(new GridBagLayout());
        add(cbox);
        setSize(300, 300);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setVisible(true);
    }
}

And you ItemListener class that takes the same ModelBean as an argument and also adds the PropertyChangeListener to the model

class CheckListener implements ItemListener {

    private ModelBean model;

    public CheckListener(ModelBean newModel) {
        this.model = newModel;
        model.addPropertyChangeListener(new PropertyChangeListener() {
            public void propertyChange(PropertyChangeEvent e) {
                System.out.println(model.getChecked());
            }
        });
    }

    @Override
    public void itemStateChanged(ItemEvent e) {
        JCheckBox source = (JCheckBox) e.getSource();
        if (source.isSelected()) {
            model.setChecked(true);
        } else {
            model.setChecked(false);
        }
    }
}

Then you class to run the program

public class TestMVC {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                final ModelBean model = new ModelBean();
                GUI gui = new GUI(model);
            }
        });
    }
}

It seems like a lot of work just for a silly boolean but the concept is a better overall design for larger programs where a lot of different data needs to be manipulated and listened to for changes.


UPDATE

Another option, if your GUI is the parent container, and you don't want to expose it by passing it by reference, you can create an interface and have GUI implement it

public interface BooleanInterface {
    public void setBoolean(boolean bool);
}

public class GUI extends JFrame implements BooleanInterface {
    boolean bool;

    @Override
    public void setBoolean(boolean bool) {
        this.bool = bool;
    }
}

public BoxListener implements ActionListener {
    BooleanInterface boolFace;

    public BoxListener(BooleanInterface boolFace) {
        this.boolFace = boolFace;
    }
}

You can then pass the GUI to the listener. Though it looks the same as what you're already doing, it actually isn't, since it no longer exposes the GUI, instead uses the interface.

Andere Tipps

Why don't we take what you have and modify it slightly:

First, create a Controller (DefaultController) class that will handle initializing the application and will hold a reference to the GUI (or View)

public class DefaultController
{
    private final GUI view = new GUI(); // The view

    private void init()
    {
        // ...

        this.view.addBoxListener(new BoxListener(this.view));

        // ...
    }

    public static void main(String[] args)
    {
        // ... Start up code ...
    }
}

Next, modify your GUI class to include methods for interacting with the JCheckBox and register a listener:

public class GUI
{
    private JCheckBox box;

    // ...

    public void addBoxListener(ItemListener listener)
    {
        box.addItemListener(listener);
    }

    public void setBoxValue(boolean selected)
    {
        box.setSelected(selected);
    }

    // ...
}

Now your BoxListener has an instance of the view (GUI) and can make calls to set the checkbox's value through the interface provided. You are no longer accessing the box member variable directly (encapsulation). This will allow you to make changes to the setBoxValue method without impacting the caller.

In your BoxListener class:

@Override
public void itemStateChanged(ItemEvent evt)
{
    view.setBoxValue(true); // For example...
}

Note: view is a member variable of BoxListener - private GUI view;

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top