This section describes the following troubleshooting issues related to focus events.
To troubleshoot a problem with focus, you can trace focus events. You can do it by adding a focus listener to the toolkit, as shown in Example 10-5.
Example 10-5 Trace Focus Events
Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener( public void eventDispatched(AWTEvent e) { System.err.println(e); } ), FocusEvent.FOCUS_EVENT_MASK | WindowEvent.WINDOW_FOCUS_EVENT_MASK | WindowEvent.WINDOW_EVENT_MASK);
The System.err
stream is used here because it does not buffer the output.
Remember that the correct order of focus events is the following:
FOCUS_LOST
on component losing focus
WINDOW_LOST_FOCUS
on top-level losing focus
WINDOW_DEACTIVATED
on top-level losing activation
WINDOW_ACTIVATED
on top-level becoming active widow
WINDOW_GAINED_FOCUS
on top-level becoming focused window
FOCUS_GAINED
on component gaining focus
When focus is transferred between components inside the focused window, only FOCUS_LOST
and FOCUS_GAINED
events should be generated. When focus is transferred between owned windows of the same owner or between an owned window and its owner, then the following events should be generated:
FOCUS_LOST
WINDOW_LOST_FOCUS
WINDOW_GAINED_FOCUS
FOCUS_GAINED
Note: The events losing focus or activation should come first.
Sometimes a problem may be caused by the native platform. To check this, investigate the native events that are related to focus. Make sure that the window you want to be focused gets activated and the component you want to focus receives the native focus event.
On the Windows platform, the native focus events are the following:
WM_ACTIVATE
for a top-level. WPARAM
is WA_ACTIVE
when activating and WA_INACTIVE
when deactivating.
WM_SETFOCUS
and WM_KILLFOCUS
for a component.
On the Windows platform, a concept of synthetic focus has been implemented. It means that a focus owner component only emulates its focusable state whereas real native focus is set to a focus proxy component. This component receives key and input method native messages and dispatches them to a focus owner. Prior to JDK7 a focus proxy component was a dedicated hidden child component inside a frame/dialog. In the latest JDK releases a frame/dialog itself serves as a focus proxy. Now it proxies focus not only for components in an owned window but for all child components as well. A simple window never receives native focus and relies on focus proxy of its owner. This mechanism is transparent for a user but should be taken into account when debugging.
On Oracle Solaris and Linux operating systems, XToolkit uses a focus model that allows AWT to manage focus itself. With this model the window manager does not directly set input focus on a top-level window, but instead it sends only the WM_TAKE_FOCUS
client message to indicate that focus should be set. AWT then explicitly sets focus on the top-level window if it is allowed.
Note: The X server and some window managers may nevertheless send focus events to a window. However all such events are discarded by AWT.
AWT does not generate the hierarchical chains of focus events when a component inside a top-level gains focus. Moreover, the native window mapped to the component itself does not get any native focus event. On the Oracle Solaris and Linux platforms, as well as on the Windows platform, AWT uses the focus proxy mechanism. Therefore, focus on the component is set by synthesizing a focus event, whereas the invisible focus proxy has native focus.
A native window that is mapped to a Window
object (not a Frame
or Dialog
object) has the override-redirect
flag set. Thus the window manager does not notify the window about focus change. Focus is requested on the window only in response to a mouse click. This window will not receive native focus events at all. Therefore, you can trace only FocusIn
or FocusOut
events on a frame or dialog. Since the major processing of focus occurs at the Java level, debugging focus with XToolkit is simpler than with WToolkit.
An applet is embedded in a browser as a child (though not a direct child) of an EmbeddedFrame
. This is a special Frame
that has the ability to communicate with the plugin. From the applet's perspective the EmbeddedFrame
is a full top-level Frame
.
Managing focus for an EmbeddedFrame
requires special additional actions. When an applet first starts, the EmbeddedFrame
does not get activated by default by the native system. The activation is performed by the plugin that triggers a special API provided by the EmbeddedFrame
. When focus leaves the applet, the EmbeddedFrame
is also deactivated in a synthesized manner.
The following focus models are supported by X window managers:
click-to-focus is a commonly used focus model. (For example, Microsoft Windows uses this model.)
focus-follows-mouse is a focus model in which focus goes to the window that the mouse hovers over.
The focus-follows-mouse model is not detected in XAWT in Java SE 7, and this causes problems for simple windows (objects of java.awt.Window
class). Such windows have the override-redirect
property, which means that they can be focused only when the mouse button is pressed, and not by hovering over the window. As a workaround, set MouseListener
on the window and request focus on it when mouse crosses the window borders.
This section describes some issues related to focus in AWT that can occur and suggests solutions.
Issue 1 - Linux + KDE, XToolkit cannot be switched between two frames when a frame's title is clicked.
Clicking a component inside a frame causes focus to change.
Solution: Check the version of your window manager and upgrade it to 3.0 or greater.
Issue 2 - You want to manage focus using KeyListener
to transfer focus in response to Tab/Shift+Tab, but not key event appear.
Solution: To catch traversal key events, you must enable them by calling Component.setFocusTraversalKeysEnabled(true)
.
Issue 3 - A window is set modal excluded with Window.setModalExclusionType(ModalExclusionType)
.
The frame, its owner, is modal blocked. In this case the window will also remain modal blocked.
Solution: A window cannot become the focused window when its owner is not allowed to get focus. The solution is to exclude the owner from modality.
Issue 4 - On Windows a component requests focus and is concurrently removed from its container.
Sometimes java.lang.NullPointerException: null pData
is thrown.
Solution: The easiest way to avoid throwing the exception is to do the removal along with requesting focus on EDT. Another, more complicated, approach is to synchronize requesting focus and removal if you need to perform these actions on different threads.
Issue 5 - When focus is requested on a component and the focus owner is immediately removed, focus goes to the component after the removed component.
For example, Component A is the focus owner. Focus is requested on Component B, and immediately after this Component A is removed from its container. Eventually focus goes to Component C, which is located after Component A in the container, but not to Component B.
Solution: In this case, ensure that the requesting focus is executed after Component A is removed, not before.
Issue 6 - On Windows, when a window is set alwaysOnTop
in an inactive frame, the window cannot receive key events.
For example, a frame is displayed, with a window that it owns. The frame is inactive, so the window is not focused. Then the window is set to alwaysOnTop
. The window gains focus, but its owner remains inactive. Therefore, the window cannot receive key events.
Solution: Bring the frame to front (the Frame.toFront()
method) before setting the window to alwaysOnTop
.
Issue 7 - When a splash screen is shown and a frame is shown after the splash screen window closes, the frame does not get activated.
Solution: Bring the frame to front (the Frame.toFront()
method) after showing it (the Frame.setVisible(true)
method).
Issue 8 - The WindowFocusListener.windowGainedFocus(WindowEvent)
method does not return the frame's most recent focus owner.
For example, a frame is the focused window, and one of its components is the focus owner. Another window is clicked, and then the frame is clicked again. WINDOW_GAINED_FOCUS
comes to the frame and the WindowFocusListener.windowGainedFocus(WindowEvent)
method is called. However, inside of this callback you cannot determine the frame's most recent focus owner, because Frame.getMostRecentFocusOwner()
returns null
.
Solution: You can get the frame's most recent focus owner inside the WindowListener.windowActivated(WindowEvent)
callback. However, by this time the frame will have become the focused window only if it does not have owned windows.
Note: This approach does not work for the window, only for the frame or dialog. |
Issue 9 - An Applet Steals focus when it starts.
Solution: This behavior is the default with JDK. However you might need to prevent the applet from getting focus on startup, for example, if your applet is invisible and does not require focus at all. In this case, you can set the special parameter initial_focus
to false
in the HTML tag, as shown in Example 10-6.
Issue 10 - A window is disabled with Component.setEnabled(false)
, but does not get totally unfocusable.
Solution: Do not assume that the condition set by calling Component.setEnabled(false)
or Component.setFocusable(false)
will be maintained unfocusable along with all its content. Instead, use the Window.setFocusableWindowState(boolean)
method.