Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/341.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

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 Swing GUI仅在单击按钮调用方法时被方法阻止_Java_Multithreading_Swing_User Interface_Block - Fatal编程技术网

Java Swing GUI仅在单击按钮调用方法时被方法阻止

Java Swing GUI仅在单击按钮调用方法时被方法阻止,java,multithreading,swing,user-interface,block,Java,Multithreading,Swing,User Interface,Block,我正在用Java创建一个IRC机器人。我创建了一个名为“loginHandler”的类,它要求用户输入登录信息,例如nick/pass/server/etc。。。用户完成后,单击“连接”按钮,初始化IRC处理程序类,bot。参见代码: package irc_bot; import java.awt.BorderLayout; //more imports are here but they are irrelevant right now public class loginHandler

我正在用Java创建一个IRC机器人。我创建了一个名为“loginHandler”的类,它要求用户输入登录信息,例如nick/pass/server/etc。。。用户完成后,单击“连接”按钮,初始化IRC处理程序类,
bot
。参见代码:

package irc_bot;

import java.awt.BorderLayout;
//more imports are here but they are irrelevant right now

public class loginHandler extends JFrame {

private static final long serialVersionUID = 6742568354533287421L;

private bot irc_bot;

private String username;
private String password;
private int[] ports={80,6667};
//.....

//gui vars
private final JTextField usernameInput;
private final JTextField passwordInput;
//......

public loginHandler(){

    super("Login data");

    Panel = new JPanel(new BorderLayout());
    Panel.setLayout(new GridLayout(13, 1));

    JLabel label = new JLabel("Hover over labels for information!!");
    Panel.add(label);

    label = new JLabel("Username: ");
    label.setToolTipText("Type in your username!");
    Panel.add(label);
    usernameInput=new JTextField("");
    usernameInput.setEditable(true);
    Panel.add(usernameInput);

    label = new JLabel("Password: ");
    label.setToolTipText("Type in your password! Starts with 'oauth:'");
    Panel.add(label);
    passwordInput=new JPasswordField("");
    passwordInput.setEditable(true);
    Panel.add(passwordInput);

    //.......
    //the other textfields are here but they are irrelevant right now


    //The important part:
    JButton okButton=new JButton("Connect");
    okButton.addActionListener(
            new ActionListener(){
                public void actionPerformed(ActionEvent event){
                    //set data method
                    setData();
                    dispose();
                    //bot object:
                    try {
                        irc_bot=new bot(username, password, master_channel, master_admin);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    //initiate  the bot:
                    try {
                        irc_bot.initiate(server, ports);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        );

    add(okButton, BorderLayout.SOUTH);


    add(new JScrollPane(Panel), BorderLayout.NORTH);

    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setSize(300,400);
    setVisible(true);

}
private void setData(){
    username=usernameInput.getText();
    password=passwordInput.getText();
    server=serverInput.getText();
    master_channel=master_channelInput.getText();
    master_admin=master_adminInput.getText();
    port=portsInput.getText();

    //set up the ports: TO-DO
}

}
我的问题是
bot.initiate()
方法会阻塞
bot
对象的GUI。如果未调用
bot.initiate()
,GUI将按预期工作。当bot.initiate()停止时,GUI将再次正常工作。问题在于initiate()方法包含一个从irc服务器读取行的无限循环(在
irc\u bot.main方法()中)

GUI窗口会出现,但它是空白的,并且它不会响应我试图关闭它或其他任何操作

程序实际上并没有冻结,我仍然可以通过irc与机器人通信

奇怪的是,如果我在main()中启动bot对象,它就会按预期工作,initiate()方法不会阻塞gui

看看bot类(我只复制了相关部分):


我怀疑initiate()运行的线程以某种方式阻塞了GUI线程。我不明白的是,为什么只有当我从action listener/window listener/any listener调用上述方法时才会发生这种情况。关于如何解决这个问题,有什么想法吗?

按钮单击匿名类的actionPerformed()方法在Swing线程上执行,因此在执行该块中的代码时,GUI不能做任何其他事情。您需要在其他线程中执行initiate()方法

要向自己证明情况确实如此,请使用以下(可怕的)代码:

这应该可以实现您想要的,尽管代码很糟糕。然后,您需要确定如何创建和管理该线程。您需要一种方法从GUI向后台线程发出信号,表明您希望它停止,可能是通过中断它


从main()方法执行代码时没有遇到此问题的原因是,您将免费获得一个新线程。使用main()启动应用程序时,调用bot上的构造函数,这将生成UI。主方法在其主线程中开始执行bot initiate()方法并进入该循环,而Swing线程负责运行UI

按钮click anonymous类的actionPerformed()方法在Swing线程上执行,因此在执行该块中的代码时,GUI不能执行任何其他操作。您需要在其他线程中执行initiate()方法

要向自己证明情况确实如此,请使用以下(可怕的)代码:

这应该可以实现您想要的,尽管代码很糟糕。然后,您需要确定如何创建和管理该线程。您需要一种方法从GUI向后台线程发出信号,表明您希望它停止,可能是通过中断它


从main()方法执行代码时没有遇到此问题的原因是,您将免费获得一个新线程。使用main()启动应用程序时,调用bot上的构造函数,这将生成UI。主方法在其主线程中开始执行bot initiate()方法并进入该循环,而Swing线程负责运行UI

对于按钮单击,在事件调度线程上调用actionPerformed,并且应该尽快从actionPerformed返回。稍后使用invokeLater进行长时间的工作。否则,事件队列将被阻塞(单线程),GUI将不响应

public void actionPerformed(ActionEvent event){
    SwingUtilites.invokeLater(new Runnable() {
        @Override
        public void run() {
            ... the work
        }
    });
}

    EventQueue.invokeLater(() -> {
        ... the work
    });

第二个备选方案使用invokeLater的alternative类,并使用java 8的lambdas缩短代码。

对于按钮单击,在事件调度线程上调用actionPerformed,并且应该尽快从actionPerformed返回。稍后使用invokeLater进行长时间的工作。否则,事件队列将被阻塞(单线程),GUI将不响应

public void actionPerformed(ActionEvent event){
    SwingUtilites.invokeLater(new Runnable() {
        @Override
        public void run() {
            ... the work
        }
    });
}

    EventQueue.invokeLater(() -> {
        ... the work
    });
第二个备选方案使用invokeLater的alternative类,并使用Java8的lambdas缩短代码

我已经尝试添加SwingWorker,以使initiate内容在 背景,但它仍然冻结gui

您必须在SwingWorker上调用
execute()
,而不是
run()
方法(常见错误)

像这样:

new SwingWorker<Void, Void> {
    @Override
    public Void doInBackground() {
        irc_bot.initiate(server, ports);
        return null;
    }
}.execute();
新SwingWorker{
@凌驾
公共无效doInBackground(){
irc_bot.initiate(服务器、端口);
返回null;
}
}.execute();
我已经尝试添加SwingWorker,以使initiate内容在 背景,但它仍然冻结gui

您必须在SwingWorker上调用
execute()
,而不是
run()
方法(常见错误)

像这样:

new SwingWorker<Void, Void> {
    @Override
    public Void doInBackground() {
        irc_bot.initiate(server, ports);
        return null;
    }
}.execute();
新SwingWorker{
@凌驾
公共无效doInBackground(){
irc_bot.initiate(服务器、端口);
返回null;
}
}.execute();

非常感谢,这正是我需要的答案。您的代码按预期工作。我的问题是我不知道actionPerformed()方法是在Swing线程上执行的。看来,我将不得不沉溺于线程处理的奇迹中,也许会更好。是的,我不得不等待大约3分钟才能点击勾号,我想:非常感谢,这正是我需要的答案。您的代码按预期工作。我的问题是我不知道actionPerformed()方法是在Swing线程上执行的。看来我不得不沉溺于线程处理的奇迹中,也许会更好。是的,我必须等待大约3分钟才能点击勾号,我想:这看起来是一个非常优雅的解决方案,但我还不知道如何在我的代码中实现它。不过我很快会调查的。非常感谢你!这个厕所
new SwingWorker<Void, Void> {
    @Override
    public Void doInBackground() {
        irc_bot.initiate(server, ports);
        return null;
    }
}.execute();