Positioning components in Swing GUIs

Saad Attieh picture Saad Attieh · Dec 26, 2012 · Viewed 40.9k times · Source

I have some questions on positioning components and some questions on text fields and text areas (Java Swing). Any help is greatly appreciated.

Right now I am trying to have two text fields beside each other with a different label above each describing what that text field does. To achieve this I have placed them in a GridLayout(2, 2).

  1. Is this the best way? It is the only way I know to have a label directly over another component. Is there a better way? What about if there is just one label above one button. Is it sensible to position this through a GridLayout(2, 1)? I am visually impaired so I do not think positioning buttons just by their pixel position is an option unless there is a simple way to place components at a relative number of pixels to another component.

  2. That leads me to my next question. What is the best way to have the same UI as above but with another component (button) centered under it. Essentially the UI should compose of two Named text fields with a calculate button under. The way I did this is by putting the above components in a panel, and adding that plus the calculate button to a surrounding panel with a GridLayout(2, 1). The problem is that the button becomes as big as the panel above it (I'm assuming). How can I adjust this and still have the button perfectly aligned under the panel of text fields/labels? Similarly with labels above text areas. The label should be small but have a larger space for the text area under.

  3. (text field): Again referring to the UI above, if the user types many characters into the first text field, will the letters go over the text field on the right? If so how can I prevent this?

  4. If I append text to a text area and it is already full, will it automatically allow the user to scroll? If not what is a simple way to make the text area scrollable?

  5. Right now I am not setting a size of the text area. Does it just grow as I add text? Does it have a default size as in number of characters?

Answer

Eng.Fouad picture Eng.Fouad · Dec 26, 2012

Right now I am trying to have two text fields beside each other with a different label above each describing what that textfield does. To achieve this I have placed them in a GridLayout(2, 2). Is this the best way? It is the only way I know to have a label directly over another component. Is there a better way? What about if there is just one label above one button. Is it sensible to position this through a GridLayout(2, 1)?

Myself, I always do it via nested panels with BorderLayout. For example:

enter image description here

JFrame frame = new JFrame("The Title");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

JPanel panOuter = new JPanel(new BorderLayout());
JPanel panLeft = new JPanel(new BorderLayout());
panLeft.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
JPanel panRight = new JPanel(new BorderLayout());
panRight.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));

panOuter.add(panLeft, BorderLayout.WEST);
panOuter.add(panRight, BorderLayout.EAST);

JLabel lblLeft = new JLabel("Label 1", JLabel.CENTER);
JLabel lblRight = new JLabel("Label 2", JLabel.CENTER);

JTextField txtLeft = new JTextField(10);
JTextField txtLright = new JTextField(10);

panLeft.add(lblLeft, BorderLayout.NORTH);
panLeft.add(txtLeft, BorderLayout.CENTER);

panRight.add(lblRight, BorderLayout.NORTH);
panRight.add(txtLright, BorderLayout.CENTER);

frame.setContentPane(panOuter);
frame.pack();
frame.setVisible(true);

Note that, you can manipulate the gaps between the components with setting empty borders. Also, you may use BorderLayout.LINE_START and BorderLayout.LINE_END instead of using BorderLayout.WEST and BorderLayout.EAST, and this will add support for RTL languages (e.g Arabic).


That leads me to my next question. What is the best way to have the same UI as above but with another component (button) centred under it. Essentially the UI should compose of two Named text fields with a calculate button under. The way I did this is by putting the above components in a panel, and adding that plus the calculate button to a surrounding panel with a GridLayout(2, 1). The problem is that the button becomes as big as the panel above it (I'm assuming). How can I adjust this and still have the button perfectly aligned under the panel of textfields/labels?

I would do it via nested panels as I did earlier, but now the bottom panel has a FlowLayout layout manager to get a good size for the button:

enter image description here

JFrame frame = new JFrame("The Title");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

JPanel panOuter = new JPanel(new BorderLayout());
JPanel panLeft = new JPanel(new BorderLayout());
panLeft.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
JPanel panRight = new JPanel(new BorderLayout());
panRight.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
JPanel panBottom = new JPanel(); // default is FlowLayout
panBottom.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));

panOuter.add(panLeft, BorderLayout.WEST);
panOuter.add(panRight, BorderLayout.EAST);
panOuter.add(panBottom, BorderLayout.SOUTH);

JLabel lblLeft = new JLabel("Label 1", JLabel.CENTER);
JLabel lblRight = new JLabel("Label 2", JLabel.CENTER);

JTextField txtLeft = new JTextField(10);
JTextField txtLright = new JTextField(10);

JButton btnBottom = new JButton("Press it!");

