Java Swing: How to Implement a Login Screen Before Showing a Jframe

Java Swing: How can I implement a login screen before showing a JFrame?

A simple modal dialog such as a JDialog should work well here. The main GUI which will likely be a JFrame can be invisible when the dialog is called, and then set to visible (assuming that the log-on was successful) once the dialog completes. If the dialog is modal, you'll know exactly when the user has closed the dialog as the code will continue right after the line where you call setVisible(true) on the dialog. Note that the GUI held by a JDialog can be every bit as complex and rich as that held by a JFrame.

Another option is to use one GUI/JFrame but swap views (JPanels) in the main GUI via a CardLayout. This could work quite well and is easy to implement. Check out the CardLayout tutorial for more.

Oh, and welcome to stackoverflow.com!

Java GUI- Set the Login Page to appear before the main Frame

There are lots of problems with your code.

  1. You are shadowing member variables frame and lframe in the constructor of class TestFrame.
JFrame lframe=new JFrame();

and

JFrame frame = new JFrame();

Here lframe and frame are local variables and not the class members.


  1. You are incorrectly initializing class member container.
container = getContentPane();

Class TestFrame extends class javax.swing.JFrame so container actually refers to the content pane of TestFrame when you actually want the content pane of lframe. Hence you are not adding any components to lframe.


  1. The code in your question does not compile since class TestFrame does not correctly implement interface ActionListener since it does not contain a method named actionPerformed.

The below code is your code with my fixes added. Note that I don't have your images, so I added text to the JLabels instead of icons. Also I added a main method – which the code in your question does not have – in order to be able to run the code as a Java application.

import java.awt.Container;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenuBar;
import javax.swing.JOptionPane;
import javax.swing.JPasswordField;
import javax.swing.JTextField;

public class TestFrame extends JFrame implements ActionListener{

private JFrame frame; //main frame
private JFrame lframe; //login frame
private Container container;
private JLabel userLabel;
private JLabel passwordLabel;
private JTextField userTextField;
private JPasswordField passwordField;
private JButton loginButton;
private JButton resetButton;
private JCheckBox showPassword;

/**
* Launch the application.
*/


/**
* Create the application. Rest of the program here.
*/
public TestFrame() {
// container = getContentPane();
userLabel = new JLabel("USERNAME");
passwordLabel = new JLabel("PASSWORD");
userTextField = new JTextField();
passwordField = new JPasswordField();
loginButton = new JButton("LOGIN");
resetButton = new JButton("RESET");
showPassword = new JCheckBox("Show Password");
/*JFrame*/ lframe=new JFrame();
container = lframe.getContentPane(); // ADDED this line
lframe.setTitle("Login BHMS");

/*JFrame*/ frame = new JFrame();
frame.setTitle("Test System");
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new JLabel(/*new ImageIcon("test.png")*/"test.png"));
frame.setResizable(false);
JMenuBar menuBar = new JMenuBar();
frame.setJMenuBar(menuBar);

/**
*
* @Main Page, IGNORE-----------------------------------------------------------------------------------------------------------------
*/

frame.setVisible(true); //the main frame
lframe.setVisible(true); //if the login is successful then the main frame is visible
}

public void login() {
setLayoutManager();
setLocationAndSize();
addComponentsToContainer();
addActionEvent();
lframe.setVisible(true);
}

public void setLayoutManager() {
container.setLayout(null);
}

public void setLocationAndSize() {
lframe.setBounds(500,500,500,500);
userLabel.setBounds(50, 150, 100, 30);
passwordLabel.setBounds(50, 220, 100, 30);
userTextField.setBounds(150, 150, 150, 30);
passwordField.setBounds(150, 220, 150, 30);
showPassword.setBounds(150, 250, 150, 30);
loginButton.setBounds(50, 300, 100, 30);
resetButton.setBounds(200, 300, 100, 30);
}

public void addComponentsToContainer() {
container.add(userLabel);
container.add(passwordLabel);
container.add(userTextField);
container.add(passwordField);
container.add(showPassword);
container.add(loginButton);
container.add(resetButton);

JLabel lblNewLabel = new JLabel("test1.png");
// lblNewLabel.setIcon(new ImageIcon(login.class.getResource("/development/test1.png")));
lblNewLabel.setBounds(106, 10, 204, 113);
getContentPane().add(lblNewLabel);
}

