Variable Layout in Swing
Asked Answered
O

5

11

How would you go about getting a decent looking gui generated when you don't know how many components you will have and how big they will be?

A user, for instance, enters how many textfields they want and which of those textfields are grouped in bordered panels and the program generates this.

I've been using GridLayout, but the problem is that it makes all cells of the same width and height, which is fine when all components have the same size, but when I, for example, have a textfield and a bordered panel with multiple fields, either the textfield gets stretched out or the panel is squeezed.

I would like all components to have their minimum size, but still, you know, usable.

Example of how it is now, using GridLayout, all fields are normal, one-line JTextFields where the panel titled date is totally squeezed (it has three fields in it) and the first level fields are way to big. Anyone have any pointers?

Origami answered 4/7, 2010 at 13:10 Comment(0)
M
15

MiGLayout has a lot of appeal, but BoxLayout is an alternative.

image

import java.awt.*;
import java.util.List;
import java.util.ArrayList;
import javax.swing.*;

public class BoxTest extends JPanel {

    private List<JTextField> fields = new ArrayList<JTextField>();

    public BoxTest() {
        this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
        this.add(createPane(3, "One ", Color.red));
        this.add(createPane(3, "Two ", Color.green));
        this.add(createPane(10, "Three ", Color.blue));
    }

    private JPanel createPane(int n, String s, Color c) {
        JPanel outer = new JPanel();
        outer.setLayout(new BoxLayout(outer, BoxLayout.Y_AXIS));
        outer.setBorder(BorderFactory.createLineBorder(c, 2));
        for (int i = 0; i < n; i++) {
            JPanel inner = new JPanel();
            inner.setLayout(new BoxLayout(inner, BoxLayout.X_AXIS));
            JLabel label = new JLabel(s + i + ":", JLabel.RIGHT);
            label.setPreferredSize(new Dimension(80, 32));
            inner.add(label);
            JTextField tf = new JTextField("Stackoverflow!", 32);
            inner.add(tf);
            fields.add(tf);
            outer.add(inner);
        }
        return outer;
    }

    private void display() {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JScrollPane jsp = new JScrollPane(this,
            JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
            JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
        this.validate();
        Dimension d = this.getPreferredSize();
        d.height /= 2;
        jsp.getViewport().setPreferredSize(d);
        jsp.getVerticalScrollBar().setUnitIncrement(
            this.getPreferredSize().height / fields.size());
        f.add(jsp);
        f.pack();
        f.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                new BoxTest().display();
            }
        });
    }
}
Monamonachal answered 4/7, 2010 at 15:59 Comment(5)
The only problem I have now is that when the labels in one box are different, the textboxes are differently sized, like so grab.by/5gpW . is there a way of fixing this without writing my own LayoutManager?Origami
@thepandaatemyface: I've updated the example to show one approach.Monamonachal
@mKorbel uses the mot juste: setting the label's preferred size is an arbitrary hack. A more precise approach might find the longest label using one of the techniques discussed here.Monamonachal
+1 - though I suspect this might also have been a good case for GroupLayout in terms of not having to set the size of labels.Fitzhugh
@AndrewThompson: Good point; see also this example using GroupLayout.Monamonachal
W
3

I would look at miglayout. It's a lot more useful than any of the inbuilt layout managers.

Wo answered 4/7, 2010 at 13:13 Comment(0)
E
3

Your general goal - "usable component sizes" clashes with "unknown number". Make the number large enough and they won't fit any screen.

Overthink if you wouldn't be better off with using JTables (cells can be made editable) in conjuction with a JScrollPanel. If you want/must keep your approach of generating components, put the whole JPanel that contains your components into a JScrollPane, that way the components wont be squeezed to badly.

Ezekielezell answered 4/7, 2010 at 13:45 Comment(0)
R
2

Yeah, MiGLayout is nice. You can do pretty much anything with it.

Racemose answered 4/7, 2010 at 13:45 Comment(0)
V
1

Minimum size in AWT and Swing is usually pointless. I suggest adding a panel to delegate minimum size to original preferred size, and possibly add a bit to the new preferred size. In GridBagLayout add weights where you want additional space to go in the normal size. As Durandal mentions, popping up scroll bars around the top-level window beats squeezing the layout or going off the screen (I'm writing this on a Netbook, so I know about windows larger than the screen).

Viera answered 4/7, 2010 at 19:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.