31

I see that GridBagLayout positions it's children with center alignment within cells. How to align left or right?

UPDATE

Constructing code (I know I could reuse c)

    // button panel
    JPanel button_panel = new JPanel();
    button_panel.add(ok_button);
    button_panel.add(cancel_button);

    // placing controls to dialog
    GridBagConstraints c;

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

    c = new GridBagConstraints();
    c.gridx = 0;
    c.gridy = 0;

    add(inputSource_label, c);

    c = new GridBagConstraints();
    c.gridx = 1;
    c.gridy = 0;
    add(inputSource_combo, c);

    c = new GridBagConstraints();
    c.gridx = 0;
    c.gridy = 1;
    add(output_label, c);

    c = new GridBagConstraints();
    c.gridx = 1;
    c.gridy = 1;
    add(output_combo, c);

    c = new GridBagConstraints();
    c.gridx = 0;
    c.gridy = 2;
    c.gridwidth = 2;
    add(button_panel, c);
Dims
  • 47,675
  • 117
  • 331
  • 600
  • 6
    Look at the GridBagLayout tutorial. There are GridBagConstraints that control this behavior, specifically the anchor field. Have you tried this? Has it not worked? If not, please show code else we won't know what you're doing wrong. – Hovercraft Full Of Eels Mar 24 '12 at 12:21
  • Oh no, GridBag again. Why you people use layout manager that was designed for computerised Swing builders? – Jakub Zaverka Mar 24 '12 at 12:32
  • You can notice that when you do GridBag, the code gets VEEEEERY long and unreadable, filled with constants everywhere. So instead of GridBag, you can try to build a hierarchy of panels using Border, Box and Flow layout. You will get 10% code length and the behaviour will be clear. – Jakub Zaverka Mar 24 '12 at 12:35
  • @Hovercraft, sorry was not attentive enough. – Dims Mar 24 '12 at 12:35
  • @Jakub I have 3 lines per each control; with panels I would have additional lines for subpanels creation. – Dims Mar 24 '12 at 12:39
  • Yes... see what happens when you resize? All components get equal space. You might not want this, you might want to keep labels at the same size and resize only inputs. – Jakub Zaverka Mar 24 '12 at 12:44
  • *"I have 3 lines per each control; with panels I would have additional lines for subpanels creation."* Sure it would. But if it takes 2 lines to create/add the sub-panel, there are 3 sub-panels, and 20 controls, you are spending an extra (1 versus 3 leaves 2) 60 lines to add the controls to GBL, over 6 LOC to create the panels and 20 lines to add the controls, for a total of 26 LOC. That means creating sub-panels will be 34 lines **shorter** overall code. – Andrew Thompson Mar 24 '12 at 12:57
  • @Jakub, also what you do to correspond vertical and horizontal positions of logically correspondent controls? – Dims Mar 24 '12 at 12:58
  • @Andrew, and what about corresponding? If I wish to have logically gridded controls with rows and columns, how I would correspond them in adjacent panels? – Dims Mar 24 '12 at 13:00
  • It depends how your want the GUI to both look & resize. Can you provide 2 ASCII art or drawn images to illustrate? Possibly a `GroupLayout` would be best if you need to align (guessing that is what you mean by 'corresponding') elements with one another. Also, for better help sooner post an [SSCCE](http://sscce.org/). – Andrew Thompson Mar 24 '12 at 13:03
  • Hm, I mentioned the GridBagConstraint.anchor field, but you've seemed to have ignored my recommendation. Why? – Hovercraft Full Of Eels Mar 24 '12 at 13:14
  • I have posted the code in my answer. – Jakub Zaverka Mar 24 '12 at 13:24
  • @Hovercraft, no I saw it and already used it. – Dims Mar 24 '12 at 15:06
  • @Dims: I did not see it used in your posted code. – Hovercraft Full Of Eels Mar 24 '12 at 15:10
  • @Hovercraft, I posted a code to support discussion what is better -- panels or grids, so I posted original code there, before introducing `anchor`s – Dims Mar 24 '12 at 16:23

2 Answers2

51

When using GridBagLayout for a tabular display of JLabel : JTextField, I like to have a method that makes my GridBagConstraints for me based on the x, y position. For example something like so:

   private GridBagConstraints createGbc(int x, int y) {
      GridBagConstraints gbc = new GridBagConstraints();
      gbc.gridx = x;
      gbc.gridy = y;
      gbc.gridwidth = 1;
      gbc.gridheight = 1;

      gbc.anchor = (x == 0) ? GridBagConstraints.WEST : GridBagConstraints.EAST;
      gbc.fill = (x == 0) ? GridBagConstraints.BOTH
            : GridBagConstraints.HORIZONTAL;

      gbc.insets = (x == 0) ? WEST_INSETS : EAST_INSETS;
      gbc.weightx = (x == 0) ? 0.1 : 1.0;
      gbc.weighty = 1.0;
      return gbc;
   }

The following code makes a GUI that looks like this:

enter image description here

import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.util.HashMap;
import java.util.Map;

import javax.swing.*;

public class GridBagEg {
   private static void createAndShowGui() {
      PlayerEditorPanel playerEditorPane = new PlayerEditorPanel();

      int result = JOptionPane.showConfirmDialog(null, playerEditorPane,
            "Edit Player", JOptionPane.OK_CANCEL_OPTION,
            JOptionPane.PLAIN_MESSAGE);
      if (result == JOptionPane.OK_OPTION) {
         // TODO: do something with info

         for (PlayerEditorPanel.FieldTitle fieldTitle : 
            PlayerEditorPanel.FieldTitle.values()) {
            System.out.printf("%10s: %s%n", fieldTitle.getTitle(),
                  playerEditorPane.getFieldText(fieldTitle));
         }
      }
   }

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

@SuppressWarnings("serial")
class PlayerEditorPanel extends JPanel {
   enum FieldTitle {
      NAME("Name"), SPEED("Speed"), STRENGTH("Strength");
      private String title;

      private FieldTitle(String title) {
         this.title = title;
      }

      public String getTitle() {
         return title;
      }
   };

   private static final Insets WEST_INSETS = new Insets(5, 0, 5, 5);
   private static final Insets EAST_INSETS = new Insets(5, 5, 5, 0);
   private Map<FieldTitle, JTextField> fieldMap = new HashMap<FieldTitle, JTextField>();

   public PlayerEditorPanel() {
      setLayout(new GridBagLayout());
      setBorder(BorderFactory.createCompoundBorder(
            BorderFactory.createTitledBorder("Player Editor"),
            BorderFactory.createEmptyBorder(5, 5, 5, 5)));
      GridBagConstraints gbc;
      for (int i = 0; i < FieldTitle.values().length; i++) {
         FieldTitle fieldTitle = FieldTitle.values()[i];
         gbc = createGbc(0, i);
         add(new JLabel(fieldTitle.getTitle() + ":", JLabel.LEFT), gbc);
         gbc = createGbc(1, i);
         JTextField textField = new JTextField(10);
         add(textField, gbc);

         fieldMap.put(fieldTitle, textField);
      }
   }

   private GridBagConstraints createGbc(int x, int y) {
      GridBagConstraints gbc = new GridBagConstraints();
      gbc.gridx = x;
      gbc.gridy = y;
      gbc.gridwidth = 1;
      gbc.gridheight = 1;

      gbc.anchor = (x == 0) ? GridBagConstraints.WEST : GridBagConstraints.EAST;
      gbc.fill = (x == 0) ? GridBagConstraints.BOTH
            : GridBagConstraints.HORIZONTAL;

      gbc.insets = (x == 0) ? WEST_INSETS : EAST_INSETS;
      gbc.weightx = (x == 0) ? 0.1 : 1.0;
      gbc.weighty = 1.0;
      return gbc;
   }

   public String getFieldText(FieldTitle fieldTitle) {
      return fieldMap.get(fieldTitle).getText();
   }

}

In this example, I display the JPanel in a JOptionPane, but it could just as easily be displayed in a JFrame or JApplet or JDialog or ...

Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
4

For example

public class DimsPanel extends JPanel
{
    public static void main(String[] args){
        JFrame main = new JFrame("Dims");
        JPanel myPanel = new DimsPanel();
        main.setContentPane(myPanel);
        main.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        main.setSize(400, 400);
        main.setLocationRelativeTo(null);
        main.setVisible(true);
    }

    JButton ok_button = new JButton("OK"), cancel_button = new JButton("Cancel");
    JLabel inputSource_label = new JLabel("Input source:"), 
                output_label = new JLabel("Output:");
    JComboBox inputSource_combo = new JComboBox(new String[]{"A", "B", "C"}), 
                output_combo = new JComboBox(new String[]{"A", "B", "C"});

    public DimsPanel(){
        super(new BorderLayout());
        Box main = new Box(BoxLayout.Y_AXIS);

        Dimension labelsWidth = new Dimension(100, 0);
        JPanel inputPanel = new JPanel(new BorderLayout()); 
        inputSource_label.setPreferredSize(labelsWidth);
        inputPanel.add(inputSource_label, BorderLayout.WEST);
        inputPanel.add(inputSource_combo);

        JPanel outputPanel = new JPanel(new BorderLayout()); 
        output_label.setPreferredSize(labelsWidth);
        outputPanel.add(output_label, BorderLayout.WEST);
        outputPanel.add(output_combo);
        // button panel
        JPanel button_panel = new JPanel();
        button_panel.add(ok_button);
        button_panel.add(cancel_button);

        main.add(inputPanel);
        main.add(outputPanel);

        add(main, BorderLayout.NORTH);
        add(button_panel);
    }
}

You can run and see it. Resizing works like a charm and the layout code has only 18 lines. The only disadvantage is that you need to specify the width of the labels by hand. If you really don't want to see setPreferredSize() in the code, then be my guest and go with GridBag. But I personally like this code more.

mKorbel
  • 109,525
  • 20
  • 134
  • 319
Jakub Zaverka
  • 8,816
  • 3
  • 32
  • 48