我用Java Swing编写了一个库登录页面并尝试运行它。该页面可以正常运行,但是当我输入任何用户名,选择一种类型并按登录时,它会引发AWT-EventQueue-0: NullPointerException
。
Library 类反序列化包含用户和书籍信息的两个文件,并将它们初始化为对象。
用户是会员和员工的父类,书籍类表示一本书及其标题、描述、副本。这些类的方法都是正确的。
登录窗口.java
import java.awt.EventQueue;
import javax.swing.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class LoginWindow {
private JFrame frmLogIn;
private JTextField textField;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
LoginWindow window = new LoginWindow();
window.frmLogIn.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Initialize the contents of the frame.
*/
public LoginWindow() {
frmLogIn = new JFrame();
JLabel lblName = new JLabel("Name:");
lblName.setBounds(23, 25, 46, 14);
frmLogIn.getContentPane().add(lblName);
JLabel lblType = new JLabel("Type:");
lblType.setBounds(23, 56, 46, 14);
frmLogIn.getContentPane().add(lblType);
JTextField textField = new JTextField();
textField.setBounds(71, 22, 158, 20);
frmLogIn.getContentPane().add(textField);
textField.setColumns(10);
JComboBox comboBox = new JComboBox();
comboBox.setModel(new DefaultComboBoxModel(new String[] {"Staff", "Member"}));
comboBox.setBounds(71, 53, 158, 20);
frmLogIn.getContentPane().add(comboBox);
JButton btnNewButton = new JButton("Login");
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
if (!Library.users.containsKey(textField.getText())) {
new CreateUserWindow();
frmLogIn.dispose();
}
else if (!Library.users.get(textField.getText()).getUserType().equals(comboBox.getActionCommand())) {
JOptionPane.showMessageDialog(null,
"The user name and user type do not match, please try again.",
"User information mismatch", JOptionPane.ERROR_MESSAGE);
}
else {
String type = comboBox.getActionCommand();
if (type.equals("Staff")) new StaffWindow((Staff)Library.users.get(textField.getText()));
else new MemberWindow((Member)Library.users.get(textField.getText()));
}
}
});
btnNewButton.setBounds(23, 88, 206, 23);
frmLogIn.getContentPane().add(btnNewButton);
frmLogIn.setTitle("Log in");
frmLogIn.setBounds(100, 100, 268, 185);
frmLogIn.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frmLogIn.getContentPane().setLayout(null);
frmLogIn.setVisible(true);
}
}
图书馆.java
import java.io.*;
import java.text.ParseException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
public class Library implements Serializable{
public static HashMap<String, User> users;
public static HashMap<String, Book> books;
public Library(boolean readFromSerialized) throws IOException, ClassNotFoundException {
users = new HashMap<>();
books = new HashMap<>();
if (readFromSerialized) {
ObjectInputStream u_in = new ObjectInputStream(new FileInputStream("./Assignment/data/Users.txt"));
ObjectInputStream b_in = new ObjectInputStream(new FileInputStream("./Assignment/data/Books.txt"));
users = (HashMap<String, User>) u_in.readObject();
books = (HashMap<String, Book>) b_in.readObject();
u_in.close();
b_in.close();
}
}
public static void serializeToFile() {
try {
ObjectOutputStream u_out = new ObjectOutputStream(new FileOutputStream("./Assignment/data/Users.txt"));
ObjectOutputStream b_out = new ObjectOutputStream(new FileOutputStream("./Assignment/data/Books.txt"));
u_out.writeObject(Library.users);
b_out.writeObject(Library.books);
u_out.close();
b_out.close();
} catch (Exception ex) {}
}
}
错误消息显示以下代码段包含一些错误,该代码是关于用户信息验证的:
if (!Library.users.containsKey(textField.getText())) {
new CreateUserWindow();
frmLogIn.dispose();
}
代码中有几个问题:
-
使用
setBounds
和使用null-layout
(setLayout(null)
),这是邪恶和不受欢迎的,因为它可能会导致诸如此类的烦人问题,请使用适当的布局管理器,以便使您的应用程序在所有操作系统和PLAF中正确呈现。 -
使用
public static
成员,这可能会导致应用程序流不一致。 -
现在,您的问题是您创建了一个全局
textfield
变量,但从未初始化它(因此null
)private JTextField textField;
但是,在您的构造函数上,您创建了另一个具有相同名称的构造函数,但它是一个局部变量:
JTextField textField = new JTextField();
当你调用这句话时:
else if (!Library.users.get(textField.getText()).getUserType().equals(comboBox.getActionCommand())) {
Java正在使用全局变量(记住它是
null
),而不是局部变量(已初始化),为了解决此问题,请删除局部变量声明中的JTextField
:JTextField textField = new JTextField();
所以,它变成了:
textField = new JTextField();
这将初始化全局变量,您将能够在
ActionListener
中使用它