public void addActionEvent() {
loginButton.addActionListener(this);
resetButton.addActionListener(this);
showPassword.addActionListener(this);
}

public void /*loginA*/actionPerformed(ActionEvent e) {
//Coding Part of LOGIN button
if (e.getSource() == loginButton) {
String userText;
String pwdText;
userText = userTextField.getText();
pwdText = passwordField.getText();
if (userText.equalsIgnoreCase("Admin") && pwdText.equalsIgnoreCase("Admin")) {
JOptionPane.showMessageDialog(this, "Login Successful."+" Hello "+userText);
}
else {
JOptionPane.showMessageDialog(this, "Invalid Username or Password");
}
}
//Coding Part of RESET button
if (e.getSource() == resetButton) {
userTextField.setText("");
passwordField.setText("");
}
//Coding Part of showPassword JCheckBox
if (e.getSource() == showPassword) {
if (showPassword.isSelected()) {
passwordField.setEchoChar((char) 0);
} else {
passwordField.setEchoChar('*');
}
}
}

public static void main(String[] args) {
EventQueue.invokeLater(() -> {
new TestFrame().login();
});
}
}

This is how lframe looks when I run the above code. Note that when I run the code, frame appears "behind" lframe and takes up the entire screen.

screen capture

However...

The experts say that a Swing application should only have one JFrame. Hence I suggest that you make lframe a JDialog and not a JFrame. I suggest that you initialize frame but do not make it visible. Only make it visible after the user has successfully logged in.

I also get the impression that you want frame to have a background image. If that is the case, then using a JLabel is not the way to do it. In order to do it, extend class javax.swing.JPanel and override its paintComponent method.

The below code demonstrates. Note that the below code uses layout managers. Also note that file test.png needs to be in the same folder as file TestFrame.class. Also, the below code uses method references.

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenuBar;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JTextField;

public class TestFrame extends JPanel implements Runnable {
private boolean initial;
private char echoChar;
private Image backgroundImage;
private JCheckBox showPassword;
private JDialog lframe; //login frame
private JFrame frame; //main frame
private JPasswordField passwordField;
private JTextField userTextField;

public TestFrame() {
initial = true;
try {
backgroundImage = ImageIO.read(getClass().getResource("test.png"));
}
catch (IOException x) {
x.printStackTrace();
}
}

public void run() {
createAndDisplayGui();
}

protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (initial && backgroundImage != null) {
initial = false;
Container contentPane = frame.getContentPane();
backgroundImage = backgroundImage.getScaledInstance(contentPane.getWidth(),
contentPane.getHeight(),
Image.SCALE_DEFAULT);
}
g.drawImage(backgroundImage, 0, 0, null);
}

private void checkLogin(ActionEvent event) {
String userText = userTextField.getText();
String password = new String(passwordField.getPassword());
if ("Admin".equals(userText) && "Admin".equals(password)) {
lframe.dispose();
frame.setVisible(true);
}
else {
JOptionPane.showMessageDialog(lframe,
"Incorrect username or password.",
"ERROR",
JOptionPane.ERROR_MESSAGE);
}
}

private void createAndDisplayGui() {
frame = new JFrame("Test System");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.add(this);
frame.setResizable(false);
JMenuBar menuBar = new JMenuBar();
frame.setJMenuBar(menuBar);
showLogin();
}

private JPanel createLoginButtons() {
JPanel buttonsPanel = new JPanel();
JButton loginButton = new JButton("LOGIN");
loginButton.addActionListener(this::checkLogin);
JButton resetButton = new JButton("RESET");
resetButton.addActionListener(this::resetLogin);
buttonsPanel.add(loginButton);
buttonsPanel.add(resetButton);
return buttonsPanel;
}

private JPanel createLoginForm() {
JPanel loginForm = new JPanel(new GridBagLayout());
loginForm.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
GridBagConstraints gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.LINE_START;
gbc.insets.bottom = 5;
gbc.insets.left = 5;
gbc.insets.right = 5;
gbc.insets.top = 5;
gbc.gridx = 0;
gbc.gridy = 0;
JLabel userLabel = new JLabel("USERNAME");
loginForm.add(userLabel, gbc);
gbc.gridx = 1;
userTextField = new JTextField(10);
loginForm.add(userTextField, gbc);
gbc.gridx = 0;
gbc.gridy = 1;
JLabel passwordLabel = new JLabel("PASSWORD");
loginForm.add(passwordLabel, gbc);
gbc.gridx = 1;
passwordField = new JPasswordField(10);
echoChar = passwordField.getEchoChar();
loginForm.add(passwordField, gbc);
gbc.gridy = 2;
showPassword = new JCheckBox("Show Password");
showPassword.addActionListener(this::showOrHidePassword);
loginForm.add(showPassword, gbc);
return loginForm;
}

