Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 登录窗口冻结_Java_Multithreading_Swing_Freeze - Fatal编程技术网

Java 登录窗口冻结

Java 登录窗口冻结,java,multithreading,swing,freeze,Java,Multithreading,Swing,Freeze,我开发了一个登录窗口,因为我的程序连接到SSH服务器 我在启动程序时打开此窗口。但我需要稍后为另一台服务器重新打开它。第二次打开时,登录窗口冻结 供参考 以下是登录窗口代码: package com.maxbester.test; import java.awt.BorderLayout; import java.awt.FlowLayout; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import j

我开发了一个登录窗口,因为我的程序连接到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);
        }
    }
}
我存储父类以在用户输入登录名和密码时通知它

服务器类非常简单:

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);
    }
}
package com.maxbester.test;
公共类控制器{
公共控制员(){
服务器=新服务器(“myserver”);
登录(服务器);
}
/**
*此方法打开登录窗口并等待,直到收到来自的信号
*接收到信号后,关闭窗口

*登录窗口必须更新“服务器”的登录名和密码

*@param服务器 */ 专用同步void askLoginPassword(最终服务器){ server.setLogin(空); server.setPassword(空); while(server.hasConnectionId()==false){ LoginWindow LoginWindow=新的LoginWindow(Controller.this,server); 试一试{ loginWindow.setVisible(true); 等待(); }捕捉(中断异常e){ 日志错误(“线程异常”,e); showMessageDialog(登录窗口,“线程异常”,“错误”,JOptionPane.Error\u消息); }最后{ loginWindow.dispose(); loginWindow=null; } } } /** *首先,此方法测试服务器是否可访问

*如果是,该方法将打开一个LoginWindow以询问用户ID

*当我们获得信息时,函数会检查 *登录名和密码正确。如果不正确,函数将重复该操作

*@param服务器 */ 私有void登录(服务器){ 布尔badLogin=true; 做{ askLoginPassword(服务器); 试一试{ //测试密码是否正确,如果不正确,则抛出异常 badLogin=false; }捕获(例外e){ badLogin=true; LOG.error(e.getMessage(),e); showMessageDialog(null,例如getMessage(),“Error”,JOptionPane.Error_MESSAGE); } }while(badLogin); } }
确切地说,发生了什么(特别是wrt线程)有点不清楚-但我认为您可能应该去看看SwingWorker文档,了解如何在swing中处理长时间运行的任务

很难看出哪种是长时间运行的方法(我想这已经被注释掉了)——但这就是可能需要与GUI线程分开的peice

另外,您希望登录窗口何时消失在收到服务器的响应之后或之前


(根据评论编辑)

从哪里从控制器构造函数调用
askLoginPassword
方法。我将把它添加到问题中。对不起,不用担心。问题是,这一切发生在哪条线索上?如果从GUI事件侦听器创建
控制器
(并随后调用
askLoginPassword
方法),则可能会阻塞事件线程。基本上,控制器是在主线程中创建的。我想我在某处挡住了什么,但我不知道在哪里。。。奇怪的是,它在第一次调用
login
时工作,但在第二次调用时冻结。可能最好放弃线程并使用模式对话框,而不是d:长时间运行的方法[…],但这可能是以后需要调用的peice()不,这会(并且确实)阻止EDT。长时间运行的东西必须在后台线程上运行。调用器是将结果传递回EDT。我快速查看了SwingWorker,但我认为这不是我需要的。我的控制器类做了很多事情,并且不是面向HMI的。我想将GUI和业务分开(MVC模式)。对于其他HMI,我实现了观察者模式。我想我也可以为登录窗口做这件事。但是对于这样一个小窗户来说,它听起来相当沉重。。。你怎么认为?