How can I use GroupLayout to build a form?
Asked Answered
H

4

5

What is the easiest way to build a form in Java using GroupLayout? With form, I mean something that has text fields with a label in front. Something like this:

Form screenshot

Hegelianism answered 11/7, 2012 at 13:59 Comment(3)
I wouldn't really recommend GroupLayout for hand-coding. It's possible, but the difficulty curve is steep, and you need to have the design sketched up beforehand to get the alignment constraints right. It's really mainly intended to be used with the Netbeans designer, and the primary advantage is that it lets you avoid having to nest panels, not clear code.Imagism
I never used GroupLayout before and was able to come up with this after 1 hour or so. The layout and resize behaviour is a lot better then using GridLayout for example, which most newbies to Swing programming would probably use for this.Hegelianism
I didn't say it's impossible to hand-code with GroupLayout, I just don't think it's a very good option. Every component has to be placed into two groups, possibly many lines of code apart. This makes the resulting code essentially write-only because of how many constraints you have to keep in your head to figure out what renders where and why. Even for your nearly trivial example it's probably much harder to look at the code and figure out its intent than when using GridBagLayout. (Which should let you get the right resize behaviour in much less than one hour.)Imagism
H
8

Using Group Layout, you can do the following:

package foo;

import javax.swing.*;
import java.awt.*;

public class ChangeIpSettingsDialog extends JDialog
{
public ChangeIpSettingsDialog( Frame owner )
{
    super( owner, true );
    setContentPane( createContent() );
}

private Container createContent()
{
    JPanel result = new JPanel();
    result.setBorder( BorderFactory.createEmptyBorder( 10, 10, 10, 10 ) );

    // Create the layout
    GroupLayout layout = new GroupLayout( result );
    result.setLayout( layout );
    layout.setAutoCreateGaps( true );

    // Create the components we will put in the form
    JLabel ipAddressLabel = new JLabel( "IP Address:" );
    JTextField ipAddressTextField = new JTextField( 20 );
    JLabel subnetLabel = new JLabel( "Subnet:" );
    JTextField subnetTextField = new JTextField( 20 );
    JLabel gatewayLabel = new JLabel( "Gateway:" );
    JTextField gatewayTextField = new JTextField( 20 );

    // Horizontally, we want to align the labels and the text fields
    // along the left (LEADING) edge
    layout.setHorizontalGroup( layout.createSequentialGroup()
                                       .addGroup( layout.createParallelGroup( GroupLayout.Alignment.LEADING )
                                                          .addComponent( ipAddressLabel )
                                                          .addComponent( subnetLabel )
                                                          .addComponent( gatewayLabel ) )
                                       .addGroup( layout.createParallelGroup( GroupLayout.Alignment.LEADING )
                                                          .addComponent( ipAddressTextField )
                                                          .addComponent( subnetTextField )
                                                          .addComponent( gatewayTextField ) )
    );

    // Vertically, we want to align each label with his textfield
    // on the baseline of the components
    layout.setVerticalGroup( layout.createSequentialGroup()
                                     .addGroup( layout.createParallelGroup( GroupLayout.Alignment.BASELINE )
                                                        .addComponent( ipAddressLabel )
                                                        .addComponent( ipAddressTextField ) )
                                     .addGroup( layout.createParallelGroup( GroupLayout.Alignment.BASELINE )
                                                        .addComponent( subnetLabel )
                                                        .addComponent( subnetTextField ) )
                                     .addGroup( layout.createParallelGroup( GroupLayout.Alignment.BASELINE )
                                                        .addComponent( gatewayLabel )
                                                        .addComponent( gatewayTextField ) )
    );

    return result;
}

public static void main( String[] args )
{
    ChangeIpSettingsDialog dialog = new ChangeIpSettingsDialog( null );
    dialog.pack();
    dialog.setVisible( true );
}
}
Hegelianism answered 11/7, 2012 at 13:59 Comment(0)
H
4

Or you ditch the GroupLayout and use the FormLayout, which was primarily designed as a layout for ... forms :-)

Henrietta answered 11/7, 2012 at 14:2 Comment(4)
For the example in the screenshot, even GridBagLayout should be sufficient.Imagism
@Henrietta I normally always use FormLayout for this, but my requirements was to not use an external library, but only the layoutmanagers already in Java.Hegelianism
@WimDeblauwe might be worth mentioning this explicitly in your questionHenrietta
Note that meanwhile up-to-date versions (1.13) are only available in commercial versions. Open source version (1.9) can be downloaded from the download archive. Documentation is not provided on the website.Neurotic
D
3

