Java 为什么每次执行ActionListener时我的GUI窗口都会冻结?
每当单击GUI窗口上的按钮时,我将通过客户端1向服务器发送一条字符串消息“5”,服务器收到该消息并将其发送到另一个客户端,即客户端2,该客户端与客户端1连接到同一端口。单击按钮时,客户端2确实会收到字符串消息“5”,但问题是,一旦单击按钮,客户端1的整个GUI窗口就会冻结(无法单击任何内容)。客户端2也是如此,它在单击按钮时发送字符串消息“2”,但在单击按钮时GUI窗口也会冻结。为什么GUI窗口冻结 代码段:Java 为什么每次执行ActionListener时我的GUI窗口都会冻结?,java,multithreading,swing,user-interface,networking,Java,Multithreading,Swing,User Interface,Networking,每当单击GUI窗口上的按钮时,我将通过客户端1向服务器发送一条字符串消息“5”,服务器收到该消息并将其发送到另一个客户端,即客户端2,该客户端与客户端1连接到同一端口。单击按钮时,客户端2确实会收到字符串消息“5”,但问题是,一旦单击按钮,客户端1的整个GUI窗口就会冻结(无法单击任何内容)。客户端2也是如此,它在单击按钮时发送字符串消息“2”,但在单击按钮时GUI窗口也会冻结。为什么GUI窗口冻结 代码段: BufferedReader buffR; Socket sock = new Soc
BufferedReader buffR;
Socket sock = new Socket(nameHost, portNum);
PrintWriter printW = new PrintWriter(sock.getOutputStream());
this.buffR = new BufferedReader(new InputStreamReader(sock.getInputStream()));
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent ae){
printW.println("5");
printW.flush();
}
});
已编辑-其他代码段(接收部分):
这是一个可运行的方法,与上面的代码片段一起位于thread类中
public void run() {
try{
while(true){
String line = br.readLine();
int update = Integer.parseInt(line);
current-= update; //int current = 0 and update is the number received from the other client, which is "5"
JLabel newNumber = new JLabel(current); //Assign the newNumber JLabel with the current number
jp.remove(number); //Remove the JLabel 'number' which initially shows "50"
jp.revalidate();
jp.repaint();
jp.add(newNumber); //Replace the JLabel 'number' with 'newNumber'
if(update == 0){
JOptionPane.showMessageDialog(jf, "Reached 0", "Message", JOptionPane.INFORMATION_MESSAGE);
System.exit(0);
}
}
} catch (IOException ioe){
System.out.println("ioe in ChatClient.run: " + ioe.getMessage());
}
}
您的while(true)
正在Swing事件线程上被调用,这会将线程绑定,并阻止它执行绘制GUI和与用户交互的操作。此外,您还多次添加ActionListener,这没有什么意义,因为按下按钮时会调用每个ActionListener
解决方案:
请注意,如果需要连续读取BufferedReader对象,则可以将其读取放在
while(true)
循环中,但不要在循环中添加任何ActionListener或对Swing对象的状态进行任何更改。相反,我会使用SwingWorker对象,将我的while(true)
循环放在它的doInBackground()
方法中,这样它肯定会在后台线程中运行,然后我会使用SwingWorker的发布/处理方法对更新GUI的显示,以便以线程安全的方式将字符串推送到GUI中。我上面给你的链接将帮助你实现这一点
编辑
您的代码可能类似于: 设置按钮的ActionListener
// add this ActionListener once and only once
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// get the line of text from the GUI
String text = myTextField.getText();
// send the text out to the socket via the PrintWriter
printW.println(text);
}
});
请注意,最好使用AbstractAction,然后使用相同的对象设置JButton和JTextArea的操作
接受的一面是使用SwingWorker允许我们使用阻塞代码,buff.readLine()代码>而不阻塞GUI。请注意,doInBackground()
方法中的所有代码都是在后台线程中完成的,并且是在Swing事件线程(事件调度线程)之外完成的:
//使用SwingWorker,因为我要发布字符串
新SwingWorker(){
受保护的Void doInBackground()引发异常{
while(true){
//从后台线程中的BufferedReader读入字符串
字符串行=buffer.readLine();
//发布字符串,以便在Swing事件线程EDT上使用
出版(行);
}
};
//此代码在Swing事件线程EDT中调用
受保护的void进程(java.util.List块){
for(字符串行:块){
//在我的JText区域中显示文本
myTextArea.append(第+行“\n”);
}
};
}.execute();
您的while(true)
正在Swing事件线程上被调用,这会捆绑线程并阻止它执行绘制GUI和与用户交互的操作。此外,您还多次添加ActionListener,这没有什么意义,因为按下按钮时会调用每个ActionListener
解决方案:
摆脱那个不必要和危险的while循环
仔细阅读,然后努力遵守规则
请注意,如果需要连续读取BufferedReader对象,则可以将其读取放在while(true)
循环中,但不要在循环中添加任何ActionListener或对Swing对象的状态进行任何更改。相反,我会使用SwingWorker对象,将我的while(true)
循环放在它的doInBackground()
方法中,这样它肯定会在后台线程中运行,然后我会使用SwingWorker的发布/处理方法对更新GUI的显示,以便以线程安全的方式将字符串推送到GUI中。我上面给你的链接将帮助你实现这一点
编辑
您的代码可能类似于:
设置按钮的ActionListener
// add this ActionListener once and only once
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// get the line of text from the GUI
String text = myTextField.getText();
// send the text out to the socket via the PrintWriter
printW.println(text);
}
});
请注意,最好使用AbstractAction,然后使用相同的对象设置JButton和JTextArea的操作
接受的一面是使用SwingWorker允许我们使用阻塞代码,buff.readLine()代码>而不阻塞GUI。请注意,doInBackground()
方法中的所有代码都是在后台线程中完成的,并且是在Swing事件线程(事件调度线程)之外完成的:
//使用SwingWorker,因为我要发布字符串
新SwingWorker(){
受保护的Void doInBackground()引发异常{
while(true){
//从后台线程中的BufferedReader读入字符串
字符串行=buffer.readLine();
//发布字符串,以便在Swing事件线程EDT上使用
出版(行);
}
};
//此代码在Swing事件线程EDT中调用
受保护的void进程(java.util.List块){
for(字符串行:块){
//在我的JText区域中显示文本
myTextArea.append(第+行“\n”);
}
};
}.execute();
您的while(true)
正在Swing事件线程上被调用,将线程绑定起来,并阻止它执行绘制GUI和与u交互的操作