我发送了一个字符串消息" 5"每当点击GUI窗口上的按钮并且服务器接收到该消息并将其发送到与客户端1相同的端口的客户端2时,通过客户端1到服务器。当单击该按钮时,客户端2确实收到字符串消息" 5",但问题是单击按钮后,客户端1的整个GUI窗口冻结(无法点击任何内容)。对于客户端2也是如此,其发送字符串消息" 2"单击按钮时,单击按钮时GUI窗口也会冻结。为什么GUI窗口会冻结?
代码段:
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();
}
});
已编辑 - 附加代码段(接收部分): 这是一个可运行的方法,它与上面的代码片段一起在线程类中。
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());
}
}
答案 0 :(得分:3)
您正在Swing事件线程上调用while (true)
,占用线程并阻止它执行绘制GUI和与用户交互的操作。此外,您多次添加ActionListener,因为按下按钮时将调用每个ActionListener,因此没有多大意义。
解决方案:
请注意,如果您需要连续读取BufferedReader对象,那么请将其读取放在while (true)
循环内,但不要添加任何ActionListeners或对状态进行任何更改循环内部的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的Action。
接受方面的事情将涉及使用SwingWorker来允许我们使用阻塞代码buffR.readLine();
而不阻止GUI。请注意,doInBackground()
方法中的所有代码都是在后台线程中完成的,而不是Swing事件线程,EDT(事件调度线程):
// use a <Void, String> SwingWorker since I want to publish a String
new SwingWorker<Void, String>() {
protected Void doInBackground() throws Exception {
while (true) {
// read in a String from the BufferedReader in background thread
String line = buffR.readLine();
// publish String so it can be used on Swing event thread, the EDT
publish(line);
}
};
// this code is called in the Swing event thread, the EDT
protected void process(java.util.List<String> chunks) {
for (String line : chunks) {
// display text in my JTextArea
myTextArea.append(line + "\n");
}
};
}.execute();