登录窗口冻结

时间:2013-02-06 13:28:17

标签: java multithreading swing freeze

我开发了一个登录窗口,因为我的程序连接到SSH服务器。

启动程序时打开此窗口。但我需要稍后再打开另一台服务器。第二次打开它时,登录窗口冻结了......

有关信息

这是LoginWindow代码:

package com.maxbester.test;

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

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

import org.apache.log4j.Logger;

import com.maxbester.test.Server;

@SuppressWarnings("serial")
public class LoginWindow extends JFrame {

    private static final Logger LOG = Logger.getLogger(LoginWindow.class);

    private Server _server;
    private Object _parent;

    private JPanel _panel;
    private JLabel _loginLabel;
    private JTextField _loginInput;
    private JLabel _passwordLabel;
    private JPasswordField _passwordInput;

    private JPanel _buttonPanel;
    private JButton _okButton;
    private JButton _cancelButton;

    public LoginWindow(Object parent, Server server) {
        _server = server;
        _parent = parent;
        initComponents();
    }

    private void initComponents() {
        setTitle("Connection window");
        setLayout(new BorderLayout());

        _loginLabel = new JLabel("Login: ");
        _loginInput = new JTextField(System.getProperty("user.name"), 15);

        _passwordLabel = new JLabel("Password: ");

        _panel = new JPanel(new GridBagLayout());
        GridBagConstraints c = new GridBagConstraints();
        c.gridx = 0;
        c.gridy = 0;
        // external padding
        c.insets = new Insets(5,5,5,5);
        _panel.add(_loginLabel,c);
        c.gridx = 1;
        _panel.add(_loginInput,c);
        c.gridy = 1;
        _panel.add(_passwordLabel,c);
        c.gridx = 0;
        _panel.add(getPasswordLabel(),c);

        add(_panel, BorderLayout.CENTER);

        _okButton = new JButton("Ok");
        _okButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent arg0) {
                okActionPerformed();
            }
        });
        _cancelButton = new JButton("Cancel");
        _cancelButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent arg0) {
                System.exit(0);
            }
        });
        _buttonPanel = new JPanel(new FlowLayout());
        _buttonPanel.add(_okButton);
        _buttonPanel.add(_cancelButton);
        add(_buttonPanel, BorderLayout.SOUTH);

        pack();
    }

    /**
     * @return the _passwordInput
     */
    private JPasswordField getPasswordInput() {
        if (LOG.isTraceEnabled()) {
            LOG.trace("getPasswordInput()");
        }
        if (_passwordInput == null) {
            _passwordInput = new JPasswordField(15) {
                // Give the focus to this field
                public void addNotify() {
                    super.addNotify();
                    requestFocusInWindow();             
                }    
            };
            _passwordInput.addKeyListener(new KeyListener() {
                @Override public void keyTyped(KeyEvent arg0) {}
                @Override
                public void keyReleased(KeyEvent keyEvent) {
                    if (keyEvent.getKeyChar() == KeyEvent.VK_ENTER) {
                        if (LOG.isTraceEnabled()) {
                            LOG.trace("Click enter in password field");
                        }
                        okActionPerformed();
                    }
                }
                @Override public void keyPressed(KeyEvent arg0) {}
            });
        }
        return _passwordInput;
    }


    protected void okActionPerformed() {
        if (LOG.isTraceEnabled()) {
            LOG.trace("okActionPerformed()");
        }
        if (_server != null) {
            String login = _loginInput.getText();
            if (login != null && !login.isEmpty()) {
                _server.setLogin(login);
                char[] password = _passwordInput.getPassword();
                if (password != null && password.length > 0) {
                    _server.setPassword(new String(password));
                    setVisible(false);
                    synchronized (_parent) {
                        if (LOG.isTraceEnabled()) {
                            LOG.trace("syncronized with "+_parent);
                        }
                        _parent.notifyAll();
                    }
                } else {
                    JOptionPane.showMessageDialog(LoginWindow.this,"Please enter a password", "Password required", JOptionPane.WARNING_MESSAGE);    
                }
            } else {
                JOptionPane.showMessageDialog(LoginWindow.this,"Please enter your login", "Login required", JOptionPane.WARNING_MESSAGE);
            }
        } else {
            LOG.error("Server is null");
            JOptionPane.showMessageDialog(LoginWindow.this,"Server is null.", "An error has occured", JOptionPane.ERROR_MESSAGE);
            System.exit(-1);
        }
    }
}

我存储父类,以便在用户输入登录名和密码时通知它。

Server类非常简单:

package com.maxbester.test;

public class Server {

    private String _url;
    private String _login = "root";
    private String _password = "";

    public Server(String url) {
        _url = url;
    }
    public Server(String url, String login, String password) {
        _url = url;
        if (login != null) {
            _login = login;
        }
        if (password != null) {
            _password = password;
        }
    }
    public String getUrl() {
        return _url;
    }
    public String getLogin() {
        return _login;
    }
    public String getPassword() {
        return _password;
    }
    public void setUrl(String url) {
        if (url != null) {
            _url = url;
        }
    }
    public void setLogin(String login) {
        _login = login;
    }
    public void setPassword(String password) {
        _password = password;
    }
    public boolean hasLogin() {
        return _login != null;
    }
    public boolean hasPassword() {
        return _password != null;
    }
    public String toString() {
        return _url;
    }
    /**
     * Test if the server has a login and a password.
     * @return Return true if the server has a login and a password, false otherwise.
     */
    public boolean hasConnectionId() {
        return _login != null && !_login.isEmpty() && _password != null && !_password.isEmpty();
    }
}

此窗口由Controller启动:

package com.maxbester.test;

public class Controller {

    public Controller() {
        Server server = new Server("myserver");
        login(server);
    }

    /**
     * <p>This method opens a login window and waits until a signal is receive from
     * that window. When the signal is received, closes the window.</p>
     * <p>The login window has to update the login and password of 'Server'.</p>
     * @param server
     */
    private synchronized void askLoginPassword(final Server server) {
        server.setLogin(null);
        server.setPassword(null);
        while (server.hasConnectionId() == false) {
            LoginWindow loginWindow = new LoginWindow(Controller.this, server);
            try {
                loginWindow.setVisible(true);
                wait();
            } catch (InterruptedException e) {
                LOG.error("Thread exception", e);
                JOptionPane.showMessageDialog(loginWindow, "Thread exception", "Error", JOptionPane.ERROR_MESSAGE);
            } finally {
                loginWindow.dispose();
                loginWindow = null;
            }
        }
    }

    /**
     * <p>First of all, this method tests if the server is reachable.</p>
     * <p>If it is, the method opens a LoginWindow in order to ask the user ids.</p>
     * <p>When we have the information, the function checks if the
     * login and password are correct. If they are not, the function repeats the operation.</p>
     * @param server
     */
    private void login(Server server) {
        boolean badLogin = true;
        do {
            askLoginPassword(server);
            try {
                // test if password is OK, if it is not, throw exception

                badLogin = false;
            } catch (Exception e) {
                badLogin = true;
                LOG.error(e.getMessage(), e);
                JOptionPane.showMessageDialog(null, e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
            }
        } while(badLogin);
    }
}

1 个答案:

答案 0 :(得分:0)

有点不清楚精确发生了什么(特别是wrt线程) - 但我认为你应该去看看SwingWorker文档,看看如何处理长时间运行的任务,

很难看出哪个是长时间运行的方法(我假设这已被注释掉了) - 但这可能需要与GUI线程保持分离。

此外,您何时期望登录窗口消失? - 在您收到服务器的回复之后或之前。

(根据评论编辑)