Keeping preferred sizes of components in center of BorderLayout
Asked Answered
U

2

5

I have a medium-large UI that uses a BorderLayout; the center is a tabbed pane containing various panels with various layouts, etc.

I want the panel in the center of this border layout to resize according to the size of the window, but I don't want the components within the panel to stretch. Labels, combo boxes, text fields, buttons -- I want them to stay at their preferred sizes, and allow the panel that contains them to stretch. I put them in a scroll pane in case the space gets too small for the panel.

Various posters with colorful vocabularies warn against the danger of using any of the setXXXsize() methods on components. That's what I do now, and I'd like to learn how to avoid it.

GridBagLayout is not appropriate for some of my panels. It is, by nature, oriented around rows and columns, and not everything fits into rows and columns. Of course I could create artificial rows and columns to fit everything into, but I'm really hoping Swing has more layout options than that.

Vertical Glue doesn't do it either. I've included it in HFOE's beloved SSCE:

    package example;

    import java.awt.BorderLayout;

    import javax.swing.Box;
    import javax.swing.BoxLayout;
    import javax.swing.JComboBox;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;

    public class BorderAndBox extends JFrame
    {
        public static void main(String args[])
        {
            BorderAndBox bnb = new BorderAndBox();
            bnb.createUI();
            bnb.setVisible(true);
        }

        public void createUI()
        {
            JPanel borderPanel = new JPanel(new BorderLayout());

            JLabel northLabel = new JLabel("Nawth");
            borderPanel.add(northLabel, BorderLayout.NORTH);

            String[] southComboChoices = { "one", "two", "three" };
            JComboBox southCombo = new JComboBox(southComboChoices);
            borderPanel.add(southCombo, BorderLayout.SOUTH);

            JPanel centerPanel = new JPanel();
            centerPanel.setLayout(new BoxLayout(centerPanel, BoxLayout.PAGE_AXIS));
            String[] firstChoices = { "first", "uno", "UN" };
            String[] secondChoices = { "second", "dos", "zwei" };
            String[] thirdChoices = { "third", "tres", "drei" };
            JComboBox firstCombo = new JComboBox(firstChoices);
            JComboBox secondCombo = new JComboBox(secondChoices);
            JComboBox thirdCombo = new JComboBox(thirdChoices);
            centerPanel.add(firstCombo);
            centerPanel.add(secondCombo);
            centerPanel.add(thirdCombo);
            centerPanel.add(Box.createVerticalGlue());  // first attempt; does NOT
            // take up available vertical space, instead it appears to create a space
            // that is shared equally among the (now) four components of this space.
            borderPanel.add(centerPanel, BorderLayout.CENTER);

            getContentPane().add(borderPanel);
            pack();
        }

    }

If you enlarge the window, the comboboxes in the center enlarge; as written, a vertical glue piece below them also enlarges, but doesn't take up all available space. It appears it is given as much space as each of them.

So what is a good way to approach this?

Unteach answered 2/3, 2012 at 16:42 Comment(5)
"..beloved SSCE:" I love it too. And it is SSCCE (2 Cs). ;)Gallegos
it can't just be a small self-contained example?Unteach
"it can't just be a small self-contained example?" Quoting one of my favorite people: "In this document, correct (or compilable, which particularly relates to computer source code) means ensuring that your example fits the accepted standards and protocols." most notable sub-point "Ensure your example is correct. Either the example compiles cleanly, or causes the exact error message about which you want help." The code compiled and showed the problem, easy done. It is an SSCCE. :)Gallegos
I guess I thought compilable was implied by self-contained, assuming execution was part of the example, but I am happy to use the slightly longer abbreviation. If we can just find another "E" word to use towards the end, then we could have double letters all the way through...Unteach
Oh, there are people already angry enough that I used 5 letters for the term. It takes all types. ;)Gallegos
G
11

BorderAndBox - centered

import java.awt.BorderLayout;
import java.awt.GridBagLayout;

