gpt4 book ai didi

仅当单击按钮时调用方法时,Java Swing GUI 才会被方法阻止

转载 作者:行者123 更新时间:2023-12-01 22:41:50 26 4
gpt4 key购买 nike

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

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_bot.mainMethod() 中)。

GUI 窗口显示,但它是空白的,并且它不会响应我尝试关闭它或其他任何内容。

程序实际上没有卡住,我仍然可以通过 irc 与机器人通信。

奇怪的是,例如,如果我在 main() 中启动机器人对象,它会按预期工作,initiate() 方法不会阻止 gui。

看一下机器人类(我只复制了相关部分):

package irc_bot;

//import stuff

public class bot {

//gui vars
private JFrame mainWindow;
//.....


//irc variables
private String server;
//.....

//lists
private List<String> botadminlist;
//.......

//for communicating with IRC
private Socket socket;
private BufferedWriter writer;//write to IRC
//.....
pritate bot_msg_handler handler;

private String line;//the received line from the IRC server is stored in this

//-----methods-----
//constructor: does the basic setup
public bot(String nick, String password, String master_channel, String master_admin) throws Exception {


//gui stuff
mainWindow=new JFrame("irc_bot");

//setup the menu
menuBar = new JMenuBar();

//first menu
menu = new JMenu("Commands");
menu.setMnemonic(KeyEvent.VK_C);
menuBar.add(menu);
//ide jön a menü kifejtése
menuItem = new JMenuItem("Show/Edit commands",
KeyEvent.VK_S);
//event handling
menuItem.addActionListener(
new ActionListener(){
public void actionPerformed(ActionEvent event){
showCommands();
}
}
);
menu.add(menuItem);
menuItem = new JMenuItem("Add command",
KeyEvent.VK_A);
//event handling
menuItem.addActionListener(
new ActionListener(){
public void actionPerformed(ActionEvent event){
addCommand();
}
}
);
menu.add(menuItem);
//more menus.......

//more GUI elements

//.......
//setup the window
mainWindow.add(bottomPanel,BorderLayout.SOUTH);
mainWindow.add(menuBar, BorderLayout.NORTH);
mainWindow.add(new JScrollPane(textBox), BorderLayout.CENTER);

mainWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainWindow.setSize(800,600);
mainWindow.setVisible(true);

sendBotMsg=false;

//setup lists
modlist=new ArrayList<mod_element>();
//.....

//user settings
this.nick=nick;
this.password=password;
this.master_channel=master_channel;
this.master_admin=master_admin;

//create the message handler object
handler = new bot_msg_handler(this.nick, this.master_channel, this.master_admin, modlist,
botadminlist, stafflist, adminlist, active_channels, cooldown, commands);
handler.setTextBox(textBox);

textBox.append("Constructor setup complete\n");
}//constructor

//IRC SPECIFIC STUFF
public void initiate(String server, int... ports) throws Exception{
this.server=server;
if(connect(server, ports)==-1){
JOptionPane.showMessageDialog(null, "Bot couldn't connect to the server!");
mainWindow.dispose();
return;
}
if(logon()==-1){
JOptionPane.showMessageDialog(null, "Bot couldn't log in!");
mainWindow.dispose();
return;
}
join(master_channel);

mainMethod();

}

private int connect(String server, int... ports) throws Exception {
// Connect directly to the IRC server.
//this.server=server;
boolean connected=false;
for(int port:ports){
textBox.append("Trying to connect to "+server+" on port "+port+"...\n");
try{
socket = new Socket();
socket.setSoTimeout(1000);//if nothing happens in 1000 milliseconds, it is gonna advance in the code. IMPORTANT!
socket.connect(new InetSocketAddress(server, port), 2000);//2000 is the timeout value in milliseconds for the connection
textBox.append("Connected to "+server+":"+port+"\n");
connected=true;
this.port=port;
break;
}
catch(SocketTimeoutException e1){
textBox.append("Connection timed out\n");
}
}
if(connected){
writer = new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream( ), "UTF-8"));//utf-8 (international characters)
reader = new BufferedReader(
new InputStreamReader(socket.getInputStream( ), "UTF-8"));
handler.setWriter(writer);
return 1;//connection successful
}else{
textBox.append("Connection timed out, cannot connect to the IRC server\nApp will shut down now.\n");
return -1;//this means that the connection failed
}

}//connect

