Этот код отображает код на оконной консоли, но не на textArea, которую я использовал - PullRequest
1 голос
/ 30 мая 2020

Ниже мой код:

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

                    }
                }
            });    
        }
    }
}

Я создаю окно для сервера, которому нужна кнопка подключения для подключения к серверному сокету, но после настройки клиента для этого сервера и после отправки клиенту сообщение, сообщение отображается на консоли для eclipse, но не в текстовой области, которой я действительно хочу быть

Поэтому, пожалуйста, помогите мне, взглянув на мой код.

1 Ответ

1 голос
/ 31 мая 2020

Две проблемы:

  1. Ваш while (true) l oop блокирует поток отправки событий AWT.
  2. Вы добавляете прослушиватель на каждой итерации вашего l oop.

Задержка очереди событий

AWT / Swing однопоточный . Когда вызывается ActionListener вашей кнопки «CONNECT TO SERVER», он вызывается в потоке отправки событий AWT. Никакие другие события не будут обрабатываться до тех пор, пока этот метод не вернется.

Поэтому, когда этот ActionListener вызывает getValue(), а getValue () читает из сокета до тех пор, пока не будет обнаружено "stop", вся обработка событий приостанавливается. Ничего не перекрашивается. Не будет ответа на ввод с помощью мыши или клавиатуры, потому что MouseEvents и KeyEvents не обрабатываются.

Вы должны выполнять операции ввода-вывода, такие как чтение из сокета в другом потоке. Однако методы Swing должны выполняться в потоке отправки событий AWT.

Одним из решений является использование класса SwingWorker , чьи методы publish и process позволяют отправлять несколько данных элементы из фонового потока в AWT даже поток отправки.

Для отправки в сокет вы можете использовать потокобезопасную BlockingQueue для хранения строк для отправки, а затем использовать al oop в другом потоке ( не поток отправки событий AWT), чтобы получить текст из этой BlockingQueue и отправить его в сокет.

Добавить слушателя только один раз

Метод addActionListener фактически добавляет слушателя на кнопку. Все добавленных вами слушателей будут вызываться при нажатии кнопки.

Итак, если вы вызываете addActionListener каждый раз, когда ваш l oop выполняется, вы добавите слушателя для каждого фрагмента данных, который вы читаете из сокета!

Вам следует добавить ActionListener к кнопке только один раз - обычно сразу после того, как вы создали кнопку.

Код

Итак, если мы переместим ввод-вывод в другие потоки и используем 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();, чтобы увидеть полную информацию об исключении.
  • Научитесь использовать менеджеры компоновки. A При нулевом макете все будет хорошо на вашем компьютере, но будут проблемы на других компьютерах, где установленные шрифты отличаются, а шрифты отображаются с разными размерами. («17 точек» означает ⁄₇₂ дюйма, который отображается с большим количеством пикселей на мониторе с разрешением 120 точек на дюйм, чем на мониторе с разрешением 96 точек на дюйм.) Кроме того, нулевой макет означает, что вы не можете изменить размер окна, чтобы сделать JTextArea и JTextField больше или меньше .
...