2011-10-11 61 views
2

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

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

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

} 
+1

对于说明性[sscce](http://sscce.org)这是一个很大的问题。 –

+0

够正确!我会在几分钟后回来...... – BenCole

+0

好的,得到了​​一个sscce了。选项卡更改组件。不幸的是使用GridBagLayout,我忘了... – BenCole

回答

3

如果你看看源LayoutFocusTraversalPolicy,这是默认的策略,它非常简单,只是延伸SortingFocusTraversalPolicy,这需要一个Comparator<? extends Component>

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

它可能不会伤害检查源是LayoutComparator这是什么LayoutFocusTraveralPolicy使用。

+1

伟大的建议! LayoutComparator是非公开的,所以我不得不克隆它。LayoutFocusTraversalPolicy不允许你指定一个比较器,它是最终的,所以我不得不克隆它。但是,我已经能够让我的比较器以垂直方式处理组件。正确的JPanel行为,但对内部组件非常非常错误...需要做更多工作,但是谢谢! – BenCole

+0

好吧!我不得不添加几行代码(我会在一个新的答案中详细说明),但这是正确的路要走。感谢一堆! – BenCole

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订购组件的机制是怪我......但这个工作,所以......万岁的魔法!