java - 使用多线程实现java gui登录

标签 java multithreading swing user-interface

我正在开发一个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/

相关文章:

java - 立即绘制 JFrame

java - 在实践中,如何使结果集不等于NULL?

java - Servlet 过滤器与 ServletRequestListener

java - 如何在运行时更改枚举 (Java)

c - C Unix 中的段错误(核心转储)

java - 两行代码的功能

c++ - 在 Managed_shared_memory 中 boost 进程间互斥

Java ActionListener 类找不到变量。

java - Java 版本在 Websphere 中意味着什么?

java - setContentLength 设置为高