import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class BorderAndBox extends JFrame
{
public static void main(String args[])
{
    BorderAndBox bnb = new BorderAndBox();
    bnb.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    bnb.createUI();
    bnb.setVisible(true);
}

public void createUI()
{
    JPanel borderPanel = new JPanel(new BorderLayout());

    JLabel northLabel = new JLabel("Nawth");
    borderPanel.add(northLabel, BorderLayout.NORTH);

    String[] southComboChoices = { "one", "two", "three" };
    JComboBox southCombo = new JComboBox(southComboChoices);
    borderPanel.add(southCombo, BorderLayout.SOUTH);

    JPanel centerPanel = new JPanel();
    centerPanel.setLayout(new BoxLayout(centerPanel, BoxLayout.PAGE_AXIS));
    String[] firstChoices = { "first", "uno", "UN" };
    String[] secondChoices = { "second", "dos", "zwei" };
    String[] thirdChoices = { "third", "tres", "drei" };
    JComboBox firstCombo = new JComboBox(firstChoices);
    JComboBox secondCombo = new JComboBox(secondChoices);
    JComboBox thirdCombo = new JComboBox(thirdChoices);
    centerPanel.add(firstCombo);
    centerPanel.add(secondCombo);
    centerPanel.add(thirdCombo);
    centerPanel.add(Box.createVerticalGlue());  // first attempt; does NOT
    // take up available vertical space, instead it appears to create a space
    // that is shared equally among the (now) four components of this space.
    JPanel centerPanelConstrain = new JPanel(new GridBagLayout());
    centerPanelConstrain.add(centerPanel);
    borderPanel.add(centerPanelConstrain, BorderLayout.CENTER);

    getContentPane().add(borderPanel);
    pack();
}

}

See also this answer. There is more than one way to solve this.

Gallegos answered 2/3, 2012 at 16:53 Comment(8)
That's a cute trick; I assume I can play with the GridBagLayout of my single component to get it to appear in the upper left, as I would like. Would you care to elaborate on why this works?Unteach
"Would you care to elaborate on why this works?" A single component added to a GBL with no constraint, ends up in the center. As to any other position, I'm not sure. I only use GBL for centering single components, and once long ago for a periodic table (arranging each element). Today I'd probably do the latter using GroupPlayout. I am no expert on GBL.Gallegos
GroupPlayout ? LOL, +1 though, I too was about to post the same logic, but seems like I am too too too late.Micropathology
This answered my question, but I would also like to have it appear in the upper-left of the available space, instead of centering it. I added gridx=0, gridy=0, and anchor=FIRST_LINE_START to a grid bag constraints instance, and added that to my call to add the panel to the grid bag panel, and it had no effect. I'll post it again if someone wants. But can someone guide me to some way of doing that?Unteach
It is certainly possible to put the center component in the top left of it's assigned space using a nested layout, but it would require 2 dummy panels. (I keep looking over my shoulder, waiting for someone to jump up and shout Or 1 good layout manager!) Put the panel in the NORTH (top) of 1 BorderLayout, then add that to the WEST (left) of a 2nd BorderLayout. Add the 2nd panel to the parent container.Gallegos
You are THE MAN -- don't know why I didn't think of that. I will be dummying panels all over the place; may into even look into writing an UpperLeftCornerLayoutManager (GoodLayoutManager? TwoDummyPanelsLayoutManager?). Thanks for all the help.Unteach
Hovercraft helped me find another way to do this: when adding to the GridBagLayout, add the single panel to a 1x1 grid with x and y weights of 1.0, positioned to NORTHWEST. You don't have to use the two dummy panels that way.Unteach
I thought there had to be a better way (& I'm not surprised it was HFOE who pointed you to it). Glad you got it sorted. :)Gallegos
S
-2

I would recommend you using JPanel with javax.swing.GroupLayout. However it is not easy to use this layout by coding it. Use code generators like Netbeans Matisse Builder and copy paste it to wherever you want if you dont want to use the IDE.

Safeconduct answered 2/3, 2012 at 17:16 Comment(1)
GroupLayout, like GridBagLayout, is all about rows and columns; I could possibly use a GroupLayout the same way Mr. Thompson just showed me GridBagLayout, I'll see if that's any easier to put in the upper left corner as I want. But I think both Group and GridBag layouts are poor choices for panels with a number of components but no row/column appearance.Unteach

© 2022 - 2024 — McMap. All rights reserved.