I working on assignment to create bank management GUI with swing. Right now I'm messing with login. Instead of using JDialog as many may suggest to use I used JFrame.

In case of any error messages on login attempt I wanted to display error above all previously displayed content, however that will end up with message to be displayed next to original content

However if I swap order of GridBagConstrains , to show message at the bottom, the layout is correct :?:

I must be doing something somewhere wrong when I either clear or re-build the frame. Also JFrame should make change in size but frame doesn't seems to get affected by this. There is a flick of larger frame, but it never change the size.

private Dimension dimLF = new Dimension(250, 150);
private Dimension dimLFErr = new Dimension(500, 500);

So the question is what I'm doing wrong?
Here is the section of code that "takes" care of this

public void runLoginFrame()
    {
        lf.setTitle("BMS - Login");
        if(errJP.getComponentCount()!= 0)
        {
            lf.getContentPane().remove(errJP);
        }
        if (errMsg)
        {
            setErrorMsg();
            setLoginLayout();
            lf.setSize(dimLFErr);
            lf.setLayout(gbag);
            gbc.gridx = 0;
            gbc.gridy = 1; // correct layout change to zero
            gbag.setConstraints(loginJP, gbc);
            gbc.gridx = 0;
            gbc.gridy = 0; // correct layout change to one
            gbag.setConstraints(errJP, gbc);
            lf.getContentPane().add(errJP);
            lf.getContentPane().add(loginJP);

        }
        else
        {
            lf.setSize(dimLF);
            setLoginLayout();
            lf.getContentPane().add(loginJP);

        }
        lf.setLocation(rp.resultPosition(dimLF));
        lf.setResizable(false);
        lf.addWindowListener(this);
        lf.setVisible(true);
        lf.pack();
    }


PS: If additional code need it let me know

Recommended Answers

All 8 Replies

Post the "loginJP" and "errJP" classes as well. Preferably with just their UI component setup portions.

private void setLoginLayout()
    {
        loginJP.removeAll(); //clean start in case JPanel already in use
        loginJP.setLayout(gbag);

        JPanel usrPanel = new JPanel();
        JLabel usrLabel = new JLabel("Username:");
        usrTF = new JTextField(10);
        usrTF.setToolTipText("Please enter your username.");
        usrPanel.add(usrLabel);
        usrPanel.add(usrTF);

        JPanel passPanel = new JPanel();
        JLabel passLabel = new JLabel("Password:");
        passPF = new JPasswordField(10);
        passPF.setToolTipText("Please enter your password.");
        passPanel.add(passLabel);
        passPanel.add(passPF);

        JPanel btnPanel = new JPanel();
        loginBtn = new JButton("Login");
        loginBtn.setPreferredSize(new Dimension(90, 30));
        loginBtn.addActionListener(this);
        loginBtn.setToolTipText("Press the button to log in to Bank Managment System.");
        clearBtn = new JButton("Clear");
        clearBtn.setPreferredSize(new Dimension(90, 30));
        clearBtn.addActionListener(this);
        clearBtn.setToolTipText("Press the button to clear the username and password text fileds.");
        btnPanel.add(loginBtn);
        btnPanel.add(clearBtn);

        gbc.gridx = 0;
        gbc.gridy = 0;
        gbag.setConstraints(usrPanel, gbc);
        gbc.gridx = 0;
        gbc.gridy = 1;
        gbag.setConstraints(passPanel, gbc);
        gbc.gridx = 0;
        gbc.gridy = 2;
        gbag.setConstraints(btnPanel, gbc);

        loginJP.add(usrPanel);
        loginJP.add(passPanel);
        loginJP.add(btnPanel);
    }
private void setErrorMsg()
    {
        errJP.removeAll(); //clean start in case JPanel already in use
        errJP.setLayout(new FlowLayout (FlowLayout.CENTER));
        errLabel = new JLabel(errStr);
        errLabel.setForeground(Color.RED);
        errJP.add(errLabel);
    }

Ok, I can't fiddle around with your exact code, because there were several parts that weren't in all that was posted above. A couple things come to mind though. First, it looks like you're sharing a single GridBagLayout manager ("gbag") among several panels, but using as if each was separate. That could definitely cause unexpected results.

On the sizing issue, Swing won't resize your JFrame by default if it's contents change size. You would need to use setSize() or pack() to resize that top-level window.

I think you would have an easier time managing all of those components if you separated the panels into their own classes, a bit like this

import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JTextField;

public class LoginFrame extends JFrame {

    private Dimension dimLF = new Dimension(250, 200);
    LoginPanel loginJP;
    ErrorPanel errJP;

