I want to make the most basic example of a login application using BorderLayout
(even if I could try CardLayout
, if it's necessary) and fixed component positions for personal future reference.
In my example, I created three panels:
login_page
home_page
exit_page
If the login info is correct, the program switches to home_page
.
If the login info is incorrect, the program switches to exit_page
.
I tested all the possible panel sequence. When I try to got from the first panel to the next one, the components of the next panel seem to get dragged to side, like this:
I believe there is something I am missing while I try to set the layout again at the end of the actionPerformed
method, but several examples I found online used this exact way.
How can I put the components of the next panel to their correct positions?
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class LoginForm extends JFrame implements ActionListener
{
private JFrame frame; //main frame
private JPanel login_page; //3 different panels/pages/states
private JPanel home_page;
private JPanel exit_page;
private JLabel login_label; //login form components
private JLabel username_label;
private JLabel password_label;
private JTextField username_text;
private JPasswordField password_text;
private JButton login_button;
private JLabel home_label; //homepage components
private JButton logout_button;
private JLabel locked_label; //exit page components
private JButton exit_button;
LoginForm() //initialization for the components and panels
{
frame = new JFrame("Login Form frame");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//////////////////////////////////////////////////////
/////////login form components initialization/////////
//////////////////////////////////////////////////////
login_page = new JPanel();
login_label = new JLabel("Login label");
username_label = new JLabel("Username");
password_label = new JLabel("Password");
username_text = new JTextField();
password_text = new JPasswordField();
login_button = new JButton("Login");
login_button.addActionListener(this);
login_label.setBounds(100,30,400,30);
username_label.setBounds(80,70,200,30);
username_text.setBounds(300,70,200,30);
password_label.setBounds(80,110,200,30);
password_text.setBounds(300,110,200,30);
login_button.setBounds(150,160,100,30);
login_page.add(login_label);
login_page.add(username_label);
login_page.add(username_text);
login_page.add(password_label);
login_page.add(password_text);
login_page.add(login_button);
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
//////////home page components initialization/////////
//////////////////////////////////////////////////////
home_page = new JPanel();
home_label = new JLabel("Home label");
logout_button = new JButton("Logout");
logout_button.addActionListener(this);
home_label.setBounds(100,30,400,30);
logout_button.setBounds(150,160,100,30);
home_page.add(home_label);
home_page.add(logout_button);
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
//////////exit page components initialization/////////
//////////////////////////////////////////////////////
exit_page = new JPanel();
locked_label = new JLabel("You are now locked from the database");
exit_button = new JButton("Exit");
exit_button.addActionListener(this);
locked_label.setBounds(100,30,400,30);
exit_button.setBounds(150,160,100,30);
exit_page.add(locked_label);
exit_page.add(exit_button);
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
frame.setContentPane(login_page); //first page to get seen
frame.setSize(550,250); //size of the window
frame.setLayout(new BorderLayout());
frame.setVisible(true);
frame.setResizable(false);
}
@Override
public void actionPerformed(ActionEvent listener)
{
JButton button = (JButton) listener.getSource();
if(button == login_button)
{
String name = username_text.getText();
String password = new String(password_text.getPassword());
if(name.equals("x") && password.equals("x"))
{
frame.remove(login_page);
frame.setContentPane(home_page);
}
else
{
frame.remove(login_page);
frame.setContentPane(exit_page);
}
}
else if(button == logout_button)
{
frame.remove(home_page);
frame.setContentPane(login_page);
}
else if (button == exit_button)
{
frame.dispose();
}
frame.setLayout(new BorderLayout());
frame.validate();
frame.repaint();
}
public static void main(String args[])
{
LoginForm login = new LoginForm();
}
}
but several examples I found online used this exact way.
I doubt it because there are so many problems with the code that it only works by chance.
Lets start by how Swing was designed to be used:
Each panel should use a layout manager. The layout manager will set the size and location of each component added to the panel. The default layout manager for the content pane of the frame is the BorderLayout
. The default layout manager for a JPanel is the FlowLayout
.
The normal order of coding is to create your panel and set the layout manager. Then you add the components to the panel. Then you add the panel to the frame.
Next you invoke pack() and setVisible() on the frame. This will invoke the layout manager for all the panels added to the frame and the components will be displayed logically based on the rules of each layout manager.
Now as the frame is resized components will grow/shrink based on the rules of the layout manager and you have created yourself a nice dynamic GUI.
Now what you are doing:
You are attempting to use setBounds() to set the size and location of each component. The size is just a random guess. You have no idea what the proper size should be. What if you ever want to change the Font to a larger size? Now you will start to get text being truncated. Don't attempt to set bounds of Swing components. Each component has logic to determine its own preferred size.
Next you set the content pane of the frame (which is fine), but then you invoke setLayout() and validate(). Do you even know what those statement do?
The point of using setLayout() is to tell the panel what layout manager to use when you add components to the frame, but then never add any panels to the frame.
Next you use validate() (which should be revalidate() when using Swing). The purpose of that method is to invoke the layout manager. So the layout manager would then reset the size/location of all the components and completely ignore the setBounds() statement you used.
Your code only works by chance because you change the layout to BorderLayout AFTER you added the panel to the frame. Since you never add any components to the frame when it is using the BorderLayout there is nothing for the layout manager to do.
Don't use setBounds().
Use the appropriate layout manager for each of your 3 panels.
Use a CardLayout
on the frame. Then you can just swap each of the above panels as required. Don't try to reinvent the wheel.
Read the Swing tutorial on Layout Mangers for more information and working examples.