我正在开发一个java应用程序,它在jframe中有一个登录表单。我里面有文本字段和按钮。
登录按钮有一个事件监听器,它是创建登录窗口的类的内部类。当用户按下登录按钮时,监听器从字段中获取值并将其传递给 validator ,该 validator 使用 mysql 数据库对其进行验证,并根据用户的输入返回 true 和 false。现在,监听器根据返回值使用 if-else
语句更新 ui。整个事情运转良好。
问题是,当进行验证时,无法使用 GUI,因为每件事都是通过单个线程完成的。所以当时 gui
有点卡住了。
如何使用多线程来避免此问题并在进行验证时使用其他 gui 组件。
最佳答案
正如您可能知道的那样,您永远不应该在事件调度线程中执行长时间运行的任务,这会使您的程序看起来像是挂起的。
同样,您永远不应该在事件调度线程之外创建/修改任何 UI 组件。
最简单的解决方案之一是使用 SwingWorker。这允许您在后台线程中执行代码,但它会自动将其结果重新同步回事件调度线程...
public class LoginForm {
public static void main(String[] args) {
new LoginForm();
}
public LoginForm() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
JDialog frame = new JDialog((JFrame) null, "Login", true);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new LoginPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
System.exit(0);
}
});
}
public class LoginPane extends JPanel {
private JTextField userNameField;
private JPasswordField passwordField;
private JButton okay;
private JButton cancel;
public LoginPane() {
setLayout(new BorderLayout());
userNameField = new JTextField(15);
passwordField = new JPasswordField(10);
okay = new JButton("Login");
cancel = new JButton("Cancel");
JPanel mainPane = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.anchor = GridBagConstraints.EAST;
gbc.insets = new Insets(2, 2, 2, 2);
mainPane.add(new JLabel("User Name:"), gbc);
gbc.gridy++;
mainPane.add(new JLabel("Password:"), gbc);
gbc.gridx++;
gbc.gridy = 0;
gbc.anchor = GridBagConstraints.WEST;
gbc.fill = GridBagConstraints.HORIZONTAL;
mainPane.add(userNameField, gbc);
gbc.gridy++;
mainPane.add(passwordField, gbc);
mainPane.setBorder(new EmptyBorder(8, 8, 8, 8));
add(mainPane);
JPanel buttonPane = new JPanel(new FlowLayout(FlowLayout.RIGHT));
buttonPane.setBorder(new EmptyBorder(8, 8, 8, 8));
buttonPane.add(okay);
buttonPane.add(cancel);
add(buttonPane, BorderLayout.SOUTH);
okay.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
userNameField.setEnabled(false);
passwordField.setEnabled(false);
okay.setEnabled(false);
cancel.setEnabled(false);
new LoginWorker(userNameField.getText(), passwordField.getPassword()).execute();
}
});
cancel.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
SwingUtilities.getWindowAncestor(LoginPane.this).dispose();
}
});
}
public class LoginWorker extends SwingWorker<Boolean, Boolean> {
private String userName;
private char[] password;
public LoginWorker(String userName, char[] password) {
this.userName = userName;
this.password = password;
}
@Override
protected Boolean doInBackground() throws Exception {
// Do you background work here, query the database, compare the values...
Thread.sleep(2000);
return Math.round((Math.random() * 1)) == 0 ? new Boolean(true) : new Boolean(false);
}
@Override
protected void done() {
System.out.println("Done...");
try {
if (get()) {
JOptionPane.showMessageDialog(LoginPane.this, "Login sucessful");
} else {
JOptionPane.showMessageDialog(LoginPane.this, "Login failed");
}
userNameField.setEnabled(true);
passwordField.setEnabled(true);
okay.setEnabled(true);
cancel.setEnabled(true);
} catch (Exception exp) {
exp.printStackTrace();
}
}
}
}
}
看看Concurrency in Swing欲了解更多信息,特别是SwingWorker
关于java - 使用多线程实现java gui登录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14210003/