Search code examples
javaswingjpaneljoptionpanegridbaglayout

Gridbag layout problems


I am designing a panel and using this panel in an OptionPane Confirm Dialog like this:

JOptionPane.showConfirmDialog(null, slaveGroupPanel, messages.getString("centrum.manageGroups"), JOptionPane.OK_CANCEL_OPTION);

My gridbag constraints are this:

    addGroupButton.setText(messages.getString("centrum.slavegroup.add"));
    gridBagConstraints = new java.awt.GridBagConstraints();
    gridBagConstraints.gridx = 6;
    gridBagConstraints.gridy = 0;
    gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
    add(addGroupButton, gridBagConstraints);

    gridBagConstraints = new java.awt.GridBagConstraints();
    gridBagConstraints.gridx = 1;
    gridBagConstraints.gridy = 0;
    gridBagConstraints.gridwidth = 5;
    gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
    gridBagConstraints.weightx = 1.0;
    add(addGroupTextField, gridBagConstraints);

    gridBagConstraints = new java.awt.GridBagConstraints();
    gridBagConstraints.gridx = 0;
    gridBagConstraints.gridy = 0;
    gridBagConstraints.gridwidth = 1;
    gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
    add(groupNameLabel, gridBagConstraints);

    groupComboBox.setModel(new DefaultComboBoxModel(slaveGroupHash.keySet().toArray() ));
    gridBagConstraints = new java.awt.GridBagConstraints();
    gridBagConstraints.gridx = 0;
    gridBagConstraints.gridy = 1;
    gridBagConstraints.gridwidth = 5;
    gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
    gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
    gridBagConstraints.weightx = 1;
    add(groupComboBox, gridBagConstraints);

    allSlavesList.setModel(new DefaultListModel());

    for (int i = 0; i < allSlaves.length; i++) {
        ((DefaultListModel)allSlavesList.getModel()).addElement(allSlaves[i]);
    }

    allSlavesList.setVisibleRowCount(4);
    jScrollPane2.setViewportView(allSlavesList);
    jScrollPane2.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);


    gridBagConstraints = new java.awt.GridBagConstraints();
    gridBagConstraints.gridx = 0;
    gridBagConstraints.gridy = 3;
    gridBagConstraints.gridwidth = 3;
    gridBagConstraints.gridheight = 2;
    gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
    gridBagConstraints.weightx = 0.45;
    gridBagConstraints.weighty = 1.0;
    add(jScrollPane2, gridBagConstraints);

    slavesInGroupList.setModel(new DefaultListModel());
    slavesInGroupList.setVisibleRowCount(4);
    jScrollPane3.setViewportView(slavesInGroupList);
    jScrollPane3.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);

    gridBagConstraints = new java.awt.GridBagConstraints();
    gridBagConstraints.gridx = 4;
    gridBagConstraints.gridy = 3;
    gridBagConstraints.gridwidth = 3;
    gridBagConstraints.gridheight = 2;
    gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
    gridBagConstraints.weightx = 0.45;
    gridBagConstraints.weighty = 1.0;
    add(jScrollPane3, gridBagConstraints);

    gridBagConstraints = new java.awt.GridBagConstraints();
    gridBagConstraints.gridx = 0;
    gridBagConstraints.gridy = 2;
    gridBagConstraints.fill = GridBagConstraints.HORIZONTAL;
    add(allSlavesLabel, gridBagConstraints);

    gridBagConstraints = new java.awt.GridBagConstraints();
    gridBagConstraints.gridx = 4;
    gridBagConstraints.gridy = 2;
    gridBagConstraints.fill = GridBagConstraints.HORIZONTAL;
    add(slavesInGroupLabel, gridBagConstraints);

    addSlaveButton.setIcon(GeneralObjects.getrightIcon());
    gridBagConstraints = new java.awt.GridBagConstraints();
    gridBagConstraints.gridx = 3;
    gridBagConstraints.gridy = 3;
    gridBagConstraints.weightx = 0.1;
    gridBagConstraints.weighty = 1.0;
    add(addSlaveButton, gridBagConstraints);

    deleteSlaveButton.setIcon(GeneralObjects.getleftIcon());
    gridBagConstraints = new java.awt.GridBagConstraints();
    gridBagConstraints.gridx = 3;
    gridBagConstraints.gridy = 4;
    gridBagConstraints.weightx = 0.1;
    gridBagConstraints.weighty = 1.0;
    add(deleteSlaveButton, gridBagConstraints);

    renameButton.setText(messages.getString("centrum.slavegroup.rename"));

    gridBagConstraints = new java.awt.GridBagConstraints();
    gridBagConstraints.gridx = 6;
    gridBagConstraints.gridy = 1;
    gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
    add(renameButton, gridBagConstraints);

    deleteButton.setText(messages.getString("centrum.slavegroup.delete"));
    gridBagConstraints = new java.awt.GridBagConstraints();
    gridBagConstraints.gridx = 5;
    gridBagConstraints.gridy = 1;
    gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
    add(deleteButton, gridBagConstraints);

