I have a JFrame containing the usual assortment of panels and widgets, and I have a JPanel which I'm using as that JFrame's glassPane. I'd like to be able to restrict keyboard focus traversal to the components in the glassPane when it's visible.
My problem may or may not be compounded by the fact that a background thread launches a process which results in a progress dialog appearing and subsequently disappearing, which steals the focus from a widget in my glassPane but returns it to some widget beneath my glassPane.
I've tried setting the JFrame's focus traversal policy to one which only allows the glassPane to be focused, but that didn't seem to have any effect. (maybe I did it incorrectly?)
Any help would be appreciated.
As mentioned in my comment, I would probably go for a J/X/Layer - but here's a solution if indeed a custom FTP is the only missing piece in your context.
To exclude components from focus traversal, reject them in the accept method of a custom FTP. Below is an example which rejects all components which are not children of the glassPane if the glassPane is visible (note: this is overly simplistic, as it handles direct children only, real-world code must walk up the parent chain until it either hit the glasspane or not)
public static class FTP extends LayoutFocusTraversalPolicy {
@Override
protected boolean accept(Component comp) {
JFrame window = (JFrame) SwingUtilities.windowForComponent(comp);
if (hasVisibleGlassPane(window)) {
return comp.getParent() == window.getGlassPane();
}
return super.accept(comp);
}
private boolean hasVisibleGlassPane(JFrame window) {
return window != null && window.getGlassPane() != null
&& window.getGlassPane().isVisible();
}
}
I'm going to make my comment an answer as I believe that it is the solution to your problem:
Perhaps a better option is to use a CardLayout to simply swap views rather than a glass pane or dialog since this situation does not seem the best suited for glass pane use. If you use CardLayout, you don't have to come up with a kludge (fiddle with focus traversal), to fix the side effects of another kludge (using glass pane for things it wasn't intended to be used for).
If you're not familiar with it, a CardLayout will allow you to easily swap components in a GUI, and is often used to swap JPanels that hold complex GUI's that occurs when the user goes from one major program state to another. I think that it would be perfect for your purposes and would prevent you from having to worry about your focus issue.
Try calling .setFocusable(false)
on the JFrame you want to ignore (or at worst, on all the components within it) while the glassPane is visible.
When I had discussion with client he gave me the same requirement. So I decided to use the JLayer and LayeredPane in my project and with all of these components as a simple solution I implemented following code, may be it will help you in your project.
public YourConstructor() {
yes.addFocusListener(new FocusAdapter() {
public void focusLost(FocusEvent fe) {
if (!no.hasFocus()) {
no.requestFocusInWindow();
}
}
});
no.addFocusListener(new FocusAdapter() {
public void focusLost(FocusEvent fe) {
if (!yes.hasFocus()) {
yes.requestFocusInWindow();
}
}
});
}
@Override
public void setVisible(boolean visibility) {
super.setVisible(visibility);
if (visibility) {
yes.requestFocusInWindow();
}
}