0

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:

enter image description here enter image description here

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();
    }
}
Coursal
  • 1,387
  • 4
  • 17
  • 32

3 Answers3

0

your problem might be giving frame.setSize(550,250);

while using layout it is better to use pack() after adding all the components and panels

U X
  • 121
  • 1
  • 1
  • 6
  • I though so too, at first. But I used pack() and it just squishes the components to one line and the problem with the next panel continues to exist. – Coursal May 03 '18 at 12:02
  • well, I have mostly use gridbag layout, you can give min width and height with it and use glues to fill the spaces. – U X May 03 '18 at 12:06
0

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:

  1. 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.

  2. 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.

  3. 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.

  4. 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:

  1. 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.

  2. 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?

  3. 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.

  4. 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.

  5. 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.

So the solution is:

  1. Don't use setBounds().

  2. Use the appropriate layout manager for each of your 3 panels.

  3. 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.

  4. Read the Swing tutorial on Layout Mangers for more information and working examples.

camickr
  • 321,443
  • 19
  • 166
  • 288
-1

set the layout of all your JPanels to null. By default, FlowLayout will be set, which is causing the problem.

add login_page.setLayout(null) after you initialize it.

add home_page.setLayout(null) after you initialize it.

add exit_page.setLayout(null) after you initialize it.

this should solve your problem. Although this is a quick solution to the problem, this is not a proper solution.

Setting a null layout is not preferable in java swings because:

A layout manager makes it easier to adjust to look-and-feel-dependent component appearances, to different font sizes, to a container's changing size, and to different locales. Layout managers also can be reused easily by other containers, as well as other programs

So always use a layout manager. So instead of using the setBounds() statement to set the location of the components manually, use a layout manager to position your components. Refer here for more information on how to use various layout managers. I would prefer a GridBagLayout here, since it is more flexible.

Ashwin K Kumar
  • 113
  • 1
  • 9
  • (1-) Don't use a null layout. Swing was designed to be used with layout managers (for too many reasons to list here). Use the appropriate layout manager (or combination of nested layout managers) for the desired layout. `By default, FlowLayout will be set, which is causing the problem.` - that will not cause the problem. The FlowLayout displays all components on the same line. They would not be squished like that on multiple lines. – camickr May 03 '18 at 14:21
  • @camickr Since he is using `setBounds()` to position the components individually, a `FlowLayout` will not work here. `FlowLayout` and `setBounds()` dont go with each other, and the squishing happens due to the `FlowLayout` only.More info on this here: https://stackoverflow.com/questions/25258318/flowlayout-in-conjection-with-setbounds?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa So, although a null layout is not preferable, this is a quick solution to the problem. – Ashwin K Kumar May 04 '18 at 05:33
  • As I suggested in my answer there are so many problems with the code that you can't really say there is one problem. The result you see is not because of the FlowLayout on the panel. For example if you just comment out `frame.setLayout(new BorderLayout());` from the ActionListener then you will see the component displayed in a FlowLayout. The layout manager overrides setBounds(). However, something strange is going on because components are added tot he frame BEFORE the layout managers is set. Again, the only proper answer is to use layout managers and don't try to find a hack solution. – camickr May 04 '18 at 14:37