这段代码在窗口控制台上显示代码,但在我使用的textArea上没有显示。

问题描述 投票:1回答:1

下面是我的代码。

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上。

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

java swing awt jtextfield jtextarea
1个回答
1
投票

两个问题。

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

阻碍了事件队列

AWTSwing为单螺纹. 当你的 "CONNECT TO SERVER "按钮的ActionListener被调用时,它会在AWT事件派遣线程中被调用。 在该方法返回之前,其他事件不会被处理。

所以当该ActionListener调用 getValue()和getValue()从一个套接字中读取,直到 "stop" 遇到,所有事件的处理都会暂停。 没有任何东西会被重新绘制。 对鼠标或键盘输入不会有任何响应,因为MouseEvents和KeyEvents没有被处理。

你必须在不同的线程上执行IO操作,比如从套接字读取。 然而,Swing方法必须在AWT事件派遣线程中执行。

一个解决方案是在AWT事件派遣线程中使用 SwingWorker 类,其 publishprocess 方法允许你从一个后台线程向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(); 以便你可以看到异常的全部细节。
  • 学会使用布局管理器。 空布局会让你的电脑上看起来还不错,但在其他电脑上就会出现问题,因为安装的字体不同,字体的渲染尺寸也不同。 ("17点 "的意思是¹⁷⁄₇₂英寸,在120DPI的显示器上呈现的像素比96DPI的显示器上多)。 另外,null布局意味着你不能调整窗口的大小来使JTextArea和JTextField变大或变小。
© www.soinside.com 2019 - 2024. All rights reserved.