为什么在JFrame打开时此属性会更改事件?

时间:2013-12-09 16:10:35

标签: java swing jformattedtextfield propertychangelistener

我有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}编写监听器但是。

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) {

由于firePCtrue,它会触发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);
}

会触发它,oldValuenewValue都是null