But as you can see in the screenshot attached there are two gaps between the text field and the add button. Also that gap occurs between delete and rename buttons. However I do not want those gaps. I have no insets defined and I have both the text field an combobox with weightx = 1; and fill = java.awt.GridBagConstraints.HORIZONTAL; So I expect them to expand horizontally as much as possible without having gaps. But why do those gaps occur?

Secondly you can clearly see that the Jlist on the right hand is wider than the one on the left hand. However both my JLists (actually ScrollPanes containing the JLists) have the gridwidth , weightx and fill parameters set to the same values. So I expect them to be equally sized. Looks like I am missing something.

enter image description here

SSCCE is added below:

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

public class SSCCE {

private javax.swing.JButton addGroupButton;
private javax.swing.JTextField addGroupTextField;
private javax.swing.JButton addSlaveButton;
private javax.swing.JList allSlavesList;
private javax.swing.JButton deleteButton;
private javax.swing.JButton deleteSlaveButton;
private javax.swing.JComboBox groupComboBox;
private javax.swing.JScrollPane jScrollPane2;
private javax.swing.JScrollPane jScrollPane3;
private javax.swing.JButton renameButton;
private javax.swing.JLabel groupNameLabel;
private javax.swing.JLabel allSlavesLabel;
private javax.swing.JLabel slavesInGroupLabel;
private javax.swing.JList slavesInGroupList;

public SSCCE() {

}

public JPanel createPanel(){
    JPanel panel = new JPanel();
    panel.setLayout(new java.awt.GridBagLayout());


    addGroupButton=new javax.swing.JButton();
    addGroupTextField=new javax.swing.JTextField();
    addSlaveButton=new javax.swing.JButton();
    allSlavesList=new javax.swing.JList();
    deleteButton=new javax.swing.JButton();
    deleteSlaveButton=new javax.swing.JButton();
    groupComboBox=new javax.swing.JComboBox();
    jScrollPane2=new javax.swing.JScrollPane();
    jScrollPane3=new javax.swing.JScrollPane();
    renameButton=new javax.swing.JButton();
    groupNameLabel=new javax.swing.JLabel();
    allSlavesLabel=new javax.swing.JLabel();
    slavesInGroupLabel=new javax.swing.JLabel();
    slavesInGroupList=new javax.swing.JList();

    allSlavesList.setModel(new DefaultListModel());
    slavesInGroupList.setModel(new DefaultListModel());



    GridBagConstraints gridBagConstraints;

    addGroupButton.setText("add");
    gridBagConstraints = new java.awt.GridBagConstraints();
    gridBagConstraints.gridx = 6;
    gridBagConstraints.gridy = 0;
    gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
    panel.add(addGroupButton, gridBagConstraints);

    gridBagConstraints = new java.awt.GridBagConstraints();
    gridBagConstraints.gridx = 1;
    gridBagConstraints.gridy = 0;
    gridBagConstraints.gridwidth = 5;
    gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
    gridBagConstraints.weightx = 1.0;
    panel.add(addGroupTextField, gridBagConstraints);

    gridBagConstraints = new java.awt.GridBagConstraints();
    gridBagConstraints.gridx = 0;
    gridBagConstraints.gridy = 0;
    gridBagConstraints.gridwidth = 1;
    gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
    panel.add(groupNameLabel, gridBagConstraints);

    groupComboBox.setModel(new DefaultComboBoxModel(new Object[]{"one","two","three"}));
    gridBagConstraints = new java.awt.GridBagConstraints();
    gridBagConstraints.gridx = 0;
    gridBagConstraints.gridy = 1;
    gridBagConstraints.gridwidth = 5;
    gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
    gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
    gridBagConstraints.weightx = 1;
    panel.add(groupComboBox, gridBagConstraints);



    allSlavesList.setVisibleRowCount(4);
    jScrollPane2.setViewportView(allSlavesList);
    jScrollPane2.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);