Just use the GUI Editor shipped within NetBeans, called Matisse. That is the most amazing GUI editor I've ever seen. It works very very good, and all your windows you design can be made resizable.

This editor produces code using the GroupLayout.

A clone of Matisse is also available as Eclipse plugin, but I don't think it is free. Take a look at it here (Disclaimer: I never used this plugin before, so I can't tell if it is the same quality as the original Matisse)
http://marketplace.eclipse.org/content/swing-gui-designer

Here is a nice screenshot:

enter image description here

Dastardly answered 11/7, 2012 at 14:6 Comment(1)
+1: Matisse is extremely useful, it's a pity that the rest of NetBeans is not up to the same level (I have to admit, I might be a bit biased having used Eclipse for many years).Michele
I
3

An example of how you could achieve the demonstrated layout with GridBagLayout:

class Main extends JFrame implements Runnable {

    JLabel lblIpAddress = new JLabel();
    JLabel lblSubnet = new JLabel();
    JLabel lblGateway = new JLabel();

    JTextField txtIpAddress = new JTextField();
    JTextField txtSubnet = new JTextField();
    JTextField txtGateway = new JTextField();

    public void run() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        Container content = this.getContentPane();

        lblIpAddress.setText("IP Address");
        lblIpAddress.setLabelFor(txtIpAddress);
        lblSubnet.setText("Subnet");
        lblSubnet.setLabelFor(txtSubnet);
        lblGateway.setText("Gateway");
        lblGateway.setLabelFor(txtGateway);

        GridBagLayout layout = new GridBagLayout();
        content.setLayout(layout);

        content.add(lblIpAddress, newLabelConstraints());
        content.add(txtIpAddress, newTextFieldConstraints());
        content.add(lblSubnet, newLabelConstraints());
        content.add(txtSubnet, newTextFieldConstraints());
        content.add(lblGateway, newLabelConstraints());
        content.add(txtGateway, newTextFieldConstraints());

        // Add a spacer to push all the form rows to the top of the window.
        GridBagConstraints spacer = new GridBagConstraints();
        spacer.fill=BOTH;
        spacer.gridwidth=REMAINDER;
        content.add(new JPanel(), spacer);

        // make sure you can't "cut off" the controls when making the window smaller
        this.pack();
        this.setMinimumSize(this.getSize());

        this.setVisible(true);
    }

    private GridBagConstraints newConstraints() {
        GridBagConstraints c = new GridBagConstraints();
        // a little breathing room
        c.insets = new Insets(2, 2, 2, 2);
        return c;
    }

    private GridBagConstraints newLabelConstraints() {
        GridBagConstraints c = newConstraints();
        // right-align labels
        c.anchor = BASELINE_TRAILING;
        // do not grow labels
        c.weightx=0.0;
        return c;
    }

    private GridBagConstraints newTextFieldConstraints() {
        GridBagConstraints c = newConstraints();
        c.anchor = BASELINE;
        // grow text fields horizontally
        c.weightx=1.0;
        c.fill=HORIZONTAL;
        // text fields end a row
        c.gridwidth=REMAINDER;
        return c;
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Main());
    }
}

The main disadvantage would be that if you wanted to say, add a right-aligned row of buttons (e.g.: "OK" and "Cancel") at the bottom, where the buttons don't align with anything else, you'd have to use a nested JPanel. (Or do something like have the form have a separate column for every button; then have the textfields span over all these columns and an additional spacer column. This is fairly counterintuitive and would negate the readability advantage. I believe MiGLayout, which is a third-party grid-based layout manager can handle this situation neatly though since it allows for merging / spanning grid cells, and splitting the merged cell.)

Imagism answered 11/7, 2012 at 15:41 Comment(3)
Add this.setBounds(0,0,300,300) in run to display the JFrame (might be a Linux and/or OpenJDK thing, but doesn't hurt). Regarding the answer: That doesn't quite do it. It'd be nice if you could post a picture of the result running in your environment so that there's a better base to discuss. In my case the text fields don't size well, i.e. at all.Neurotic
@KarlRichter - "My environment" is reachable by a) time machine; or b) me bothering to set up Java again after not having touched it for ages, to improve an answer not very many people (OP included) seem to care about, on a question that has a different accepted answer. I'm not going to swear it worked correctly for me three years ago, but if it doesn't work right now, I might as well nuke my answer.Imagism
@KarlRichter Also, if you have a similar problem as the OP, and the accepted answer isn't helping you for some reason, I'd recommend asking a new question that includes the reason why.Imagism

© 2022 - 2024 — McMap. All rights reserved.