    public LoginFrame() {
        setTitle("BMS - Login");
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLayout(new GridBagLayout());

        GridBagConstraints gbc = new GridBagConstraints();

        loginJP = new LoginPanel();
        gbc.gridx = 0;
        gbc.gridy = 1;
        getContentPane().add(loginJP, gbc);

        errJP = new ErrorPanel();
        gbc.gridx = 0;
        gbc.gridy = 0;
        getContentPane().add(errJP, gbc);

        setSize(dimLF);

        setResizable(false);
        setVisible(true);

    }

    /** one panel for login components */
    class LoginPanel extends JPanel {

        public LoginPanel() {
            setLayout(new GridBagLayout());

            GridBagConstraints gbc = new GridBagConstraints();
            
            // probably don't need separate panels for each pair here
            JPanel usrPanel = new JPanel();
            JLabel usrLabel = new JLabel("Username:");
            JTextField usrTF = new JTextField(10);
            usrTF.setToolTipText("Please enter your username.");
            usrPanel.add(usrLabel);
            usrPanel.add(usrTF);

            JPanel passPanel = new JPanel();
            JLabel passLabel = new JLabel("Password:");
            JPasswordField passPF = new JPasswordField(10);
            passPF.setToolTipText("Please enter your password.");
            passPanel.add(passLabel);
            passPanel.add(passPF);

            JPanel btnPanel = new JPanel();
            JButton loginBtn = new JButton("Login");
            loginBtn.setPreferredSize(new Dimension(90, 30));
            loginBtn.setToolTipText("Press the button to log in to Bank Managment System.");
            loginBtn.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    // I just put this call in here to turn err msg on
                    errJP.setErrMsg("error occurred");
                }
            });

            JButton clearBtn = new JButton("Clear");
            clearBtn.setPreferredSize(new Dimension(90, 30));
            clearBtn.setToolTipText("Press the button to clear the username and password text fileds.");
            clearBtn.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    // I just put this call in here to turn err msg off
                    errJP.setErrMsg("");
                }
            });
            btnPanel.add(loginBtn);
            btnPanel.add(clearBtn);

            gbc.gridx = 0;
            gbc.gridy = 0;
            add(usrPanel, gbc);
            
            gbc.gridx = 0;
            gbc.gridy = 1;
            add(passPanel, gbc);
            
            gbc.gridx = 0;
            gbc.gridy = 2;
            add(btnPanel, gbc);
        }
    }

    /** another panel just for the error message(s) */
    class ErrorPanel extends JPanel {

        String errStr = "";
        JLabel errLabel;

        public ErrorPanel() {
            setLayout(new FlowLayout(FlowLayout.CENTER));
            errLabel = new JLabel(errStr);
            errLabel.setForeground(Color.RED);
            add(errLabel);
        }

        public void setErrMsg(String msg) {
            errStr = msg;
            errLabel.setText(errStr);
        }
    }
    
    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new LoginFrame();
            }
        });
    }

}

I'm already making changes to see if that solve the issue.

I have side question. Passing control from frame to frame. In the past what I did is declare a frame, then pass it as an argument from frame to frame and after that dispose of previous holder so only one frame is visible at time. It was awkward solution but it worked.
Can you suggest better solution?

A separate controlling class to handle those transitions is cleaner to manage. The frames themselves are just visual mechanisms for interacting with the data/process, so it's really just data or state information that needs to be passed to the new frame (or a reference to the aforementioned controlling class that is actually controlling the process state).

I'm getting brain-dead would you mind small code example?

Ok, building a bit on the LoginFrame code above, here is a tiny framework that manages a login frame and a main app frame that is shown for a valid user. It doesn't do much, but should illustrate the point a bit.

I threw the other classes in at the bottom so it could be pasted into and run from a single file. Obviously, you would want to separate them to appropriate top-level public classes.

