'Java Swing login window not closing
so I'm new to swing on java and I'm trying to make a login window as a precursor to a program. The login window is quite standard, it has a password and user input, a login button, and an x on the top right. However, I'm trying to make it so that the user cannot interact with the main program until they've inputted the correct login data. However, while the setenabled(false) function has allowed me to prevent access to the main program, after the user enters the correct info, nothing happens and the login screen remains.
in my login class I have an loggedin boolean that is true if the right input is detected. however, the setenabled(true) doesn't seem to be executing, and the login window doesn't seem to be closing after the right input is entered. This is my actionperformed method from my login class:
Does anyone know why this is? Is my this.setDefaultCloseOperation(this.EXIT_ON_CLOSE); not doing what I think it should be doing? Does it not just close the current window (the login window) thus giving the user access to the main program?
Solution 1:[1]
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:
- 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.txtwill be created. - Run the PasswordHasher, and generate a hash. Past that hash into the user database file.
- Run DemoWindow again. This time play with several things, like enetering no username, no password, wrong username, wrong password, proper stuff.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
