Reputation: 4062
I'm trying to make a fairly basic panel for adding/editing users in a database. To make this happen, I want to have a number of labels for different fields on the left, and the appropriate controls for that field on the right. (So, the left might say something like "Username", "User Type", "Expiration Date", etc, and the associated right-hand side would have a text panel, a drop down, and a calendar widget.)
The problem I'm running into is that I want these to both line up horizontally (a label and it's associated "control areas" should start at the same line), and vertically (all labels should start along the same vertical line, and all control areas should start on the same vertical line.) Some control areas are larger or smaller than others, though; many consist of only a single text panel, while others have things like radio buttons, calendar widgets, etc, associated with them.
Furthermore, the types of fields needed are changing frequently, and depending on context (such as whether a new user is being created or an old one edited, and the permissions level of the controlling user), some of these fields may be excluded. So, I want something that will largely arrange itself - if I have to set positions very manually, I expect things to break as parts are excluded.
What I'd like to see is a layout manager that will basically let me set coordinates on a flexible grid, and then size the grid automatically to provide minimum space to each element, while still keeping the grid lines straight. That way I could simply keep a list of controls and their associated labels, and build the panel programmatically so that labels/controls are always assigned to the same rows.
I haven't figured out how to do this with any of the layout managers though: GridLayout
seems to require that everything be the same size, and BoxLayout
wants to arrange things either vertically or horizontally but not both. So, I keep finding that either my rows line up but are not aligned neatly vertically, or the wrong labels line up with the wrong controls.
Any advice?
Upvotes: 0
Views: 207
Reputation: 11163
Here's an example, as you can see, there are 2 normal sized rows, 1 medium sized and 1 larger (taller) row in different order, I think this is something similar to what you wanted to do
The height of the row is determined by the ipady
attribute of the GridBagConstraints
, you can read more on How to use GridBagLayout and the docs
I haven't used GridBagLayout
a lot, so there might be some things that could be skipped or improved, but for a matter of having this example, here's the output of the code below:
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class GridBagLayoutExample {
private JPanel contentPane;
private JFrame frame;
private JLabel label;
private JTextField field;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new GridBagLayoutExample().createAndShowGui();
}
});
}
public void createAndShowGui() {
frame = new JFrame("GridBagLayout Example");
contentPane = new JPanel();
contentPane.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
label = new JLabel("A small label");
field = new JTextField();
c.insets = new Insets(0, 10, 0, 10);
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 0;
c.gridx = 0;
c.gridy = 0;
contentPane.add(label, c);
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 0.5;
c.gridx = 2;
c.gridy = 0;
c.gridwidth = 2;
contentPane.add(field, c);
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 0.5;
c.gridx = 0;
c.gridy = 1;
c.ipady = 20;
contentPane.add(new JLabel("Another but much larger JLabel"), c);
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 0.5;
c.gridx = 2;
c.gridy = 1;
c.ipady = 20;
c.gridwidth = 2;
contentPane.add(new JButton("And including a larger JButton"), c);
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 0.5;
c.gridx = 0;
c.gridy = 2;
c.ipady = 60;
contentPane.add(new JLabel("A TALLER ROW!"), c);
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 0.5;
c.gridx = 2;
c.gridy = 2;
c.ipady = 60;
c.gridwidth = 2;
contentPane.add(new JTextField(), c);
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 0.5;
c.gridx = 0;
c.gridy = 3;
c.ipady = 0;
contentPane.add(new JLabel("Another normal row"), c);
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 0.5;
c.gridx = 2;
c.gridy = 3;
c.gridwidth = 2;
contentPane.add(new JTextField(), c);
frame.add(contentPane);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
I hope you have an idea with this in mind now, if you still have doubts, ask another (more specific) question including your mcve
Upvotes: 3
Reputation: 27996
GridBagLayout
is the easiest way to achieve this. It is not the most intuitive layout manager to use: you need to specify a 'constraint' for each component when added. There are ways to specify the position relative to the previous component but I tend to use explicit gridx
and gridy
values to ensure you know exactly where things are going to go. You can have a method that adds the label and component and moves to the next row so that this logic is contained:
private final JPanel pane = new JPanel(new GridBagLayout());
private final GridBagConstraints c = new GridBagConstraints();
private void addLabelledComponent(String label, Component component) {
c.gridx = 0;
pane.add(new JLabel(label), c);
c.gridx = 1;
pane.add(component, c);
c.gridy++;
}
See How To Use GridBagLayout for more details such as defining alignment, padding, spanning rows and columns etc.
Upvotes: 3