JavaSwingLookAndFeel: JRootPane and default buttons


JRootPane and default buttons

JRootPane supports the notion of a default button (JButton) that can be "clicked" by special keys no matter which component (JComponent?) has focus.

JButton has a property "defaultCapable". If it is true, it can become default button (see problems below).

Applications can suggest a "default" default button; whether and how it changes automatically by user interaction is governed by the UI delegates.

Unfortunately some implementation details effectively rule out many ways a UI can behave.

Possible strategies for a LAF

  1. don't change the default button at all (Metal)

  2. always set the default button to the last focused default capable JButton (older Basic/Motif/Windows, 1.4.1 Basic/Motif/Window)

  3. always set the default button to the currently focused default capable JButton, if there is one, otherwise return it to the original default button (newer Basic/Motif/Windows)

Furthermore,

Property and strategy problems

Different problems

Use of default buttons in the standard classes

(This hasn't changed at all since 1.1.1)

JColorChooser: ColorChooserDialog sets OK button as default button

BasicOptionPaneUI: initial focus component was set as default button (once added), even if not default capable (also twice to make sure?)

Suggestions

Application

LAF

Implementation

1.1.1 / 1.2

JRootPane handles keys; they are (un-)registered depending on != null in setDefaultButton().

BasicButtonListener (also used for Windows): strategy 2 without 'null' exception

MetalButtonListener: strategy 1

MotifButtonListener: strategy 2 with 'null' doing nothing

1.3

Keyboard code has moved into new (Basic)RootPaneUI.

JButton unregisters itself in removeNotify if it still is the defaultButton. JButton could not remain the defaultButton although not in the container hierarchy anymore (the root pane's reference to it could also cause a memory leak), so this had to be changed somehow (#4134035); but this way seems to be a little short-sighted (see above).

1.4beta1+2+3

An effort was made to implement strategy 3 with 'null-does-nothing' (except in Metal, which never changed defaultButton anyway; but parts of this strategy still are executed in MetalLAF) so that the default button would follow the focus to defaultCapable buttons, but return to the explicitly set button when another component is focused. (This is an incompatible change to BasicButtonListener. Custom UIs that used it will suddenly behave differently.)

Unfortunately, it isn't done properly (yet). Details:

BasicButtonListener: only sets (a default capable) JButton as default button in focusGained if there already is one (changed to what

MotifButtonListener always did). During this call sets the root pane's client property "temporaryDefaultButton" (so the RootPaneUI knows the origin of the property change was the LAF and not the application).

Whenever an AbstractButton (!) loses focus, sets the defaultButton the client property "initialDefaultButton" (which BasicRootPaneUI has hopefully installed; but it has not done this if the defaultButton was set before the UI was installed, so it will be restored to null and then disable defaultButtons completely).

MetalButtonListener: doesn't do anything is focusGained, but the rest of the code still is there (focusLost resets to initialValue, which may be 'null').

BasicRootPane: if "temporaryDefaultButton" is not sent when the PropertyChangeEvent is received, sets "initialDefaultButton".

Problems:

This UI strategy still needs working out many details and cases. It doesn't work smoothly the way it is now (beta 2+3 didn't change anything).

Maybe JRootPane itself should be extended if support for such temporary defaultButton transfer is desired (and that seems to be the case).

At least automatic transfer should be explicitly disabled and not just taken for granted if there happens to be no defaultButton at the moment. That would also allow the application to disable LAF-specific automatic transfer and still have a (fixed) default button (but then it could just set all other buttons to not defaultCapable).

Interesting bug reports and evaluations: (#4384407)(#4146858)(#4164757)


(C) 2001-2009 Christian Kaufhold (swing@chka.de)