Swing:将键盘焦点遍历限制为特定小部件

时间:2012-04-03 20:48:20

标签: java swing

我有一个包含常用的面板和小部件的JFrame,我有一个JPanel,我正在使用它作为JFrame的glassPane。我希望能够将键盘焦点遍历限制在glassPane中的组件可见时。

我的问题可能会或可能不会因为后台线程启动一个进程导致进程对话框出现并随后消失这一事实而复杂化,这会从我的glassPane中的窗口小部件中窃取焦点但将其返回到我的下面的某个窗口小部件的glassPane。

我已经尝试将JFrame的焦点遍历策略设置为仅允许glassPane聚焦的一个,但这似乎没有任何效果。 (也许我做错了?)

任何帮助都将不胜感激。

5 个答案:

答案 0 :(得分:3)

我打算将我的评论作为答案,因为我相信这是你问题的解决方案:

也许更好的选择是使用CardLayout来简单地交换视图而不是玻璃窗格或对话框,因为这种情况似乎不适合玻璃窗格使用。如果你使用CardLayout,你不必提出一个kludge(小提示焦点遍历),以修复另一个kludge的副作用(使用玻璃窗格,它不打算用于它的东西)。

如果您不熟悉它,CardLayout将允许您轻松交换GUI中的组件,并且通常用于交换具有复杂GUI的JPanel,这些GUI在用户从一个主要程序状态转到另一个主程序状态时发生。我认为这对您的目的来说是完美的,并且会阻止您担心您的焦点问题。

答案 1 :(得分:3)

正如我在评论中所提到的,我可能会选择J / X / Layer - 但如果确实是自定义FTP是您上下文中唯一缺少的部分,那么这是一个解决方案。

要从焦点遍历中排除组件,请在自定义FTP的accept方法中拒绝它们。下面是一个例子,如果glassPane是可见的,它拒绝所有不是glassPane的子组件的组件(注意:这过于简单,因为它只处理直接子项,现实世界的代码必须沿着父链向上走,直到它击中玻璃板还是没有)

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();
    }

}

答案 2 :(得分:2)

在glassPane可见的情况下,尝试在您要忽略的JFrame上调用.setFocusable(false)(或者最坏的情况下,调用其中的所有组件)。

答案 3 :(得分:0)

当我与客户讨论时,他给了我相同的要求。所以我决定在我的项目中使用JLayer和LayeredPane,并将所有这些组件作为我在代码中实现的简单解决方案,可能会对您的项目有所帮助。

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();
    }
}

答案 4 :(得分:0)

以kleopatra的答案为基础并在类似情况下帮助他人;我有一堆我不想聚焦的自定义秋千组件(有时仅在它们不可编辑时)。我结束了:

/**
 * A custom focus traversal policy to make focus traversal inside a container to ignore some swing components.<br /><br />
 * 
 * <b>Ignored components:</b><br />
 * - <code>CustomComponent1</code> components<br />
 * - <code>CustomComponent2</code> components that are not editable<br /><br />
 * 
 * <b>Usage:</b><br /><br />
 * <code>Container.setFocusTraversalPolicy(new CustomFocusTraversalPolicy());</code>
 */
public class CustomFocusTraversalPolicy extends LayoutFocusTraversalPolicy {

    private static final long serialVersionUID = 1L;

    protected boolean accept(Component c) {

        if(c instanceof CustomComponent1) {
            return false;
        }

        if(c instanceof CustomComponent2) {

            CustomComponent2 t = (CustomComponent2) c;

            if(!t.isEditable()) {
                return false;
            }
        }

        return super.accept(c);
    }

}

请注意,需要为每个Container设置策略(我为创建的每个Window都设置了策略):

Window window = new JFrame(); // Or JDialog; both subclasses of Container and Window
window.setFocusTraversalPolicy(new CustomFocusTraversalPolicy());