下面是我的代码。
package Project1;
import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.JButton;
import java.awt.Font;
import javax.swing.JScrollBar;
import java.awt.Color;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class DonorChat extends JFrame {
/**
*
*/
private static final long serialVersionUID = 1L;
String get=null;
String s1=null;
DataOutputStream dos;
DataInputStream dis;
JButton btnNewButton;
private JPanel contentPane;
public JTextField textField;
public JTextArea textArea ;
public JButton btnNewButton_1;
public DonorChat() {
setTitle("Donor Chat");
// setIconImage(Toolkit.getDefaultToolkit().getImage("E:\\algorithm\\Project1\\Project1\\Blood.png"));
setIconImage(Toolkit.getDefaultToolkit().getImage("E:\\algorithm\\Project1\\Project1\\Blood.png"));
setForeground(Color.RED);
setFont(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(0, 0, 800, 1000);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
textArea= new JTextArea();
textArea.setFont(new Font("Tahoma", Font.BOLD, 17));
textArea.setBounds(31, 222, 707, 522);
contentPane.add(textArea);
textField = new JTextField();
textField.setFont(new Font("Tahoma", Font.BOLD, 17));
textField.setBounds(31, 793, 510, 105);
contentPane.add(textField);
textField.setColumns(10);
textField.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
}
});
btnNewButton = new JButton("Send\r\n");
btnNewButton.setFont(new Font("Tahoma", Font.BOLD, 17));
btnNewButton.setForeground(Color.RED);
btnNewButton.setBackground(Color.LIGHT_GRAY);
btnNewButton.setBounds(602, 820, 125, 47);
contentPane.add(btnNewButton);
JScrollBar scrollBar = new JScrollBar();
scrollBar.setBounds(717, 222, 21, 522);
contentPane.add(scrollBar);
btnNewButton_1 = new JButton("CONNECT TO SERVER");
btnNewButton_1.setBackground(Color.RED);
btnNewButton_1.setForeground(Color.DARK_GRAY);
btnNewButton_1.setFont(new Font("Times New Roman", Font.BOLD, 29));
btnNewButton_1.setBounds(31, 60, 707, 86);
contentPane.add(btnNewButton_1);
btnNewButton_1.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
try {
ServerSocket ss=new ServerSocket(9995);
Socket snSocket=ss.accept();
dos=new DataOutputStream(snSocket.getOutputStream());
dis=new DataInputStream(snSocket.getInputStream());
getValue();
ss.close();
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
setVisible(true);
}
public void getValue() throws IOException{
btnNewButton.removeActionListener(null);
while(true){
s1=dis.readUTF();
if (s1.equals("stop")){
textArea.setText("Client Want to Stop:"+s1);
break;
}
else{
System.out.println("Client Says:"+s1);
textArea.setText("Client Says:"+s1);
}
System.out.println("Type Something for Client");
btnNewButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0){
try {
dos.writeUTF(get);
}
catch(Exception e){
}
}
});
}
}
}
我正在为服务器建立一个窗口,它需要一个连接按钮来连接服务器的socket,但是在为该服务器设置客户端并发送消息后,消息显示在eclipse的控制台,但没有显示在我想要的textarea上。
所以请大家帮我看看我的代码。
两个问题。
while (true)
循环阻塞了AWT事件派遣线程。AWTSwing为单螺纹. 当你的 "CONNECT TO SERVER "按钮的ActionListener被调用时,它会在AWT事件派遣线程中被调用。 在该方法返回之前,其他事件不会被处理。
所以当该ActionListener调用 getValue()
和getValue()从一个套接字中读取,直到 "stop"
遇到,所有事件的处理都会暂停。 没有任何东西会被重新绘制。 对鼠标或键盘输入不会有任何响应,因为MouseEvents和KeyEvents没有被处理。
你必须在不同的线程上执行IO操作,比如从套接字读取。 然而,Swing方法必须在AWT事件派遣线程中执行。
一个解决方案是在AWT事件派遣线程中使用 SwingWorker 类,其 publish
和 process
方法允许你从一个后台线程向AWT偶调度线程发送多个数据元素。
对于发送到socket,你可以使用一个线程安全的BlockingQueue来存储要发送的行,然后在不同的线程(不是AWT事件派遣线程)中使用循环从该BlockingQueue中获取文本并将其发送到socket。
该方法 addActionListener
其实 增加一个听众 到一个按钮。 所有 当按钮被按下时,您所添加的监听器将被调用。
因此,如果您调用 addActionListener
每当你的循环执行时,你将为你从套接字中读取的每一条数据添加一个监听器!你应该只为按钮添加一次ActionListener--通常是在你创建按钮之后。
你应该只为一个按钮添加一次ActionListener--通常是在你创建按钮之后。
因此,如果我们将IO移到其他线程,并使用BlockingQueue来跟踪要发送的线路,它看起来像这样。
private final BlockingQueue<String> linesToSend =
new LinkedBlockingDeque<>();
public DonorChat() {
// ...
textField.addActionListener(new ActionListener() {
linesToSend.add(textField.getText());
});
btnNewButton.addActionListener(new ActionListener() {
linesToSend.add(textField.getText());
});
// ...
}
private void getValue(Socket snSocket) {
textArea.setText("");
SwingWorker<Void, String> socketReader =
new SwingWorker<Void, String>() {
@Override
protected Void doInBackground()
throws IOException {
// Runs in another thread.
// No AWT/Swing calls allowed here!
dis = new DataInputStream(snSocket.getInputStream());
while (true) {
String s1 = dis.readUTF();
if (s1.equals("stop")) {
publish("Client wants to stop.");
break;
}
publish("Client says: " + s1);
}
snSocket.close();
return null;
}
@Override
protected void process(List<String> linesRead) {
// Runs in event dispatch thread thread.
// AWT/Swing calls only; no I/O allowed here!
for (String line : linesRead) {
textArea.append(line + "\n");
}
}
};
socketReader.execute();
// Lines to send were added in AWT event dispatch thread
// by ActionListeners.
// We want to send them to the socket in a different thread.
Runnable linesSender = new Runnable() {
@Override
public void run() {
try {
dos = new DataOutputStream(snSocket.getOutputStream());
while (true) {
dos.writeUTF(linesToSend.take());
}
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
};
new Thread(linesSender).start();
}
其他一些重要的注意事项:
catch
块。 例外告诉你出了什么问题,在哪里出了问题,这是非常有价值的信息。 如果你不知道该把什么放在 catch
块,写 e.printStackTrace();
以便你可以看到异常的全部细节。