Java PropertyChange对SpinnerNumberModel的支持
我想听听JSpinner的SpinnerNumberModel值的变化。Java PropertyChange对SpinnerNumberModel的支持,java,swing,propertychanged,propertychangesupport,propertychangelistener,Java,Swing,Propertychanged,Propertychangesupport,Propertychangelistener,我想听听JSpinner的SpinnerNumberModel值的变化。 我创建了一个PropertyChangeSupport并将模型放入其中 我需要propertyChangeListener,因为它向我显示属性的新旧值 代码段不起作用:当我单击JSpinner时,propertyChange方法不会打印任何内容。 一个简单的ChangeListener只提供新的值,但我也需要旧的值,我如何获得它 package de.unikassel.jung; import java.beans.P
我创建了一个PropertyChangeSupport并将模型放入其中 我需要propertyChangeListener,因为它向我显示属性的新旧值 代码段不起作用:当我单击JSpinner时,
propertyChange
方法不会打印任何内容。一个简单的ChangeListener只提供新的值,但我也需要旧的值,我如何获得它
package de.unikassel.jung;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import javax.swing.JFrame;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
public class PropertyChangeTest implements PropertyChangeListener {
public static void main(String[] args) {
new PropertyChangeTest();
}
public PropertyChangeTest() {
JFrame frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
int value = 1;
int min = 0;
int max = 10;
int step = 1;
SpinnerNumberModel spinnerModel = new SpinnerNumberModel(value, min, max, step);
PropertyChangeSupport pcs = new PropertyChangeSupport(spinnerModel);
pcs.addPropertyChangeListener("value", this);
JSpinner spinner = new JSpinner(spinnerModel);
frame.getContentPane().add(spinner);
frame.setVisible(true);
}
@Override
public void propertyChange(PropertyChangeEvent evt) {
System.out.println(evt);
System.out.println(evt.getSource());
}
}
与其听模型,不如听编辑的,如下所示
JSpinner spinner = new JSpinner(new SpinnerNumberModel(1, 0, 10, 1));
JSpinner.DefaultEditor editor = (JSpinner.DefaultEditor) spinner.getEditor();
editor.getTextField().addPropertyChangeListener("value", this);
要使PropertyChangeSupport正常工作,您需要调用其
firePropertyChange
方法,但更重要的是,support对象需要能够访问其正在侦听的属性的setXXX方法,并且在该方法中需要调用PropertyChangeSupport的firePropertyChange方法。因此,我认为要使您的想法发挥作用,您需要扩展模型的类,为其提供PropertyChangeSupport对象,为其提供add和remove侦听器方法,并确保侦听模型的setValue方法中所做的更改,这是关键。在我的示例中,该方法如下所示:
@Override
public void setValue(Object newValue) {
// store old value and set the new one
Object oldValue = getValue();
super.setValue(newValue);
// construct the event object using these saved values
PropertyChangeEvent evt = new PropertyChangeEvent(this, VALUE, oldValue,
newValue);
// notify all of the listeners
pcs.firePropertyChange(evt);
}
下面是使用PropertyChangeSupport的示例模型类:
import java.beans.*;
import javax.swing.*;
import javax.swing.event.*;
@SuppressWarnings("serial")
class MySpinnerNumberModel extends SpinnerNumberModel {
public static final String VALUE = "value";
private SwingPropertyChangeSupport pcs = new SwingPropertyChangeSupport(this);
// you will likely need to create multiple constructors to match
// the ones available to the SpinnerNumberModel class
public MySpinnerNumberModel(int value, int min, int max, int step) {
super(value, min, max, step);
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
pcs.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
pcs.removePropertyChangeListener(listener);
}
@Override
public void setValue(Object newValue) {
// store old value and set the new one
Object oldValue = getValue();
super.setValue(newValue);
// construct the event object using these saved values
PropertyChangeEvent evt = new PropertyChangeEvent(this, VALUE, oldValue,
newValue);
// notify all of the listeners
pcs.firePropertyChange(evt);
}
}
最后是测试类,以测试上述类是否正常工作:
import java.beans.*;
import javax.swing.*;
public class TestSpinnerPropChange {
private static void createAndShowUI() {
final MySpinnerNumberModel myModel = new MySpinnerNumberModel(1, 0, 10, 1);
final JSpinner spinner = new JSpinner(myModel);
final JTextField oldValueField = new JTextField(10);
final JTextField newValueField = new JTextField(10);
JPanel panel = new JPanel();
panel.add(spinner);
panel.add(new JLabel("old value:"));
panel.add(oldValueField);
panel.add(new JLabel("new value:"));
panel.add(newValueField);
myModel.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
// checking the property name is overkill here, but is a good habit
// to get into, especially if listening to more than one property.
if (evt.getPropertyName().equals(MySpinnerNumberModel.VALUE)) {
oldValueField.setText(evt.getOldValue().toString());
newValueField.setText(evt.getNewValue().toString());
}
}
});
JFrame frame = new JFrame("TestSpinnerPropChange");
frame.getContentPane().add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
星期一早上。。。经典的不抵抗评论的时刻:-) @蒂马舍夫
- “需要propertyChangeListener,因为它向我展示了属性的新旧价值。”——(挑剔——但总是强烈要求将需求和解决方案分开:),我认为情况正好相反:在更改通知中,您需要访问新旧价值,propertyChangeEvent/Listener是支持它的通知类型,可能还有其他类型
- PropertyChangeSupport不应该用于观察代码的一部分,它应该用于观察者一侧(就像@Hovercraft在他的示例中所做的):它的唯一责任是管理并通知注册到观察者的侦听器
- 有时候,accessibleContext为黑客提供了一个钩子——然而,这是一个钩子到它的黑客(除非你真的需要支持可访问性,这很可能是这样的:-)与所有黑客一样,这是一个脆弱的解决方案,很可能在将来的某个时候会造成痛苦。更稳定地跟踪有关Action和AbstractButton如何交互的链接
- 用更丰富的更改通知增强模型是一条可行之路(如:my absolute Favorite:-)
- 只是一个小细节:如果你有一个奴隶,让他做所有的工作-PropertyChangeSupport有一些方法可以接受旧的/新的值,不需要feed在可观察对象上创建事件。当新旧相等时,它将被丢弃
- 对于通知事件中的newValue,不要使用参数,而是再次使用getValue(super可能已拒绝更改)
您必须在setters中启动属性更改。1+,因为这可能是一个比我更好的答案。谢谢,这很好。有没有类似JCheckBox的编辑器?JCheckBox的属性更改侦听器@垃圾Godsee.找到了:
checkBox.getAccessibleContext().addPropertyChangeListener(listener)
这保存了我的一天。。。为什么我们必须通过编辑器才能获得文本字段?+1添加属性更改支持的好例子,它回答了实际问题!:-)@垃圾神:是的,但是正确地解决问题比回答问题要好。您的答案可以做到这一点,更重要的是,代码要少得多。:)@mKorbel a)使用尽可能简单的组件来显示示例中的内容没有错b)MySpinnerModel对错误输入的鲁棒性(或不鲁棒性)作为其优点。我的建议是临时的。正如在对数据库进行反规范化时,必须了解并准备好后果。