3

I have an application that has multiple panels; I would like to have the freedom to use different layout managers for the different panels, but would like them to behave similarly as the window is resized by the user.

    package example;

    import java.awt.GridBagConstraints;
    import java.awt.GridBagLayout;

    import javax.swing.BoxLayout;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.JTabbedPane;
    import javax.swing.JTextField;

    public class TP1 extends JFrame
    {
        public static void main(String[] args)
        {
            TP1 tp1 = new TP1();
            tp1.go();
        }

        public void go()
        {
            setDefaultCloseOperation(EXIT_ON_CLOSE);

            // create a panel with some labels on it
            JPanel innerFirst = new JPanel();
            innerFirst.setLayout(new BoxLayout(innerFirst, BoxLayout.PAGE_AXIS));
            innerFirst.add(new JLabel("one"));
            innerFirst.add(new JLabel("two"));
            innerFirst.add(new JLabel("three"));
            innerFirst.add(new JLabel("four"));

            // put that panel in a scroll pane
            JScrollPane firstSP = new JScrollPane(innerFirst);

            // make another panel and put our scrolled panel in it
            JPanel outerFirst = new JPanel(); 
            outerFirst.setLayout(new BoxLayout(outerFirst, BoxLayout.PAGE_AXIS));
            outerFirst.add(firstSP); 

            // create a GridBagLayout panel with some text fields on it
            JPanel innerSecond = new JPanel(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridx = 0;
            gbc.gridy = 0;
            gbc.weightx = .25;
            gbc.anchor = GridBagConstraints.LINE_START;
            innerSecond.add(new JTextField(8), gbc);
            gbc.gridx = 0;
            gbc.gridy = 1;
            innerSecond.add(new JTextField(10), gbc);
            gbc.gridx =0;
            gbc.gridy = 2;
            innerSecond.add(new JTextField(12), gbc);

            // put that panel in a scroll pane
            JScrollPane secondSP = new JScrollPane(innerSecond);

            // make another panel and put our second scrolled panel in it
            JPanel outerSecond = new JPanel(); 
            outerSecond.setLayout(new BoxLayout(outerSecond, BoxLayout.LINE_AXIS));
            outerSecond.add(secondSP); 

            JPanel innerThird = new JPanel(new GridBagLayout());
            GridBagConstraints gbc3 = new GridBagConstraints();
            gbc3.anchor = GridBagConstraints.LINE_END;
            gbc.weightx = .25;
            gbc3.gridx = 0;
            gbc3.gridy = 0;
            innerThird.add(new JLabel("1st label"), gbc3);
            gbc3.gridy = 1;
            innerThird.add(new JLabel("second label"), gbc3);
            gbc3.gridy = 2;
            innerThird.add(new JLabel("IIIrd label"), gbc3);

            gbc3.anchor = GridBagConstraints.LINE_START;
            gbc3.gridx = 1;
            gbc3.gridy = 0;
            innerThird.add(new JTextField(8), gbc3);
            gbc3.gridy = 1;
            innerThird.add(new JTextField(12), gbc3);
            gbc3.gridy = 2;
            innerThird.add(new JTextField(14), gbc3);

            JScrollPane thirdSP = new JScrollPane(innerThird);
            JPanel outerThird = new JPanel();
            outerThird.setLayout(new BoxLayout(outerThird, BoxLayout.LINE_AXIS));
            outerThird.add(thirdSP);

            // put the scrolled panes onto a tabbed pane
            JTabbedPane tp = new JTabbedPane();
            tp.add("text fields", outerSecond);
            tp.add("labels", outerFirst);
            tp.add("mixed", outerThird);

            // add the tabbed pane to the frame
            this.add(tp);

            // pack it and ship it.
            pack();
            setVisible(true);
        }
    }

Running the above code, we get a window with a tabbed pane in it with three tabs. If we make the window smaller, all of them get scroll bars, as intended. If we make it larger, the three behave differently: the tab with labels only leaves them at the top left of the window, the tab with fields only centers them vertically on the left edge, and the one with the gridbag of mixed labels and fields centers them both horizontally and vertically in the enlarged window.

This is not acceptable for the application; I need to somehow make all the panels behave similarly in this way. I need them all to have scroll bars, and I would like them all to keep to the upper left if the window is made larger than the internal panel.

One other requirement: my tabs are occupied by something that extends JPanel, I've been told before I can put JScrollPane directly into the tab, but for my application I don't want to do that either. It just makes other things more complicated than they need to be.

In addition to wanting all the extra space to be put at the bottom and the right, I would dearly love to understand WHY these three situations behave differently. I still believe that we would all be better off if we understood the principles behind what we're doing, instead of just copying examples right and left and doing things by trial and error until they work.

(Incidentally, I have a GroupLayout panel that does seem to gravitate to the upper left, but didn't think it was necessary for my question and this is 100 lines of code as it is.)

mKorbel
  • 109,525
  • 20
  • 134
  • 319
arcy
  • 12,845
  • 12
  • 58
  • 103

2 Answers2

2

I still believe that we would all be better off if we understood the principles behind what we're doing,

See A Visual Guide to Layout Managers for working examples and explanations of the various layout managers. You need to learn how the various constraints are used for a particular layout manager.

camickr
  • 321,443
  • 19
  • 166
  • 288
  • I have read Visual Guide, and most other parts of the Oracle/Sun/Java Swing tutorials. It's a good introduction. And I agree I need to learn how the various constraints are used, that's what I'm trying to do. I haven't found anything that covers this. There are rules somewhere that say "in this situation we center vertically and left-justify, and in this we left- and top-justify, and in this we center vertically and horizontally. I've got one of each, and I want to know what rules put those things there. – arcy Feb 09 '12 at 13:25
  • The tutorial explains it. A FlowLayout aligns compnents in a row. They can be left/center/right aligned depending on the alignment property of the layout manager. For a BoxLayout the same thing you can horizontally/veritically layout components. Then within the vertical layout the components can be horizontally aligned left/center/right depending on the alignementX value of the component. With the GridBagLayout the components clump together in the center unless you speicify a weightX value for one of the components. Work and understand one layout manager at a time. – camickr Feb 09 '12 at 16:50
2

Seems like in order to understand why is this happening in your code, you need to understand certain terms. For example, PAGE_AXIS, LINE_AXIS, LINE_END, LINE_START and so on. Since you are providing them as constraints, these are the things that describe the orientation of the components being added to the container and their starting point, like as you writing :

innerFirst.setLayout(new BoxLayout(innerFirst, BoxLayout.PAGE_AXIS));

Here you telling your BoxLayout to start adding components from the point which refers to the start of the page. (When you start your Notepad, your cursor is placed at the PAGE_AXIS on the new document). But when you are writing this :

JPanel innerSecond = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.weightx = .25;
gbc.anchor = GridBagConstraints.LINE_START;

Here the term anchor is used when the component is smaller than its display area. It determines where, within the display area, to place the component. But here since you mentioned that it has the value LINE_START which means :

Place the component centered along the edge of its display area where lines of text 
would normally begin for the current ComponentOrientation. Equal to WEST for horizontal,
left-to-right orientations and EAST for horizontal, right-to-left orientations.

That's why the three JTextFields you created, you see them at the center on the left side.

mKorbel
  • 109,525
  • 20
  • 134
  • 319
nIcE cOw
  • 24,468
  • 7
  • 50
  • 143
  • I probably should have posted a different version -- I've tried using LINE_START and FIRST_LINE_START in that place, and it does not change the position of the labels. FIRST_LINE_START is supposed to put things in the upper-left corner like I'm after, but for some reason here it does not. Does anyone know why? – arcy Feb 09 '12 at 13:28
  • @rcook : Try to add something like gbc.weighty = 0.1; then do things, that will change the location. – nIcE cOw Feb 09 '12 at 14:51
  • Well, it did change things -- now the three text fields are spread out across the panel vertically. Is there a way to keep them together, the way the labels are? I'm still wondering why the labels behave differently. – arcy Feb 09 '12 at 16:40
  • @rcook : It's the difference of Layout Manager that you are using, for JLabel you using BoxLayout, but for JTextField you are using GridBagLayout. – nIcE cOw Feb 09 '12 at 16:52
  • 1
    This answer came the closest to helping me. The weightx and weighty constraints on a given component allow GridBag to calculate how much of any space over the GridBagPanel's preferred space is to be occupied by that component. It is not a number of pixels; it is a 'weight' compared to other weighty for components in that column. After I got weightx and weighty set, I had to set first_line_start and first_line_end set on the bottom and right components in the grid bag, else the item in that cell would spread out over its space. – arcy Feb 09 '12 at 18:54
  • @rcook : Even answering this question helped me too, in understanding GridBagLayout, I had never used it, just learned it to answer you, so will experiment now with it, to know it a bit more :-) – nIcE cOw Feb 10 '12 at 07:31