    gridBagConstraints = new java.awt.GridBagConstraints();
    gridBagConstraints.gridx = 0;
    gridBagConstraints.gridy = 3;
    gridBagConstraints.gridwidth = 3;
    gridBagConstraints.gridheight = 2;
    gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
    gridBagConstraints.weightx = 0.45;
    gridBagConstraints.weighty = 1.0;
    panel.add(jScrollPane2, gridBagConstraints);

    slavesInGroupList.setVisibleRowCount(4);
    jScrollPane3.setViewportView(slavesInGroupList);
    jScrollPane3.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);

    gridBagConstraints = new java.awt.GridBagConstraints();
    gridBagConstraints.gridx = 4;
    gridBagConstraints.gridy = 3;
    gridBagConstraints.gridwidth = 3;
    gridBagConstraints.gridheight = 2;
    gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
    gridBagConstraints.weightx = 0.45;
    gridBagConstraints.weighty = 1.0;
    panel.add(jScrollPane3, gridBagConstraints);

    gridBagConstraints = new java.awt.GridBagConstraints();
    gridBagConstraints.gridx = 0;
    gridBagConstraints.gridy = 2;
    gridBagConstraints.fill = GridBagConstraints.HORIZONTAL;
    panel.add(allSlavesLabel, gridBagConstraints);

    gridBagConstraints = new java.awt.GridBagConstraints();
    gridBagConstraints.gridx = 4;
    gridBagConstraints.gridy = 2;
    gridBagConstraints.fill = GridBagConstraints.HORIZONTAL;
    panel.add(slavesInGroupLabel, gridBagConstraints);

    //addSlaveButton.setIcon(GeneralObjects.getrightIcon());
    gridBagConstraints = new java.awt.GridBagConstraints();
    gridBagConstraints.gridx = 3;
    gridBagConstraints.gridy = 3;
    gridBagConstraints.weightx = 0.1;
    gridBagConstraints.weighty = 1.0;
    panel.add(addSlaveButton, gridBagConstraints);

    //deleteSlaveButton.setIcon(GeneralObjects.getleftIcon());
    gridBagConstraints = new java.awt.GridBagConstraints();
    gridBagConstraints.gridx = 3;
    gridBagConstraints.gridy = 4;
    gridBagConstraints.weightx = 0.1;
    gridBagConstraints.weighty = 1.0;
    panel.add(deleteSlaveButton, gridBagConstraints);

    renameButton.setText("rename");

    gridBagConstraints = new java.awt.GridBagConstraints();
    gridBagConstraints.gridx = 6;
    gridBagConstraints.gridy = 1;
    gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
    panel.add(renameButton, gridBagConstraints);

    deleteButton.setText("delete");
    gridBagConstraints = new java.awt.GridBagConstraints();
    gridBagConstraints.gridx = 5;
    gridBagConstraints.gridy = 1;
    gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
    panel.add(deleteButton, gridBagConstraints);




    ((DefaultListModel)allSlavesList.getModel()).addElement("one");
    ((DefaultListModel)allSlavesList.getModel()).addElement("two");
    ((DefaultListModel)allSlavesList.getModel()).addElement("three");

    ((DefaultListModel)slavesInGroupList.getModel()).addElement("one");
    ((DefaultListModel)slavesInGroupList.getModel()).addElement("two");
    ((DefaultListModel)slavesInGroupList.getModel()).addElement("three");
    panel.setPreferredSize(new Dimension(600,300));


    return panel;

}

