开发者

Customizing FocusTraversalPolicy for JFrame with GridBagLayout

I have a JFrame with four components: three JPanels and a JTabbedPane. Two panels have selectable components and are located approximately in BorderLayout.NORTH and EAST, while the JTabbedPane sits approximately in CENTER. The tabs of the TabbedPane are aligned on the bottom of the pane. I say approximately because the actual lay开发者_C百科out is done with a GridBagLayout (sorry!).

Currently, the focus traversal cycle goes like this:

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

However, I'd like it to be:

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

I have tried the Vector-based FocusTraversalPolicy given by the Java Focus Guide with no luck: I couldn't get the cursor to go down into the tab panel contents.

I then looked into extending/changing the other FocusTraversalPolicy classes out there, but got nowhere with that either.

I'm fairly sure the issue is the current FocusTraversalPolicy uses component location on screen to determine the layout cycle. Technically the side panel is higher on the screen than the center tabbed pane. I'd really like to change this though. Anybody else run into this/have any insight? Thanks!!

EDIT:

Here's an SSCCE with proper layout code demonstrating the problem. Just a note: the issue is NOT the layout, as that has to stay the same.

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

}


If you look at the source for LayoutFocusTraversalPolicy, which is the default policy, it pretty much just extends SortingFocusTraversalPolicy, which takes a Comparator<? extends Component>.

You should be able to provide your own Comparator which is an inner class and so has access to parent components, and provide appropriate comparison values by looking at themselves and their parents.

It probably wouldn't hurt to check out the source to LayoutComparator which is what LayoutFocusTraveralPolicy uses.


After cloning LayoutComparator, I had to add the following lines to the compare method:

    ...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...

Honestly I don't know how this works...the mechanism of using compare to order components is strange to me...but this works, so... hooray magic!

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