0

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

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

有关信息

这是登录窗口代码:

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();
    }
}

此窗口由控制器启动:

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);
    }
}
4

1 回答 1

0

it's a little unclear precisley whats happening (particular wrt threads) - but I think that you should probably go and look at the SwingWorker documentation to see how to handle long running tasks in swing,

It's hard to see which is the long running method (I assume this is commented out) - but that's the peice that probably needs to be kept seperate from the GUI thread.

Also, when are you expecting the login window to vanish? - after or before you have received a response from the server.

(edited in response to comments)

于 2013-02-13T19:40:58.110 回答