public static void main(String[] args){
    SSCCE a = new SSCCE();
    JOptionPane.showConfirmDialog(null, a.createPanel(), "centrum.manageGroups", JOptionPane.OK_CANCEL_OPTION);
}


}

Solution

  • You should try to use a little bit more nesting because you can not set up such layout in a flat layout.

    From what you describe, I see:

    • A root panel containing 3 rows (use a GridBagLayout to set this up and give all the extra vertical space to the last row)
    • Row 1: your label, your textfield and a button--> use a BorderLayout
    • Row 2: a combobox and 2 buttons --> Use GridBagLayout and give all the extra-space to the combobox
    • Row 3: 2 labels, 2 lists and 2 buttons --> Use GridBagLayout to set this up

    Now, one thing to understand with GridBagLayout is that weightx/weighty are not percentage of the width/height it will distribute but how is "extra" space distributed. It will first give each component its preferred size and then, if there is any extra space, it will distribute that space according to the weight of each component.

    For the last row, the width of each "column" is based on the preferred size of your 2 labels (one is clearly wider than the other) and the preferred size of your 2 JList (which is based on the content of the JList).

    Here is an update of your SSCCE (although I had to rework it a lot because the code was a bit messy: try to do things in order, first set up your components, then lay them out in the order they appear, it is much simpler to read).

    import java.awt.BorderLayout;
    import java.awt.GridBagConstraints;
    import java.awt.GridBagLayout;
    import java.awt.Insets;
    
    import javax.swing.DefaultComboBoxModel;
    import javax.swing.DefaultListModel;
    import javax.swing.JDialog;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.SwingUtilities;
    
    public class SSCCE {
    
        private javax.swing.JButton addGroupButton;
        private javax.swing.JTextField addGroupTextField;
        private javax.swing.JButton addSlaveButton;
        private javax.swing.JList allSlavesList;
        private javax.swing.JButton deleteButton;
        private javax.swing.JButton deleteSlaveButton;
        private javax.swing.JComboBox groupComboBox;
        private javax.swing.JScrollPane jScrollPane2;
        private javax.swing.JScrollPane jScrollPane3;
        private javax.swing.JButton renameButton;
        private javax.swing.JLabel allSlavesLabel;
        private javax.swing.JLabel slavesInGroupLabel;
        private javax.swing.JList slavesInGroupList;
        private JLabel groupNameLabel;
    
        public SSCCE() {
    
        }
    
        public JPanel createPanel() {
            JPanel panel = new JPanel();
            panel.setLayout(new java.awt.GridBagLayout());
    
            addGroupButton = new javax.swing.JButton();
            addGroupTextField = new javax.swing.JTextField();
            addSlaveButton = new javax.swing.JButton();
            allSlavesList = new javax.swing.JList();
            deleteButton = new javax.swing.JButton();
            deleteSlaveButton = new javax.swing.JButton();
            groupComboBox = new javax.swing.JComboBox();
            jScrollPane2 = new javax.swing.JScrollPane();
            jScrollPane3 = new javax.swing.JScrollPane();
            renameButton = new javax.swing.JButton();
            allSlavesLabel = new javax.swing.JLabel("All slaves");
            slavesInGroupLabel = new javax.swing.JLabel("Devices in this group");
            groupNameLabel = new JLabel("Groupd name:");
            slavesInGroupList = new javax.swing.JList();
            groupComboBox.setModel(new DefaultComboBoxModel(new Object[] { "one", "two", "three" }));
            addGroupButton.setText("add");
            allSlavesList.setModel(new DefaultListModel());
            slavesInGroupList.setModel(new DefaultListModel());
            renameButton.setText("rename");
            deleteButton.setText("delete");
            addSlaveButton.setText("->");
            deleteSlaveButton.setText("<-");
            allSlavesList.setVisibleRowCount(4);
            jScrollPane2.setViewportView(allSlavesList);
            jScrollPane2.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
            ((DefaultListModel) allSlavesList.getModel()).addElement("one");
            ((DefaultListModel) allSlavesList.getModel()).addElement("two");
            ((DefaultListModel) allSlavesList.getModel()).addElement("three");
    
            ((DefaultListModel) slavesInGroupList.getModel()).addElement("one");
            ((DefaultListModel) slavesInGroupList.getModel()).addElement("two");
            ((DefaultListModel) slavesInGroupList.getModel()).addElement("three");
            slavesInGroupList.setVisibleRowCount(4);
            jScrollPane3.setViewportView(slavesInGroupList);
            jScrollPane3.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
    
            // Let's split your display in 3 rows
            panel = new JPanel(new GridBagLayout());
            JPanel row1 = new JPanel(new BorderLayout(3, 3));
            JPanel row2 = new JPanel(new GridBagLayout());
            JPanel row3 = new JPanel(new GridBagLayout());
    
            // Use GBL to make three rows and give all extra vertical space to the last one
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridwidth = GridBagConstraints.REMAINDER;
            gbc.weightx = 1.0;
            gbc.fill = GridBagConstraints.BOTH;
            gbc.insets = new Insets(3, 3, 3, 3);
            panel.add(row1, gbc);
            panel.add(row2, gbc);
            // Gives all extra v-space to last row
            gbc.weighty = 1.0;
            panel.add(row3, gbc);
    
            GridBagConstraints gridBagConstraints;
    
            // Set up row 1
            row1.add(groupNameLabel, BorderLayout.WEST);
            row1.add(addGroupButton, BorderLayout.EAST);
            row1.add(addGroupTextField);// In the middle so that it takes all the width and it won't stretch vertically because row1 has weighty
                                        // set to 0.0
    
            // Set up row 2
            // We give all extra space to the combo box
            gbc = new java.awt.GridBagConstraints();
            gbc.insets = new Insets(3, 3, 3, 3);
            gbc.fill = java.awt.GridBagConstraints.HORIZONTAL;
            gbc.weightx = 1;
            row2.add(groupComboBox, gbc);
            gbc.weightx = 0;
            row2.add(deleteButton, gbc);
            row2.add(renameButton, gbc);
    
            // Set up row3
            gbc = new java.awt.GridBagConstraints();
            gbc.insets = new Insets(3, 3, 3, 3);
            gbc.gridx = 0;
            gbc.gridy = 0;
            gbc.weightx = 1.0;
            gbc.anchor = GridBagConstraints.WEST;
            row3.add(allSlavesLabel, gbc);
            gbc.gridx = 2;
            row3.add(slavesInGroupLabel, gbc);
    
            gbc.weighty = 1.0;
            gbc.weightx = 1.0;
            gbc.gridheight = 2;
            gbc.gridx = 0;
            gbc.gridy = 1;
            gbc.fill = GridBagConstraints.BOTH;
    
            row3.add(jScrollPane2, gbc);
            gbc.fill = GridBagConstraints.NONE;
            gbc.anchor = GridBagConstraints.CENTER;
            gbc.gridheight = 1;
            gbc.gridx = 1;
            gbc.weightx = 0;
            row3.add(addSlaveButton, gbc);
            gbc.gridy = 2;
            row3.add(deleteSlaveButton, gbc);
    
            gbc.gridheight = 2;
            gbc.gridx = 2;
            gbc.gridy = 1;
            gbc.fill = GridBagConstraints.BOTH;
    
            row3.add(jScrollPane3, gbc);
    
            return panel;
    
        }
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    SSCCE a = new SSCCE();
                    JDialog dialog = new JDialog();
                    dialog.add(a.createPanel());
                    dialog.pack();
                    dialog.setLocationRelativeTo(null);
                    dialog.setVisible(true);
                    // JOptionPane.showConfirmDialog(null, a.createPanel(), "centrum.manageGroups", JOptionPane.OK_CANCEL_OPTION);
                }
            });
        }
    
    }