Swing JCheckBox is based on MVC. Thus, I want that the check box开发者_开发知识库es in my GUI use a data model that my custom class provides.
That is:checkBox1
is "bound" to a property isBackgroundShown
checkBox2
is "bound" to a property isResizingEnabled
The checkboxes should be based on property state, the property state should fire a checkbox refresh if changed.
actually, AbstractButtons don't have a "real" model (which should be shareable across buttons) - the ButtonModel has per-instance view state (pressed, armed) mixed with more data-like state like selected. What's worse, the selected property on the button only looks like a bound property (with setters and getters) but isn't (never fires propertyChange).
Your options:
- implement a ButtonModel which fires a PropertyChange on change of selected and set it to the JCheckBox, then bind that new property of the model to your data property
- use an Action as intermediate and bind the its Action.SELECTED_KEY to your data model
- implement an Adapter on top of the ButtonModel which maps changeEvents to propertyChangeEvents if selected changed
- use a binding framework which does the one or other automatically (JGoodies Binding does the first, BeansBinding the last)
Great answer. I'd like to expand the options you have written.
The first option: implementing a button model with PropertyChange
Considerations:
1. The ButtonModelWithPropertyChange can be written once for many controls and its code is not logically part of the client class code, so it doesn't add complexity to the client class code.
2. I've adopted the shortcut of writing sync code into the property setter, while I should
have written a PropertyChange for the client class's property and bound the properties togheter.
While the second is the "standard" way, it seems to me that is a lot of code, and I'm more intrested in this solution only if an IDE like Netbeans were able to manage it for me (as probably is).
//use static if you nest the class
public /*static*/ class ButtonModelWithPropertyChange extends ToggleButtonModel {
public static final String PROP_SELECTED = "test";
@Override
public void setSelected(boolean selected) {
boolean oldSelected = isSelected();
super.setSelected(selected);
propertyChangeSupport.firePropertyChange(PROP_SELECTED, oldSelected, selected);
}
private PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
public void addSelectedChangeListener(PropertyChangeListener listener) {
propertyChangeSupport.addPropertyChangeListener(listener);
}
public void removeSelectedChangeListener(PropertyChangeListener listener) {
propertyChangeSupport.removePropertyChangeListener(listener);
}
}
And use it:
import java.awt.*;
import java.awt.event.*;
import java.beans.*;
import javax.swing.*;
import javax.swing.JToggleButton.ToggleButtonModel;
public class TestCheckBoxWithMVC extends JFrame {
public static void main(String [] args) {new TestCheckBoxWithMVC().setVisible(true);}
//my checkbox AND my "bounded" property
JCheckBox myCheckBox = new JCheckBox("my checkbox");
ButtonModelWithPropertyChange buttonModel;
public boolean myProperty;
//my button to test to assign the property and see the checkbox changed accordingly
JButton testBtn = new JButton("Assigning property directly");
public boolean isMyProerty() {
return myProperty;
}
//my property setter that sets the selected value of the model of the checkbox too
public void setMyProperty(boolean b) {
myProperty = b;
buttonModel.setSelected(b);
}
public TestCheckBoxWithMVC() {
super();
setLayout(new FlowLayout());
buttonModel = new ButtonModelWithPropertyChange();
buttonModel.addSelectedChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
myProperty = (Boolean)evt.getNewValue();
}
});
myCheckBox.setModel(buttonModel);
add(myCheckBox);
testBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
setMyProperty(!isMyProerty());
}
});
add(testBtn);
pack();
}
//insert here the ButtonModelWithPropertyChange uncommenting static OR put it in
//an ad hoc file.
}
精彩评论