我有2 JFormattedTextField
个以不同的形式输入相同的信息。我想在用户更改另一个时进行一次更改。我在使用PropertyChangeListener
之前已经实现了类似的功能,但是这次我遇到了一个奇怪的错误。
当我的JFrame
打开时,PropertyChangeListener
事件被触发,原因无关紧要。 getNewValue()
上PropertyChangeEvent
的值为空。
以下是引用我的标签的所有代码:
private JFormattedTextField fpsField;
然后在我的JFrame构造函数中:
fpsField = new JFormattedTextField(NumberFormat.getInstance());
fpsField.addPropertyChangeListener("value", new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent arg0) {
if(!updatingFPS){
updatingFPS = true;
Float fps = (Float) arg0.getNewValue();
long newDelay = Math.round(1000/fps);
delayField.setValue(newDelay);
updatingFPS = false;
}
}
});
GridBagConstraints gbc_fpsField = new GridBagConstraints();
gbc_fpsField.insets = new Insets(0, 0, 5, 0);
gbc_fpsField.fill = GridBagConstraints.HORIZONTAL;
gbc_fpsField.gridx = 1;
gbc_fpsField.gridy = 0;
monitorPreferencesPane.add(fpsField, gbc_fpsField);
fpsField.setColumns(10);
正如您所看到的,我没有在代码中设置值,并且在我有机会输入任何内容之前调用事件(并生成NullPointerException
)。我没有为{{1}编写监听器但是。
答案 0 :(得分:3)
由于默认值为null
,因此在打开JFrame
时触发的焦点事件将触发属性更改事件,因为无法充分比较null
。在可能的解决方案之后,请参阅下面的代码的完整说明。
摆脱NPE的一个解决方案是在添加fpsField
之前为您的PropertyChangeListener
设置默认值,因为这样做PropertyChange
时不会触发JFrame
事件打开。
JFormattedTextField fpsField = new JFormattedTextField(NumberFormat.getInstance());
fpsField.setValue(0);
如果您无法设置默认值,另一种解决方案是在更新delayField
之前检查事件中的旧值和新值是否实际不同。当null
打开时,它们都是JFrame
。
触发事件的原因是FocusEvent
触发原因为ACTIVATION
的{{1}}被JFormattedTextField
处理,并调用
/**
* Processes any focus events, such as
* <code>FocusEvent.FOCUS_GAINED</code> or
* <code>FocusEvent.FOCUS_LOST</code>.
*
* @param e the <code>FocusEvent</code>
* @see FocusEvent
*/
protected void processFocusEvent(FocusEvent e) {
super.processFocusEvent(e);
// ignore temporary focus event
if (e.isTemporary()) {
return;
}
if (isEdited() && e.getID() == FocusEvent.FOCUS_LOST) {
InputContext ic = getInputContext();
if (focusLostHandler == null) {
focusLostHandler = new FocusLostHandler();
}
// if there is a composed text, process it first
if ((ic != null) && composedTextExists) {
ic.endComposition();
EventQueue.invokeLater(focusLostHandler);
} else {
focusLostHandler.run();
}
}
else if (!isEdited()) {
// reformat
setValue(getValue(), true, true);
}
}
和
/**
* Does the setting of the value. If <code>createFormat</code> is true,
* this will also obtain a new <code>AbstractFormatter</code> from the
* current factory. The property change event will be fired if
* <code>firePC</code> is true.
*/
private void setValue(Object value, boolean createFormat, boolean firePC) {
由于firePC
为true
,它会触发PropertyChange
上的value
事件。
最后,由于默认值为null
,因此实际触发事件的条件
/**
* Support for reporting bound property changes for Object properties.
* This method can be called when a bound property has changed and it will
* send the appropriate PropertyChangeEvent to any registered
* PropertyChangeListeners.
*
* @param propertyName the property whose value has changed
* @param oldValue the property's previous value
* @param newValue the property's new value
*/
protected void firePropertyChange(String propertyName,
Object oldValue, Object newValue) {
PropertyChangeSupport changeSupport;
synchronized (getObjectLock()) {
changeSupport = this.changeSupport;
}
if (changeSupport == null ||
(oldValue != null && newValue != null && oldValue.equals(newValue))) {
return;
}
changeSupport.firePropertyChange(propertyName, oldValue, newValue);
}
会触发它,oldValue
和newValue
都是null
。