当前位置:编程学习 > JAVA >>

点击按钮,出发处理事件,但是界面没有反应


下面是个聊天程序的客户端,我启动服务器后,我在客户端输入ip地址和端口后,点击btnNewButton_1(连接服务器)按钮,调用connect函数,发起连接服务器请求,整个界面没有反应,请大家帮忙看看问题出在哪里?



package com.myjava;
import java.awt.EventQueue;


import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.JTextArea;
import javax.swing.JButton;
import javax.swing.JScrollPane;
import javax.swing.JScrollBar;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

public class ClientSocketFrame {

private JFrame frmChatclient;
private JTextField textIP;
private JTextField textPort;
private JTextField textField_2;
private JScrollPane scrollPane;
private JTextArea textArea;
 private PrintWriter writer; // 声明PrintWriter类对象
    private BufferedReader reader; // 声明BufferedReader对象
    private Socket socket; // 声明Socket对象
    private JButton btnNewButton_1;
/**
 * Launch the application.
 */
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
ClientSocketFrame window = new ClientSocketFrame();
window.frmChatclient.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}

/**
 * Create the application.
 */
public ClientSocketFrame() {
initialize();
}


/**
 * Initialize the contents of the frame.
 */
private void initialize() {
frmChatclient = new JFrame();
frmChatclient.setResizable(false);
frmChatclient.setTitle("ChatClient");
frmChatclient.setBounds(100, 100, 467, 299);
frmChatclient.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frmChatclient.getContentPane().setLayout(null);

JLabel lblNewLabel = new JLabel("IP\u5730\u5740\uFF1A");
lblNewLabel.setBounds(10, 10, 60, 15);
frmChatclient.getContentPane().add(lblNewLabel);

textIP = new JTextField();
textIP.setBounds(70, 7, 131, 21);
frmChatclient.getContentPane().add(textIP);
textIP.setColumns(10);

JLabel lblNewLabel_1 = new JLabel("\u7AEF\u53E3\uFF1A");
lblNewLabel_1.setBounds(231, 10, 54, 15);
frmChatclient.getContentPane().add(lblNewLabel_1);

textPort = new JTextField();
textPort.setBounds(271, 7, 87, 21);
frmChatclient.getContentPane().add(textPort);
textPort.setColumns(10);

textField_2 = new JTextField();
textField_2.setBounds(45, 237, 325, 21);
frmChatclient.getContentPane().add(textField_2);
textField_2.setColumns(10);

JLabel lblNewLabel_2 = new JLabel(" \u6D88\u606F\uFF1A");
lblNewLabel_2.setBounds(0, 243, 54, 15);
frmChatclient.getContentPane().add(lblNewLabel_2);

JButton btnNewButton = new JButton("\u53D1\u9001");
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
  writer.println(textField_2.getText()); // 将文本框中信息写入流
  textArea.append("客户端发送的信息是:" + textField_2.getText()
                        + "\n"); // 将文本框中信息显示在文本域中
  textField_2.setText(""); // 将文本框清空
}
});
btnNewButton.setBounds(376, 236, 79, 23);
frmChatclient.getContentPane().add(btnNewButton);

textArea = new JTextArea();
textArea.setBounds(10, 46, 441, 178);
frmChatclient.getContentPane().add(textArea);

btnNewButton_1 = new JButton("\u8FDE\u63A5");
btnNewButton_1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
connect(textIP.getText(),Integer.parseInt(textPort.getText()));
}
});
btnNewButton_1.setBounds(368, 6, 83, 23);
frmChatclient.getContentPane().add(btnNewButton_1);

//scrollPane = new JScrollPane();
//scrollPane.setBounds(0, 227, 455, -185);
//frmChatclient.getContentPane().add(scrollPane);


// scrollPane.add(textArea);
// scrollPane.setViewportView(textArea);



}



