为什么编辑节点后 JTree 会短暂失去焦点?

发布于 2024-10-18 01:31:22 字数 1469 浏览 4 评论 0原文

尝试:F2开始编辑并ENTER停止编辑,焦点切换到下一个组件并在几毫秒内返回到树节点。在示例中,您可以看到 focusPainted 矩形在 JTabbedPane-Header 中闪烁。使用 FocusListener 应该会更清晰。

为什么编辑节点后 JTree 会短暂失去焦点?

如何防止这种行为?

public class Focus {

private static void createAndShowGUI() {
    final JTextArea text = new JTextArea("Tab Header gained focus");

    JTree tree = new JTree();
    tree.setEditable( true );
    int row = 0;
    while( row < tree.getRowCount() ) {
        tree.expandRow( row++ );
    }

    JTabbedPane tabp = new JTabbedPane();
    tabp.addTab( "Lorem", text );
    tabp.addFocusListener( new FocusListener() {
        @Override
        public void focusLost( FocusEvent e ) { }
        @Override
        public void focusGained( FocusEvent e ) {
            text.setText( text.getText() +"\nWoohoo, I got the focus!" );
        }
    });

    JFrame frame = new JFrame( "Focus" );
    frame.setLayout( new BorderLayout() );
    frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    frame.getContentPane().add(tree, BorderLayout.WEST);
    frame.getContentPane().add(tabp, BorderLayout.CENTER);
    frame.pack();
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);

    tree.startEditingAtPath( tree.getPathForRow( 0 ) );

}
public static void main(String[] x) {
    EventQueue.invokeLater(new Runnable() {
        @Override public void run() {
            createAndShowGUI();
        }
    });
}
}

try: F2 start editing and ENTER stop editing and the focus switches to the next Component and goes back to the Tree-Node in milliseconds. In the example you can see the focusPainted rectangle flashing in the JTabbedPane-Header. With a FocusListener it shall be clearer.

Why I lose the focus for a short Time from JTree after editing a Node?

How to prevent this behavior?

public class Focus {

private static void createAndShowGUI() {
    final JTextArea text = new JTextArea("Tab Header gained focus");

    JTree tree = new JTree();
    tree.setEditable( true );
    int row = 0;
    while( row < tree.getRowCount() ) {
        tree.expandRow( row++ );
    }

    JTabbedPane tabp = new JTabbedPane();
    tabp.addTab( "Lorem", text );
    tabp.addFocusListener( new FocusListener() {
        @Override
        public void focusLost( FocusEvent e ) { }
        @Override
        public void focusGained( FocusEvent e ) {
            text.setText( text.getText() +"\nWoohoo, I got the focus!" );
        }
    });

    JFrame frame = new JFrame( "Focus" );
    frame.setLayout( new BorderLayout() );
    frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    frame.getContentPane().add(tree, BorderLayout.WEST);
    frame.getContentPane().add(tabp, BorderLayout.CENTER);
    frame.pack();
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);

    tree.startEditingAtPath( tree.getPathForRow( 0 ) );

}
public static void main(String[] x) {
    EventQueue.invokeLater(new Runnable() {
        @Override public void run() {
            createAndShowGUI();
        }
    });
}
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

一个人练习一个人 2024-10-25 01:31:22

当编辑开始时,树将 DefaultCellEditor 添加到 JTree 层次结构中。该文本字段获得焦点。当编辑停止时(按下 Enter 键),BasicTreeUI.completeEditing() 方法检查树本身或编辑器组件是否是焦点所有者。在这种情况下,编辑完成后树将再次获得焦点。

在停止算法中,编辑器被从树中删除。之前是焦点拥有者,因此焦点会转移到下一个可聚焦组件(焦点循环)。在您的 UI 中,这将是选项卡式窗格。

由于编辑器之前已获得焦点,BasicTreeUI 请求树的焦点。

这些步骤完全符合您所描述的行为。

唯一的解决方案(不完整,但显示了方向)是设置您自己的 FocusTraversalPolicy:

private static class TreeEditorFocusTraversalPolicy extends DefaultFocusTraversalPolicy {
    private final JTree tree;
    public TreeEditorFocusTraversalPolicy(JTree tree) {
        this.tree = tree;
    }

    @Override
    public Component getComponentAfter(Container aContainer, Component aComponent) {
        if (aComponent instanceof CellEditor) {
            return tree;
        }
        return super.getComponentAfter(aContainer, aComponent); 
    }
}

将此实例设置为您的树:

tree.setFocusTraversalPolicy(new TreeEditorFocusTraversalPolicy(tree));
tree.setFocusCycleRoot(true);

到目前为止的问题:焦点遍历(Tab、Shift+Tab)不再起作用。 FocusTraversalPolicy 是 Swing 的重要组成部分,需要一些时间来创建工作策略。也许看看 LegacyGlueFocusTraversalPolicy 这是默认策略。

希望这有助于走得更远。

The tree adds a DefaultCellEditor to the JTree hierarchy when editing starts. This textfield gains the focus. When editing stopped (Enter pressed), the BasicTreeUI.completeEditing() method checks whether the tree itself or the editor component is the focus owner. In that case, the tree will be focused again after the editing is finished.

In the stop algorithm, the editor is removed from the tree. It was the focus owner before, so the focus will be transfered to the next focusable component (focus cycle). In your UI this will be the tabbed pane.

Due to the fact that the editor was focused before, the BasicTreeUI requests the focus for the tree.

These steps map perfectly on your described behaviour.

The only solution (not complete, but shows the direction) is to set your own FocusTraversalPolicy:

private static class TreeEditorFocusTraversalPolicy extends DefaultFocusTraversalPolicy {
    private final JTree tree;
    public TreeEditorFocusTraversalPolicy(JTree tree) {
        this.tree = tree;
    }

    @Override
    public Component getComponentAfter(Container aContainer, Component aComponent) {
        if (aComponent instanceof CellEditor) {
            return tree;
        }
        return super.getComponentAfter(aContainer, aComponent); 
    }
}

Set this instance to your tree:

tree.setFocusTraversalPolicy(new TreeEditorFocusTraversalPolicy(tree));
tree.setFocusCycleRoot(true);

The problem so far: the focus traversal (Tab, Shift+Tab) does not work anymore. The FocusTraversalPolicy is a huge part of Swing and needs some time to create a working policy. Maybe have a look at the LegacyGlueFocusTraversalPolicy which is the default policy.

Hope this helps to get further.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文