Since the default value is null
, the focus event fired when opening the JFrame
will fire a property change event because null
can not be adequately compared. See the full explanation with code below after the possible solutions.
One solution to get rid of the NPE is to set a default value to your fpsField
before adding the PropertyChangeListener
since doing that will not fire the PropertyChange
event when the JFrame
opens.
JFormattedTextField fpsField = new JFormattedTextField(NumberFormat.getInstance());
fpsField.setValue(0);
Another solution, if you can't set the default value, is to check if the old and new values in the event are actually different before updating your delayField
. They are both null
when the JFrame
opens.
The reason the event is fired is because a FocusEvent
, where the cause is ACTIVATION
is fired and processed by your JFormattedTextField
, which calls
/**
* 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);
}
}
and
/**
* 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) {
since firePC
is true
, it fires the PropertyChange
event on value
.
Finally, since the default value is null
, the condition to actually fire the event
/**
* 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);
}
will fire it, oldValue
and newValue
being both null
.