Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Positioning components in Swing GUIs

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?

like image 816
Saad Attieh Avatar asked Dec 26 '12 22:12

Saad Attieh


People also ask

What are the various components of Swing explain?

Swing in java is part of the Java foundation class, which is lightweight and platform-independent. It is used for creating window-based applications. It includes components like button, scroll bar, text field, etc. Putting together all these components makes a graphical user interface.

Which of these are components of Swing?

Swing has a wide range of various components, including buttons, check boxes, sliders, and list boxes. In this part of the Swing tutorial, we will present JButton , JLabel , JTextField , and JPasswordField .

Which types of components are used in designing Swing based GUI?

Explanation: All the components in swing like JButton, JComboBox, JList, JLabel are inherited from the JComponent class which can be added to the container classes. Containers are the windows like frame and dialog boxes. Basic swing components are the building blocks of any gui application.


2 Answers

There are a number of layout managers that might be capable of providing you with what you need.

  • MigLayout
  • JGoodies FormLayout
  • GridBagLayout

For, GridBagLayout would be my choice (I'm biased, as I've been using this layout manager for the past 12 years ;))

enter image description here

public class TestLayout17 {

    public static void main(String[] args) {
        new TestLayout17();
    }

    public TestLayout17() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        public TestPane() {
            setLayout(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridx = 0;
            gbc.gridy = 0;
            gbc.insets = new Insets(2, 2, 2, 2);

            add(new JLabel("Label 1"), gbc);
            gbc.gridx++;
            add(new JLabel("Label 2"), gbc);

            gbc.gridx = 0;
            gbc.gridy++;
            gbc.fill = GridBagConstraints.HORIZONTAL;
            add(new JTextField(10), gbc);
            gbc.gridx++;
            add(new JTextField(10), gbc);

            gbc.gridx = 0;
            gbc.gridy++;
            gbc.fill = GridBagConstraints.NONE;
            gbc.gridwidth = 2;
            add(new JButton("Click"), gbc);

        }

    }

}

I also agree with Eng.Fouad's suggestion of using compound containers to make your life easier in the long run

You might find Laying Out Components Within a Container a worth while read.

like image 179
MadProgrammer Avatar answered Oct 22 '22 23:10

MadProgrammer


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 :)

like image 42
Eng.Fouad Avatar answered Oct 22 '22 22:10

Eng.Fouad