The only valid login is "Bob","12345". (And don't take this to be an example of managing secure logins, the MainApp controller is the point of the code :P )

import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JTextField;

public class LoginFrame extends JFrame {

    private Dimension dimLF = new Dimension(250, 200);
    LoginPanel loginJP;
    ErrorPanel errJP;
    
    MainApp mainApp;

    public LoginFrame(MainApp mainApp) {
        super();
        this.mainApp = mainApp;
        
        setTitle("BMS - Login");
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLayout(new GridBagLayout());

        GridBagConstraints gbc = new GridBagConstraints();

        loginJP = new LoginPanel();
        gbc.gridx = 0;
        gbc.gridy = 1;
        getContentPane().add(loginJP, gbc);

        errJP = new ErrorPanel();
        gbc.gridx = 0;
        gbc.gridy = 0;
        getContentPane().add(errJP, gbc);

        setSize(dimLF);

        setResizable(false);
        setVisible(true);

    }

    class LoginPanel extends JPanel {
        LoginCredentials credentials;
        final JTextField usrTF;
        final JPasswordField passPF;
        
        public LoginPanel() {
            setLayout(new GridBagLayout());

            GridBagConstraints gbc = new GridBagConstraints();
            
            JPanel usrPanel = new JPanel();
            JLabel usrLabel = new JLabel("Username:");
            usrTF = new JTextField(10);
            usrTF.setToolTipText("Please enter your username.");
            usrPanel.add(usrLabel);
            usrPanel.add(usrTF);

            JPanel passPanel = new JPanel();
            JLabel passLabel = new JLabel("Password:");
            passPF = new JPasswordField(10);
            passPF.setToolTipText("Please enter your password.");
            passPanel.add(passLabel);
            passPanel.add(passPF);

            JPanel btnPanel = new JPanel();
            JButton loginBtn = new JButton("Login");
            loginBtn.setPreferredSize(new Dimension(90, 30));
            loginBtn.setToolTipText("Press the button to log in to Bank Managment System.");
            loginBtn.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    validateLogin();
                }
            });

            JButton clearBtn = new JButton("Clear");
            clearBtn.setPreferredSize(new Dimension(90, 30));
            clearBtn.setToolTipText("Press the button to clear the username and password text fileds.");
            clearBtn.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    errJP.setErrMsg("");
                    usrTF.setText("");
                    passPF.setText("");
                }
            });
            btnPanel.add(loginBtn);
            btnPanel.add(clearBtn);

            gbc.gridx = 0;
            gbc.gridy = 0;
            add(usrPanel, gbc);
            
            gbc.gridx = 0;
            gbc.gridy = 1;
            add(passPanel, gbc);
            
            gbc.gridx = 0;
            gbc.gridy = 2;
            add(btnPanel, gbc);
        }
        
        private void validateLogin() {
            String user = usrTF.getText();
            credentials = new LoginCredentials(user);
            char[] pwd = passPF.getPassword();
            if (credentials.validate(pwd)) {
                // valid user - set credentials on MainApp and close
                mainApp.setUserCredentials(credentials);
                dispose();
            } else {
                errJP.setErrMsg("Invalid login");
            }
        }
    }

    class ErrorPanel extends JPanel {

        String errStr = "";
        JLabel errLabel;

        public ErrorPanel() {
            setLayout(new FlowLayout(FlowLayout.CENTER));
            errLabel = new JLabel(errStr);
            errLabel.setForeground(Color.RED);
            add(errLabel);
        }

        public void setErrMsg(String msg) {
            errStr = msg;
            errLabel.setText(errStr);
        }
    }
    
    public static void main(String args[]) {
        new MainApp();
    }
}

/** Main application class that coordinates 
 * the data and process transitions. 
 */
class MainApp {
    private LoginCredentials userCredentials;

    public MainApp(){
        logIn();
    }
    
    private void logIn() {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new LoginFrame(MainApp.this);
            }
        });
    }
    
    public void setUserCredentials(LoginCredentials userCredentials) {
        this.userCredentials = userCredentials;
        if (userCredentials.isLoggedIn()){
            // valid user logged in - show MainFrame
            showMainFrame();
        } else {
            logIn();
        }
    }

    public LoginCredentials getUserCredentials() {
        return userCredentials;
    }

    private void showMainFrame() {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new MainFrame(MainApp.this);
            }
        });
    }
    
}

/** small class for user credentials.
 * - NOT REALLY SECURE - just for example
 */
class LoginCredentials{
    private String user;
    private boolean loggedIn;
    
    public LoginCredentials(String user){
        this.user = user;
    }

    public String getUser() {
        return user;
    }

    public boolean isLoggedIn() {
        return loggedIn;
    }

    /** validate a user named "Bob" with a password "12345"
     * (Amazing, I have the same combination on my luggage...)
     */
    public boolean validate(char[] pwd){
        if ("Bob".equals(user) && pwd != null){
            if ("12345".equals(String.valueOf(pwd))){
                loggedIn = true;
                return true;
            }
        }
        return false;
    }
}

/** Main program frame for a logged in user */
class MainFrame extends JFrame{
    MainApp app;
    
    public MainFrame(MainApp app){
        super("Main Frame");
        this.app = app;
        initComponents();
        setVisible(true);
    }

    private void initComponents() {
        JPanel somePanel = new JPanel();
        String greeting = " Hi "+ app.getUserCredentials().getUser();
        JLabel label = new JLabel(greeting);
        somePanel.add(label);
        getContentPane().add(somePanel);
        
        setSize(300, 300);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
    }
    
}
commented: What would the Java forum be without you? +9
commented: Another great example +12
commented: You're a hero. +5

Hmm, I was not so far from your solution. I just got stuck with return of possible error message. You example provided another solution. Sometimes I still over-kill the logic instead of doing it simple way.

Thank you for your help Ezzaral. Two issues solved.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.