private void connect(String ip,int port) { // 连接套接字方法
textArea.append("尝试连接......\n"); // 文本域中信息信息
        try { // 捕捉异常
            socket = new Socket(ip,port); // 实例化Socket对象
            while (true) {
                writer = new PrintWriter(socket.getOutputStream(), true);
                reader = new BufferedReader(new InputStreamReader(socket
                        .getInputStream())); // 实例化BufferedReader对象
                textArea.append("完成连接。\n"); // 文本域中提示信息
                getServerInfo();
            }
        } catch (Exception e) {
            e.printStackTrace(); // 输出异常信息
        }
    }
    

  private void getServerInfo() {
        try {
            while (true) {
                if (reader != null) {
                    String line = reader.readLine();// 读取服务器发送的信息
                    if (line != null)
                        textArea.append("接收到服务器发送的信息:" + line + "\n"); // 显示服务器端发送的信息
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (reader != null) {
                    reader.close();// 关闭流
                }
                if (socket != null) {
                    socket.close(); // 关闭套接字
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

              
                
                
--------------------编程问答--------------------

            补充一下,我确认了一下,点击按钮后,客户端和服务端的连接已经建立成功了,但是
textArea.append("完成连接。\n"); 
这行信息没有加在textArea显示出来,好像在哪里阻塞了一样。 --------------------编程问答-------------------- 经测试,在执行getServerInfo()中的
String line = reader.readLine();

时卡住了。readLine()方法一直不返回,程序一直阻塞在这里。

测试时我自己写了服务端用PrintWriter发信息,客户端用楼主的BufferedReader读信息,执行readLine()时出现问题,目前不知道什么原因,以后查查资料再说。。。
在服务端改用DataOutputStream的writeUTF()发数据,客户端用DataInputStream的readUTF()接收数据,测试成功。

至于“完成连接”显示不出来的原因,是因为程序在处理“连接”按钮的响应事件时卡在了readLine()方法处,导致按钮的响应事件无法结束,程序没有办法更新界面。

另外注意一下,connect()方法中的死循环也有问题,在里面反复不停地创建对象,不太合适吧……我盯着任务管理器,看着javaw进程的内存占用从几十M很快升到几百M,还是很壮观的。。。。。这个死循环也会使connect()方法一直执行,导致按钮响应事件无法完成,同样会使界面不能更新。getServerInfo()中的死循环也一样。在测试中我把这两个死循环都去掉了。 --------------------编程问答-------------------- 不知道“尝试连接....”这几个字显示出来没有, 我这边的结果是这几个字也没显示出来
你的这一段代码:

  while (true) {
                writer = new PrintWriter(socket.getOutputStream(), true);
                reader = new BufferedReader(new InputStreamReader(socket
                        .getInputStream())); // 实例化BufferedReader对象
                textArea.append("完成连接。\n"); // 文本域中提示信息
                getServerInfo();
            }

以及这一段代码:

    while (true) {
                if (reader != null) {
                    String line = reader.readLine();// 读取服务器发送的信息
                    if (line != null)
                        textArea.append("接收到服务器发送的信息:" + line + "\n"); // 显示服务器端发送的信息
                }
            }

造成了死循环,没有跳出的条件,就致使你的监听事件无法终结。
那么好了,编译器会对代码进行优化,编译器才没那么傻,它会进行编译优化,textArea.append(String)不会你调用一次就马上执行一次append操作,因为append操作只是一个信息回显的操作,而是将append的内容写入到一个缓存,到你的方法结束后一下子添加到界面中,而你的
while (true) {
                writer = new PrintWriter(socket.getOutputStream(), true);
                reader = new BufferedReader(new InputStreamReader(socket
                        .getInputStream())); // 实例化BufferedReader对象
                textArea.append("完成连接。\n"); // 文本域中提示信息
                getServerInfo();
            }
这个循环在等待我提到的另外一个循环结束,而那个循环是个死循环,循环不能结束,造成方法也不能结束,添加到界面的机会就没有了, 也就显示不出来了


我认为你是要让客户端在那儿不停的登客户端发来的消息, 那你必须要开一个现场来等待,不然的话你什么也干不了。至于线程该怎么写, 不是一下子就能说清楚的, 好好去看看书吧 --------------------编程问答--------------------       while (true) {
                writer = new PrintWriter(socket.getOutputStream(), true);
                reader = new BufferedReader(new InputStreamReader(socket
                        .getInputStream())); // 实例化BufferedReader对象
                textArea.append("完成连接。\n"); // 文本域中提示信息
                getServerInfo();
            }
连接不需要写死循环。
           while (true) {
                if (reader != null) {
                    String line = reader.readLine();// 读取服务器发送的信息
                    if (line != null)
                        textArea.append("接收到服务器发送的信息:" + line + "\n"); // 显示服务器端发送的信息
                }
            }
像这种需要等待的死循环都需要用线程处理,如果你用线程,你服务器不返回消息,你这个程序就是阻塞开始状态。 --------------------编程问答-------------------- 返回链接完成 提示后,将界面重绘一下,或者刷新一下,就会显示出来了 --------------------编程问答-------------------- 前面的同学说死循环的问题:
我点了按钮应该在循环之前先执行textArea.append("尝试连接......\n"); 
这句为什么也显示不出来呢,有个同学说刷新或重绘界面这个怎么做呢。

的确是在哪里卡住了,我如果关闭掉服务端,客户端就会把这些信息显示出来了。 --------------------编程问答--------------------
引用 6 楼 hjgman 的回复:
前面的同学说死循环的问题:
我点了按钮应该在循环之前先执行textArea.append("尝试连接......\n"); 
这句为什么也显示不出来呢,有个同学说刷新或重绘界面这个怎么做呢。

的确是在哪里卡住了,我如果关闭掉服务端,客户端就会把这些信息显示出来了。


不是刷新和重绘的问题 --------------------编程问答--------------------
Quote: 引用 6 楼 hjgman 的回复:

前面的同学说死循环的问题:
我点了按钮应该在循环之前先执行textArea.append("尝试连接......\n"); 
这句为什么也显示不出来呢,有个同学说刷新或重绘界面这个怎么做呢。

的确是在哪里卡住了,我如果关闭掉服务端,客户端就会把这些信息显示出来了。[/qote]
不是刷新和重绘的问题,你把服务端关了就抛出了异常,循环才停掉了。你把getserverinfo做成线程就好了 --------------------编程问答--------------------

btnNewButton_1.addActionListener(new ActionListener(){
      public void actionPerformed(ActionEvent e){
        new Thread(){
          public void run(){
            connect(textIP.getText(),Integer.parseInt(textPort.getText()));
          }
        }.start();
      }
    });

详细原因自己参考awt的线程问题!
简单来说,按钮被点击时触发了一个事件,这个线程是awt本身维护界面的线程,那么如果这个事件函数总也不结束,那么它就不会去更新界面,所以如果你的按钮事件执行长时间任务,应该提交到新线程中执行,这样就得到你要的结果了!
补充:Java ,  Java SE
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,