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?

thepandaatemyface
  • 5,034
  • 6
  • 25
  • 30

5 Answers5

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();
            }
        });
    }
}
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • The only problem I have now is that when the labels in one box are different, the textboxes are differently sized, like so http://grab.by/5gpW . is there a way of fixing this without writing my own LayoutManager? – thepandaatemyface Jul 04 '10 at 17:42
  • @thepandaatemyface: I've updated the example to show one approach. – trashgod Aug 02 '10 at 15:54
  • @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](http://stackoverflow.com/questions/5979795/how-to-calculate-the-number-of-rows-and-columns-in-each-row-a-text-takes-in-a-j/5998117#5998117). – trashgod May 15 '11 at 00:34
  • 2
    +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. – Andrew Thompson Oct 31 '11 at 07:21
  • @AndrewThompson: Good point; see also this [example](http://stackoverflow.com/a/8504753/230513) using `GroupLayout`. – trashgod Dec 14 '11 at 15:46
3

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

Gordon
  • 4,823
  • 4
  • 38
  • 55
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.

Durandal
  • 19,919
  • 4
  • 36
  • 70
2

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

Michael
  • 34,873
  • 17
  • 75
  • 109
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).

Tom Hawtin - tackline
  • 145,806
  • 30
  • 211
  • 305