此代码在 window 控制台上显示代码,但不在我使用的 textArea 上显示代码

This code is displaying code on window console but not on the textArea which I had used

下面是我的代码:

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){

                    }
                }
            });    
        }
    }
}

我正在为服务器构建一个 window,它需要一个连接按钮来连接服务器套接字,但是在为该服务器设置客户端并向客户端发送消息后,该消息显示在eclipse 的控制台,但不在我真正想要的 textarea 上

所以请帮我看看我的代码。

两个问题:

  1. 您的 while (true) 循环正在阻塞 AWT 事件分派线程。
  2. 您在循环的每次迭代中都添加了一个侦听器。

阻塞事件队列

AWT/Swing is single threaded。当调用“CONNECT TO SERVER”按钮的 ActionListener 时,它会在 AWT 事件调度线程中调用。在该方法 returns.

之前,不会处理其他事件

因此,当 ActionListener 调用 getValue() 并且 getValue() 从套接字读取数据直到遇到 "stop" 时,所有事件处理都会暂停。什么都不会重新粉刷。不会有鼠标或键盘输入的响应,因为没有处理MouseEvents和KeyEvents。

您必须执行 I/O 操作,例如从不同线程上的套接字读取数据。但是,Swing 方法必须在 AWT 事件调度线程中执行。

一种解决方案是使用 SwingWorker class,其 publishprocess 方法允许您将多个数据元素从后台线程发送到 AWT,甚至分派线程。

为了发送到套接字,您可以使用线程安全的 BlockingQueue 来存储要发送的行,然后在不同的线程(而不是 AWT 事件调度线程)中使用循环从该 BlockingQueue 中获取文本并将其发送到套接字。

只添加一次监听器

方法 addActionListener 实际上 添加一个监听器 到一个按钮。 您添加的所有 个侦听器将在按下按钮时被调用。

因此,如果您在每次循环执行时都调用 addActionListener,那么您将为从套接字读取的每条数据添加一个侦听器!

您应该只将 ActionListener 添加到按钮一次 — 通常是在您创建按钮之后。

代码

因此,如果我们将 I/O 移动到其他线程并使用 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(); 以便您可以查看异常的完整详细信息。
  • Learn to use layout managers. 空布局在您的计算机上看起来没问题,但在其他计算机上就会出现问题,因为安装的字体不同并且字体以不同的大小呈现。 (“17 点”表示 ¹⁷⁄₇₂ 英寸,在 120 DPI 显示器上呈现的像素比在 96 DPI 显示器上呈现的像素更多。)此外,空布局意味着您无法调整 window 的大小来制作 JTextArea 和JTextField 更大或更小。