panLeft.add(lblLeft, BorderLayout.NORTH);
panLeft.add(txtLeft, BorderLayout.CENTER);

panRight.add(lblRight, BorderLayout.NORTH);
panRight.add(txtLright, BorderLayout.CENTER);

panBottom.add(btnBottom);

frame.setContentPane(panOuter);
frame.pack();
frame.setVisible(true);

Similarly with labels above text areas. The label should be small but have a larger space for the text area under.

I would suggest you to use TitledBorder:

enter image description here

JFrame frame = new JFrame("The Title");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

JPanel panOuter = new JPanel(new BorderLayout());
JPanel panLeft = new JPanel(new BorderLayout());
panLeft.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
JPanel panRight = new JPanel(new BorderLayout());
panRight.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
JPanel panBottom = new JPanel(); // default is FlowLayout
panBottom.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));

JPanel panInput = new JPanel(new BorderLayout());
panInput.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
JPanel panConsole = new JPanel(new BorderLayout());

Border outsideBorder = BorderFactory.createEmptyBorder(5, 5, 5, 5);
Border insideBorder = BorderFactory.createTitledBorder("The Console");
Border theBorder = BorderFactory.createCompoundBorder(outsideBorder, insideBorder);
panConsole.setBorder(theBorder);

panInput.add(panLeft, BorderLayout.WEST);
panInput.add(panRight, BorderLayout.EAST);
panInput.add(panBottom, BorderLayout.SOUTH);

panOuter.add(panInput, BorderLayout.NORTH);
panOuter.add(panConsole, BorderLayout.CENTER);

JLabel lblLeft = new JLabel("Label 1", JLabel.CENTER);
JLabel lblRight = new JLabel("Label 2", JLabel.CENTER);

JTextField txtLeft = new JTextField(10);
JTextField txtLright = new JTextField(10);

JButton btnBottom = new JButton("Press it!");

JTextArea txtConsole = new JTextArea(5, 10);

panLeft.add(lblLeft, BorderLayout.NORTH);
panLeft.add(txtLeft, BorderLayout.CENTER);

panRight.add(lblRight, BorderLayout.NORTH);
panRight.add(txtLright, BorderLayout.CENTER);

panBottom.add(btnBottom);

panConsole.add(txtConsole, BorderLayout.CENTER);

frame.setContentPane(panOuter);
frame.pack();
frame.setVisible(true);

third (text field): Again referring to the UI above, if the user types many characters into the first text field, will the letters go over the text field on the right? If so how can I prevent this?

Try the above code, and see how it acts :)


Fourth: If I append text to a text area and it is already full, will it automatically allow the user to scroll? If not what is a simple way to make the text area scrollable?

You need to use something called JScrollPane:

enter image description here

JFrame frame = new JFrame("The Title");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

JPanel panOuter = new JPanel(new BorderLayout());
JPanel panLeft = new JPanel(new BorderLayout());
panLeft.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
JPanel panRight = new JPanel(new BorderLayout());
panRight.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
JPanel panBottom = new JPanel(); // default is FlowLayout
panBottom.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));

JPanel panInput = new JPanel(new BorderLayout());
panInput.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
JPanel panConsole = new JPanel(new BorderLayout());

Border outsideBorder = BorderFactory.createEmptyBorder(5, 5, 5, 5);
Border insideBorder = BorderFactory.createTitledBorder("The Console");
Border theBorder = BorderFactory.createCompoundBorder(outsideBorder, insideBorder);
panConsole.setBorder(theBorder);

panInput.add(panLeft, BorderLayout.WEST);
panInput.add(panRight, BorderLayout.EAST);
panInput.add(panBottom, BorderLayout.SOUTH);

panOuter.add(panInput, BorderLayout.NORTH);
panOuter.add(panConsole, BorderLayout.CENTER);

JLabel lblLeft = new JLabel("Label 1", JLabel.CENTER);
JLabel lblRight = new JLabel("Label 2", JLabel.CENTER);

JTextField txtLeft = new JTextField(10);
JTextField txtLright = new JTextField(10);

JButton btnBottom = new JButton("Press it!");

JTextArea txtConsole = new JTextArea(5, 10);

JScrollPane srcPane = new JScrollPane(txtConsole,
            JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
            JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);

panLeft.add(lblLeft, BorderLayout.NORTH);
panLeft.add(txtLeft, BorderLayout.CENTER);

panRight.add(lblRight, BorderLayout.NORTH);
panRight.add(txtLright, BorderLayout.CENTER);

panBottom.add(btnBottom);

panConsole.add(srcPane, BorderLayout.CENTER);

frame.setContentPane(panOuter);
frame.pack();
frame.setVisible(true);

I hope I answered all of your questions :)