private void resetLogin(ActionEvent event) {
userTextField.setText("");
passwordField.setText(null);
}

private void showLogin() {
lframe = new JDialog(frame, "Login BHMS");
lframe.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
lframe.add(createLoginForm(), BorderLayout.CENTER);
lframe.add(createLoginButtons(), BorderLayout.PAGE_END);
lframe.pack();
lframe.setLocationRelativeTo(null);
lframe.setVisible(true);
}

private void showOrHidePassword(ActionEvent event) {
if (showPassword.isSelected()) {
passwordField.setEchoChar((char) 0);
}
else {
passwordField.setEchoChar(echoChar);
}
}

public static void main(String[] args) {
EventQueue.invokeLater(new TestFrame());
}
}

Login screen in JFrame

You don't have a layout manager set, so the JFrame's Default which is BorderLayout, is adding everything to the center, which means when you add pass, it covers over the user, then when you add the login button, it covers over the pass, so it looks like you only have a login button. In order to get what you want:

add User at top of window
add Pass at middle of window
add Login at bottom of window

An example of the code could be:

launcher.setLayout(new BorderLayout());
launcher.add(user, BorderLayout.NORTH);
launcher.add(pass, BorderLayout.CENTER);
launcher.add(login, BorderLayout.SOUTH);

If you want to make it check login when the button is clicked add an ActionListener to login.

login.addActionListener(new ActionListener(){

public void actionPerformed(ActionEvent e){
//Check login stuff here...

//with maybe something like this?
String sLogin = login.getText();
String sPass = pass.getText();
//Then compare with some other string/data you already have saved somewhere...

}
});

However if you want more exact layout, you can try searching up GridBagLayout

If you want to read more about layouts in general go here: LayoutManagers

How to proceed from login screen to the next screen? JPanel, JFrame?

Depends, but often it's better if you can reuse the same window. Often, you might want to use a JDialog / JOptionPane to handle login. Dialog windows are meant to be more disposable

Java GUI login screen

This:

if(puname.equals(usertxt) && ppaswd.equals(passtxt)) {
MainMenu menu =new MainMenu();
dispose();
}

Needs to go inside of this:

while (scan.hasNext()) {
usertxt = scan.nextLine();
passtxt = scan.nextLine();
}

You're looping through the file with the while loop, but only testing the equality of the Strings after the while loop ends. This won't work as you're finding out.

Java Swing login window not closing

package stackoverflow;

import javax.swing.JFrame;
import javax.swing.WindowConstants;

public class ExitFrame {

public static void main(final String[] args) {
final JFrame f = new JFrame();

// this will do nothing, thus not react to the user trying to close the window
f.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);

// this will only hide the window, as if fsetVisible(false) was called
f.setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE);

// this will actually dispose the window, as if f.dispose() was called
f.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);

// this will shut down the whole JVM, ending your program, as if System.exit(0); was called
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}

}

To help you on your actual problem:

For blocking access to the calling (parent) Window, you should use Dialogs, like the JDialog, set it to modal mode, and give the parent window was parameter.

    final JDialog d = new JDialog(f);
d.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
d.setModal(true);
// add elements
d.setVisible(true); // will block until d gets hidden or disposed.

// code will resume here

You can also just have class MyDialog extends JDialog, like you do with JFrame in your code.

An even more advanced method

is not to implement stuff on JFrames or JDialogs, but simply as JPanel. Why? Because you then can add it anywhere you like, and dont have to worry about the 'external' behaviour.

You can then add that Panel to a JFrame, JWindow, JDialog, another JPanel, and even the JOptionPane with message dialogs etc.

It is a bit harder to implement, because you need to attach the 'external' events of the parent to the JPanel somehow, but once you figure that out it's easy as pie.

Full program example:

I've just implemented a login demo in Swing to show you how I would do it. This serves this question and another one, where I'll post a link to here.

