【问题标题】:Customizing FocusTraversalPolicy for JFrame with GridBagLayout使用 GridBagLayout 为 JFrame 自定义 FocusTraversalPolicy
【发布时间】:2011-10-11 17:01:17
【问题描述】:

我有一个包含四个组件的 JFrame:三个 JPanel 和一个 JTabbedPane。两个面板具有可选组件,并且大致位于 BorderLayout.NORTH 和 EAST 中,而 JTabbedPane 大致位于 CENTER 中。 TabbedPane 的选项卡在窗格底部对齐。我说大概是因为实际布局是使用 GridBagLayout 完成的(对不起!)。

目前,焦点遍历循环是这样的:

Current Cycle:  
   1) North JPanel  
   2) East JPanel  
   3) JTabbedPane selected tab  
   4) JTabbedPane selected tab content  

但是,我希望它是:

Desired Cycle:  
   1) North JPanel  
   2) JTabbedPane selected tab content  
   3) JTabbedPane selected tab  
   4) East JPanel  

我尝试了Java Focus Guide 提供的基于矢量的 FocusTraversalPolicy,但没有成功:我无法让光标向下进入选项卡面板内容。

然后我研究了扩展/更改其他 FocusTraversalPolicy 类,但也无济于事。

我很确定问题是当前的 FocusTraversalPolicy 使用屏幕上的组件位置来确定布局周期。从技术上讲,侧面板在屏幕上高于中心选项卡式窗格。不过,我真的很想改变这一点。还有其他人遇到这个/有任何见解吗?谢谢!!

编辑:

这是一个带有正确布局代码的 SSCCE,演示了该问题。请注意:问题不在于布局,因为它必须保持不变。

package SO;

import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.JTextField;

public class ssccee7729709{
    JPanel north;
    JPanel north2;
    JPanel east;
    JTabbedPane center;
    JFrame content;

    void initialize() {
        north = new JPanel(new FlowLayout()) {
            {
                this.setBackground(Color.CYAN);
            }
        };
        north.add(new JLabel("Title panel"));

        north2 = new JPanel(new FlowLayout()) {
            {
                this.setBackground(Color.RED);
            }
        };
        north2.add(new JLabel("north2 Panel"));
        north2.add(new JTextField(4));
        north2.add(new JTextField(4));

        east = new JPanel(new GridLayout(3,1)) {
            {
                this.setBackground(Color.BLUE);
            }
        };
        east.add(new JButton("b1"));
        east.add(new JButton("b2"));

        center = new JTabbedPane(JTabbedPane.BOTTOM, JTabbedPane.WRAP_TAB_LAYOUT);
        for (int i = 0; i < 2; i++) {
            JPanel panel = new JPanel(new GridLayout(4,1));
            panel.add(new JLabel("Panel " + i));
            panel.add(new JTextField(6));
            panel.add(new JTextField(6));
            panel.add(new JTextField(6));
            center.addTab("Tab " + i, panel);   
        }

        content = new JFrame();
        content.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

        content.setLayout(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        {
            gbc.fill = GridBagConstraints.BOTH;
            gbc.gridwidth = 4;
            gbc.weightx = 1;
            content.add(north, gbc);
        }
        {
            gbc = new GridBagConstraints();
            gbc.fill = GridBagConstraints.BOTH;
            gbc.anchor = GridBagConstraints.PAGE_START;
            gbc.gridwidth = 1;
            gbc.weightx = 1;
            // gbc.weighty = .1;
            gbc.gridy = 1;
            gbc.gridx = 1;
            content.add(north2, gbc);
        }
        {
            gbc = new GridBagConstraints();
            gbc.fill = GridBagConstraints.BOTH;
            gbc.gridwidth = GridBagConstraints.RELATIVE;
            gbc.gridheight = GridBagConstraints.RELATIVE;
            gbc.weighty = 1;
            gbc.gridy = 2;
            content.add(center, gbc);
        }
        {
            gbc = new GridBagConstraints();
            gbc.fill = GridBagConstraints.VERTICAL;
            gbc.anchor = GridBagConstraints.SOUTHEAST;
            gbc.gridwidth = GridBagConstraints.REMAINDER;
            gbc.gridx = 3;
            gbc.gridheight = 4;
            content.add(east, gbc);
        }

      content.setVisible(true);
      content.pack();
    }

    public static void main(String args[]) {
        ssccee7729709 so = new ssccee7729709();
        so.initialize();
    }

}

【问题讨论】:

  • 这对于一个说明性的sscce来说是一个很大的问题。
  • 真的!我会在几分钟内回来...
  • 好的,搞定了。选项卡以更改组件。不幸的是使用了我忘记的 GridBagLayout...
  • 如果我错了,请纠正我,但问题本质上是它如何处理焦点遍历到选项卡与选项卡内容的方式之一——对吗?对我来说,程序焦点首先进入选项卡然后进入其内容对我来说似乎更自然,不是吗?
  • 是和不是。是的,因为这是问题的一部分(你是对的,如果选项卡在顶部,那将是最自然的)。但我也希望它转到 East JPanel 之前的 Tabs,这是更大的问题。

标签: java swing focus custom-controls


【解决方案1】:

如果您查看默认策略 LayoutFocusTraversalPolicy 的源代码,它几乎只是扩展了 SortingFocusTraversalPolicy,它采用了 Comparator&lt;? extends Component&gt;

您应该能够提供自己的 Comparator,它是一个内部类,因此可以访问父组件,并通过查看它们自己和它们的父组件来提供适当的比较值。

查看LayoutComparator 的来源可能不会有什么坏处,这是 LayoutFocusTraveralPolicy 使用的。

【讨论】:

  • 好建议! LayoutComparator 是非公开的,所以我不得不克隆它。 LayoutFocusTraversalPolicy 不允许你指定一个比较器,它是最终的,所以我也必须克隆它。但是,我已经能够让我的 Comparator 以垂直方式处理组件。正确的 JPanel 行为,但内部组件非常非常错误......还有更多工作要做,但谢谢!
  • 好的!我必须添加几行代码(我将在新答案中详细说明),但这是正确的方法。非常感谢!
【解决方案2】:

克隆 LayoutComparator 后,我必须在 compare 方法中添加以下行:

    ...previous code...
    int zOrder = a.getParent().getComponentZOrder(a) - b.getParent().getComponentZOrder(b);

    /// added these:
    if (a instanceof EastPanel) {
        if (b instanceof JTabbedPane || b instanceof NorthPanel) {
            return -1;
        }
    }
    if (b instanceof EastPanel) {
        if (a instanceof JTabbedPane || a instanceof NorthPanel) {
            return 1;
        }
    }

    if (horizontal) {
        if (leftToRight) {
    ...more code...

老实说,我不知道这是如何工作的...使用compare 订购组件的机制对我来说很奇怪...但这有效,所以...万岁魔术!

【讨论】:

    猜你喜欢
    • 2014-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-09
    • 1970-01-01
    相关资源
    最近更新 更多