I’m trying to create a login form using Java Swing. But I want the layout to look tighter, but still responsive.
The structure of my project
Project/ └── src ├── GUI │ ├── Control.java │ ├── Main.java │ └── pages │ ├── LoginPanel.java └── Helper └── Helpers.java
This is the picture of the GUI, this is not what I want:
The components in the form
panel are not behaving as I would expect, I want the fields to be close to the labels but not filling the entire space horizontally.
And my code:
LoginPanel
package GUI.pages; import javax.swing.*; public class LoginPanel extends JPanel { // Some labels, button, groups and fields private static JTextField usernameInputField; private static JPasswordField passwordInputField; private static JButton submit; private static JLabel message; private static JButton registerRedirect = new JButton("register"); private static final int PADDING = 30; public LoginPanel() { setLayout(new BorderLayout()); JLabel title = Helpers.generateTitle(); JPanel titleContainer = new JPanel(); titleContainer.setLayout(new FlowLayout(FlowLayout.LEFT, PADDING, PADDING)); titleContainer.add(title); // the username row JLabel usernameLabel = new JLabel("Username: "); usernameInputField = new JTextField(50); // The password row JLabel passwordLabel = new JLabel("Password: "); passwordInputField = new JPasswordField(50); JPanel form = new JPanel(); form.setLayout(new GridBagLayout()); GridBagConstraints c = new GridBagConstraints(); c.gridwidth = 2; c.gridx = 0; c.gridy = 0; c.anchor = GridBagConstraints.WEST; c.insets = new Insets(0,20,0,0); form.add(usernameLabel, c); c = new GridBagConstraints(); c.gridx = 0; c.gridy = 1; c.anchor = GridBagConstraints.WEST; c.insets = new Insets(0,20,0,0); form.add(passwordLabel, c); c = new GridBagConstraints(); c.gridx = 1; c.gridy = 0; c.weightx = 0.1; c.ipadx = 200; JPanel usernameFieldContainer = new JPanel(); usernameFieldContainer.add(usernameInputField); usernameFieldContainer.setSize(new Dimension(usernameInputField.getWidth() + 10, usernameInputField.getHeight() + 10)); form.add(usernameFieldContainer, c); c = new GridBagConstraints(); c.gridx = 1; c.gridy = 1; c.weightx = 0.001; c.weightx = 0.001; c.ipadx = 50; JPanel passwordFieldContainer = new JPanel(); passwordFieldContainer.add(passwordInputField); passwordFieldContainer.setSize(new Dimension(passwordInputField.getWidth() + 10, passwordInputField.getHeight() + 10)); form.add(passwordFieldContainer, c); // Configuring the submit button submit = new JButton("Sign in"); submit.addActionListener(new LoginActionListener()); submit.setActionCommand("login"); JPanel submitContainer = new JPanel(); submitContainer.setLayout(new FlowLayout(FlowLayout.RIGHT, PADDING, PADDING)); submitContainer.add(submit); // adding everything to the layout add(titleContainer, BorderLayout.PAGE_START); add(form, BorderLayout.LINE_START); add(submitContainer, BorderLayout.PAGE_END); } }
Main
package GUI; import javax.swing.*; import GUI.pages.LoginPanel; public class Main extends JFrame { public static void main(String[] args){ JFrame frame = new Main(); } public Main(){ JPanel login_panel = new LoginPanel(); add(login_panel); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true); pack(); } }
This is how I want it to look like(updated):
REM(the title) ________________________________ __________________ Username: [__________________] __________________ Password: [__________________] [Submit button]
Advertisement
Answer
I want the fields to be close to the labels but not filling the entire space horizontally.
public final static int WINDOW_WIDTH = 750; public final static int WINDOW_HEIGHT = 550;
Don’t attempt to set a window size. All Swing components will determine their own preferred size. You add all the components to the frame and the pack()
the frame BEFORE you invoke the setVisible(…) method. The frame will then be sized based on the preferred size of all the components.
private static JLabel usernameLabel; private static JTextField usernameInputField;
Don’t use static variables. That is not how the static keyword should be used.
There is no need to create an instance variable for your labels. You generally only create instance variables when you want the variable to be reference in multiple methods. The label is just for display on the form. The text fields will be reference in the ActionListener of your button, so they should be instance variables.
setSize(400, 400);
Don’t attempt to set the size. The extra vertical height is because you just use 400 as the random height of the frame. The pack() method will determine the preferred size.
usernameInputField = new JTextField(50); ... passwordInputField = new JPasswordField(150);
The number in the constructor will be used to size the text field to contain “W” characters. It is not pixels. So the values you specify are too large.
c.fill = GridBagConstraints.HORIZONTAL;
No need for the “fill” constraint.
form.setMaximumSize(new Dimension(200, passwordInputField.getHeight()));
No need to specify a maximum size.
I would also suggest that your entire layout can be done using the GridBagLayout
.
For the label in the first row you would use a gridwidth = 2
. Same for the button in the last row.
Then you can use the anchor
constraint to control the alignment of the label/button on the row. That is do you want the label centered and the button right aligned.