DemoWindow

package stackoverflow.userlogin;

import java.awt.BorderLayout;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JTextField;

import stackoverflow.userlogin.UserLoginPanel.UserCredentials;

public class DemoWindow extends JFrame {
private static final long serialVersionUID = -5431874284425397696L;

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

private final JTextField gTxtStatus = new JTextField();
private final JButton gBtnLogin = new JButton("Log in!");

private User mCurrentUser = null;

public DemoWindow() {
setTitle("Logging in...");
setBounds(100, 100, 200, 200);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setLayout(new BorderLayout());

add(new JLabel("Status:"), BorderLayout.NORTH);

gTxtStatus.setText("Not logged in!");
add(gTxtStatus);

gBtnLogin.addActionListener(al -> runLogin());
add(gBtnLogin, BorderLayout.SOUTH);

setVisible(true);
}

private void runLogin() {
try {
UserCredentials uc = null;
while (true) {
uc = UserLoginPanel.getUserCredentials(this, uc);
if (uc == null) {
gTxtStatus.setText("User login aborted.");
break;
}

final User user = UserManager.getUserByName(uc.mUsername);
if (user == null) {
gTxtStatus.setText("No user with name [" + uc.mUsername + "] found!");
continue;
}

final String hashedPassword = PasswordHasher.hashPassword(uc.mPasswordChars);
final boolean passwordOK = user.matchesPasswordHash(hashedPassword);
if (!passwordOK) {
gTxtStatus.setText("Password mismatch!");
continue;
}

mCurrentUser = user;
gTxtStatus.setText("User logged in: [" + mCurrentUser + "]");
break;
}
} catch (final Exception e) {
JOptionPane.showMessageDialog(this, "Error: " + e, "Error", JOptionPane.ERROR_MESSAGE);
}

}

}

PasswordHasher

package stackoverflow.userlogin;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.util.Arrays;

public class PasswordHasher {

static public final String MY_APP_SALT = PasswordHasher.class.getPackageName();

public static void main(final String[] args) throws IOException {
try (final BufferedReader buffer = new BufferedReader(new InputStreamReader(System.in));) {
while (true) {
System.out.println("Enter password. Enter empy line to end app.");
final String line = buffer.readLine();
if (line == null || line.trim().length() < 1) break;

final String hash = hashPassword(line.toCharArray());
System.out.println("Password: " + line);
System.out.println("Hash: " + hash);
System.out.println();
}
}
System.out.println("\nApp ended.");
}

static public String hashPassword(final char[] pPasswordChars) {
try {
final MessageDigest md = MessageDigest.getInstance("SHA1");
md.reset();

final byte[] saltBuffer = MY_APP_SALT.getBytes("UTF-8");
md.update(saltBuffer);

final byte[] passwordBuffer = charsToBytes(pPasswordChars);
md.update(passwordBuffer);

final byte[] digest = md.digest();
String hexStr = "";
for (int i = 0; i < digest.length; i++) {
hexStr += Integer.toString((digest[i] & 0xff) + 0x100, 16).substring(1);
}
return hexStr;

} catch (final Exception e) {
throw new RuntimeException(e);
}
}
static public byte[] charsToBytes(final char[] pChars) {
final CharBuffer charBuffer = CharBuffer.wrap(pChars);
final ByteBuffer byteBuffer = Charset.forName("UTF-8").encode(charBuffer);
final byte[] bytes = Arrays.copyOfRange(byteBuffer.array(), byteBuffer.position(), byteBuffer.limit());
Arrays.fill(byteBuffer.array(), (byte) 0); // clear sensitive data
return bytes;
}

}

User

package stackoverflow.userlogin;

import java.util.Objects;

public class User {
private final String mUsername;
private final String mPasswordHash;

public User(final String pUsername, final String pPasswordHash) {
mUsername = pUsername;
mPasswordHash = pPasswordHash;
}

public User(final String pLine) {
final String[] args = pLine.split(",");
mUsername = args[0];
mPasswordHash = args[1];
}

public String getUsername() {
return mUsername;
}
public boolean matchesUsername(final String pUsername) {
return stringMatches(mUsername, pUsername);
}
public boolean matchesPasswordHash(final String pPasswordHash) {
return stringMatches(mPasswordHash, pPasswordHash);
}
static public boolean stringMatches(final String pString1, final String pString2) {
final String s1 = pString1 == null ? null : pString1.trim().toLowerCase();
final String s2 = pString2 == null ? null : pString2.trim().toLowerCase();
return Objects.equals(s1, s2);
}

@Override public String toString() {
return mUsername;
}

}