private int logon() throws Exception {//logs the bot in the irc
writer.write("PASS " + password + "\r\n");//twitch specific stuff
writer.write("NICK " + nick + "\r\n");
writer.flush( );

// Read lines from the server until it tells us we have connected.
String line = null;
while ((line = reader.readLine()) != null) {
rawBox.append(line+"\n");
if (line.contains("004")) {
// We are now logged in.
textBox.append("The bot is successfully logged in\n------------------\n");
return 1;
}
else if (line.contains("Login unsuccessful")) {
textBox.append("Login was unsuccessful.\n");
return -1;
}
}
return -1;
}//logon

private void join(String channel) throws Exception {
// Join the channel. Only for initial use.
writer.write("JOIN " + channel + "\r\n");
writer.flush( );

writer.write("TWITCHCLIENT 3"+"\r\n");
writer.flush();
}//join

private void mainMethod() throws Exception{
// Keep reading lines from the server.
//-------MAIN PROCESS------
msgInput.setEditable(true);//the textbox is ready to be used

while (true){
try{
line = reader.readLine( );//waits for a line for 1000 millisecs
handler.setLine(line);
}catch(SocketTimeoutException e7){
//if there is no incoming line in a second, it's gonna create an exception
//we want nothing to do with the exception though
}

if(line!=null){
handler.set_msg_type(0);//default for each line

if (line.startsWith("PING ")) {
// We must respond to PINGs to avoid being disconnected.
handler.sendPONG();
}

//Print the raw line received by the bot to the rawBox
rawBox.append(line+"\n");


//analyze the line and gather information
handler.msgAnalyzer();

//message handling:
handler.msgHandler();

//update channellist and other lists
updateLists();
}//if

//other tasks
handler.otherTasks();
line=null;


//send the message
if(sendBotMsg){
handler.sendPRIVMSG(channelToSend, msgToSend);
sendBotMsg=false;
}

}//while

}//mainMethod


//Methods called from the gui are here, but they are irrelevant now

我尝试添加 SwingWorker,以便启动内容在后台运行,但它仍然卡住 gui。

当我...时,该程序将按预期运行

  1. 不调用启动方法。我仍然在 actionPerformed 方法中创建对象,并且获得了一个正常运行的 GUI。

  2. 不要从actionPerformed调用启动函数。

例如,当我这样做时,机器人会按预期工作:

public static void main(String[] args) throws Exception {
String server="irc.twitch.tv";
int[] ports={80,6667};
String nick ="test";
String password = "test";
String master_channel = "#master";
String master_admin="master";

//bot object:
bot irc_bot=new bot(nick, password, master_channel, master_admin);//this is gonna be our irc_bot object
//initiate the bot:
irc_bot.initiate(server, ports);
}

我怀疑运行initiate()的线程以某种方式阻塞了GUI线程。我不明白的是为什么它只发生在我从 Action 监听器/窗口监听器/任何监听器调用所述方法时。关于如何解决这个问题有什么想法吗?

最佳答案

按钮单击匿名类的 actionPerformed() 方法在 Swing 线程上执行,因此当执行该 block 中的代码时,GUI 无法执行任何其他操作。您需要在其他线程中执行initiate()方法。

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

new Thread(){
public void run() {
//initiate the bot:
try {
irc_bot.initiate(server, ports);
} catch (Exception e) {
e.printStackTrace();
}

}}.start();

尽管代码很糟糕,但这应该可以实现您正在寻找的目标。然后您需要弄清楚如何创建和管理该线程。您需要一种方法来从 GUI 向后台线程发出您希望其停止的信号(可能是通过中断它)。

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

关于仅当单击按钮时调用方法时,Java Swing GUI 才会被方法阻止,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26012709/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com