06.Java网络编程(java GUI实现的聊天界面)
目前测试存在两个问题 1.最初是继承Frame来实现界面显示,后来发现,界面中部分控件存在时而显示时而不显示的问题,查找资料之后,将Frame修为JFrame,并且修改setVisible的时机,界面显示的问题解决,不显示的原因,有一种说法就是注释中提到的 2.界面显示问题解决之后,目前接收消息的线程无法正常接收,导致震动功能也无法实现,原因还有待进一步排查 package com.ren.socket; import java.awt.BorderLayout; import java.awt.Button; import java.awt.Color; import java.awt.Font; import java.awt.Frame; import java.awt.Panel; import java.awt.TextArea; import java.awt.TextField; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.BufferedWriter; import java.io.ByteArrayOutputStream; import java.io.FileInputStream; import java.io.FileWriter; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException; import java.sql.Date; import java.text.SimpleDateFormat; import javax.swing.JFrame; /** * 先调整窗口大小才会显示出组件,而不是立马显示出组件,在组件还未添加到面板前就将窗口 * (JFrame)设为可见(setVisible()),控件并不会引发重绘。解决方法很简单, * 只需要等所有组件都准备好以后才将JFrame的setVisible()设置为true。 * 非要在调用setVisible()之后添加组件,那么你也可以这样做:getContentPane().invalidate(); * * 即便这样做了,也没有达到想要的效果 */ public class GUIChat_UDP extends JFrame{ private static final long serialVersionUID = 1L; private Button send; private Button log; private Button clear; private Button shake; private TextArea viewText; private TextArea sendText; private TextField tField; private DatagramSocket socket; private BufferedWriter writer; public GUIChat_UDP(){ Init(); southPanel(); centerPanel(); event(); getContentPane().invalidate(); } private void centerPanel() { Panel center = new Panel(); //显示的文本区域 viewText = new TextArea(); //发送的文本区域 sendText = new TextArea(); //设置为边界布局管理器 center.setLayout(new BorderLayout()); //发送的文本区域放在南边 center.add(sendText, BorderLayout.SOUTH); //显示区域放在中间 center.add(viewText, BorderLayout.CENTER); //设置不可以编辑 viewText.setEditable(false); //设置背景色 viewText.setBackground(Color.WHITE); //设置字体大小 sendText.setFont(new Font("xxx", Font.PLAIN, 15)); viewText.setFont(new Font("xxx", Font.PLAIN, 15)); //将这个panel设置在中间位置 this.add(center,BorderLayout.CENTER); } private void southPanel() { Panel south = new Panel(); //用于输入聊天对象的IP地址 tField = new TextField(15); tField.setText("127.0.0.1"); send = new Button("send"); log = new Button("log"); clear = new Button("clear"); shake = new Button("shake"); //添加如布局 south.add(tField); south.add(send); south.add(log); south.add(clear); south.add(shake); this.add(south, BorderLayout.SOUTH); } private void Init() { this.setLocation(500, 50); this.setSize(400,600); this.setVisible(true); //开启接收消息线程 new Receive().start(); try { //初始化发送码头 socket = new DatagramSocket(); writer = new BufferedWriter(new FileWriter("log.txt",true)); } catch (SocketException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } private void event() { //关闭按钮事件 this.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { try { socket.close(); writer.close(); System.exit(0); } catch (Exception e2) { } } }); //发送按钮事件 send.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { try { send(); } catch (IOException e1) { e1.printStackTrace(); } } }); //消息记录 log.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { try { logFile(); } catch (IOException e1) { e1.printStackTrace(); } } }); //清空屏幕 clear.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { viewText.setText(""); } }); //震动 shake.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { try { send(new byte[]{-1}, tField.getText()); } catch (IOException e1) { e1.printStackTrace(); } } }); //快捷键监听 sendText.addKeyListener(new KeyAdapter() { @Override public void keyReleased(KeyEvent e) { //control+enter键发送消息 if (e.getKeyCode() == KeyEvent.VK_ENTER && e.isControlDown()) { try { send(); } catch (Exception e2) { } } } }); } //通过不断改变界面在屏幕中的位置达到震动的效果 protected void shake() { int x = this.getLocation().x; int y = this.getLocation().y; for (int i = 0; i < 10; i++) { try { this.setLocation(x + 10, y + 10); Thread.sleep(20); this.setLocation(x + 10, y - 10); Thread.sleep(20); this.setLocation(x - 10, y + 10); Thread.sleep(20); this.setLocation(x - 10, y - 10); Thread.sleep(20); this.setLocation(x, y); } catch (Exception e) { } } } protected void logFile() throws IOException { //刷新缓冲区 writer.flush(); //读取消息记录文件 FileInputStream fis = new FileInputStream("log.txt"); ByteArrayOutputStream baos = new ByteArrayOutputStream(); int len; byte[] arr = new byte[8192]; while((len = fis.read(arr))!= -1){ baos.write(arr,0,len); } String log = baos.toString(); viewText.setText(log); fis.close(); baos.close(); } protected void send() throws IOException { String message = sendText.getText(); String ip = tField.getText(); ip = ip.trim().length() == 0?"255.255.255.255":ip; send(message.getBytes(),ip); String time = getCurrentTime(); String sendMessage = time+" 我对:"+(ip.equals("255.255.255.255")?"所有人":ip)+"说:\r\n "+message+"\r\n\r\n"; viewText.append(sendMessage); //将发送的消息写入文件 writer.write(sendMessage); sendText.setText(""); } private void send(byte[] bytes, String ip) throws IOException { DatagramPacket packet = new DatagramPacket (bytes,bytes.length,InetAddress.getByName(ip),9999); socket.send(packet); } private String getCurrentTime() { Date date = new Date(System.currentTimeMillis()); SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日HH:mm:ss"); return format.format(date); } //接收消息的线程 private class Receive extends Thread{ @Override public void run() { super.run(); try { DatagramSocket socket = new DatagramSocket(9999); DatagramPacket packet = new DatagramPacket(new byte[8192], 8192); while(true){ socket.receive(packet); byte[]arr = packet.getData(); int len = packet.getLength(); if (arr[0] == -1 && len == 1) { shake(); continue; } String message = new String(arr,0,len); String time = getCurrentTime(); String ip = packet.getAddress().getHostAddress(); String receivedMessage = time+" "+ip+"对我说:\r\n"+message+"\r\n"; viewText.append(receivedMessage); //写入收到的消息 writer.write(receivedMessage); } } catch (Exception e) { } } } public static void main(String[] args) { new GUIChat_UDP(); } }