UserLoginPanel

package stackoverflow.userlogin;

import java.awt.BorderLayout;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JTextField;

public class UserLoginPanel extends JPanel {
private static final long serialVersionUID = -2478650783143301888L;

static public class UserCredentials {
public final String mUsername;
public final char[] mPasswordChars;
public UserCredentials(final String pUsername, final char[] pPasswordChar) {
mUsername = pUsername;
mPasswordChars = pPasswordChar;
}
public void clearPassword() {
for (int i = 0; i < mPasswordChars.length; i++) {
mPasswordChars[i] = 0;
}
}
}

static public UserCredentials getUserCredentials(final Window pParent, final UserCredentials pDefaultCredentials) {
final JDialog d = new JDialog(pParent);
d.setTitle("Please log in");
final UserLoginPanel panel = new UserLoginPanel(ae -> d.dispose(), pDefaultCredentials);
d.setModal(true);
d.add(panel);
d.pack();
d.setVisible(true);
d.dispose();
return panel.getReturnValue();
}

private final JTextField gTxtUsername = new JTextField();
private final JPasswordField gTxtPassword = new JPasswordField();
private final JButton gBtnCancel = new JButton("Cancel");
private final JButton gBtnOK = new JButton("OK");

private final ActionListener mActionListener;

private UserCredentials mReturnValue = null;

public UserLoginPanel(final ActionListener pActionListener, final UserCredentials pDefaultCredentials) {
mActionListener = pActionListener;
mReturnValue = pDefaultCredentials;

setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));

add(new JLabel("Username:"));
if (mReturnValue != null) gTxtUsername.setText(mReturnValue.mUsername);
add(gTxtUsername);

add(new JLabel("Password:"));
if (mReturnValue != null) gTxtPassword.setText(new String(mReturnValue.mPasswordChars));
add(gTxtPassword);

{
final JPanel hor = new JPanel();

gBtnCancel.addActionListener(al -> gBtnCancel_click());
hor.add(gBtnCancel, BorderLayout.WEST);

gBtnOK.addActionListener(al -> gBtnOK_click());
hor.add(gBtnOK, BorderLayout.EAST);

add(hor);
}
}

private void gBtnOK_click() {
mReturnValue = new UserCredentials(gTxtUsername.getText(), gTxtPassword.getPassword());
mActionListener.actionPerformed(new ActionEvent(this, 0, "ok"));
}

private void gBtnCancel_click() {
mReturnValue = null;
mActionListener.actionPerformed(new ActionEvent(this, -1, "cancel"));
}

public UserCredentials getReturnValue() {
return mReturnValue;
}

}

UserManager

package stackoverflow.userlogin;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.stream.Collectors;

public class UserManager {

static public final String USER_DB_FILENAME = "user-database.txt";

static private List<User> sLoadedUsers;

static public List<User> getAllUsers() throws IOException {
if (sLoadedUsers == null) {
final Path file = Paths.get(USER_DB_FILENAME);
try {
sLoadedUsers = Files.lines(file)
.filter(p -> p != null && !p.isEmpty() && p.contains(","))
.map(p -> new User(p))
.collect(Collectors.toList());
} catch (final Exception e) {
Files.write(file, "username,passwordhash".getBytes()); // create default file
throw e;
}
}
return sLoadedUsers;
}
static public User getUserByName(final String pUsername) throws IOException {
for (final User user : getAllUsers()) {
if (user.matchesUsername(pUsername)) return user;
}
return null;
}

}

My user-database.txt file:

Peter,744ed63cee96b0542fcde52b63410ef6a9b8ae63

contains the user 'Peter' with the password 'Lustig'.

Steps to run:

  1. Run the DemoWindow once. Click on "Log in!" and then in the dialog "OK". An error will occur and the user database file user-database.txt will be created.
  2. Run the PasswordHasher, and generate a hash. Past that hash into the user database file.
  3. Run DemoWindow again. This time play with several things, like enetering no username, no password, wrong username, wrong password, proper stuff.


Related Topics



Leave a reply



Submit