今天跟着教学视频做了一个简易版的聊天工具,算是对以前知识的一些小总结
主要包含异常,IO流,简单的网络编程(UDP传输),GUI的简单设计,多线程的一些知识点.
package com.zixue.haha; 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.text.SimpleDateFormat; import java.util.Date; public class Demo05_GUIChat { /* * GUI聊天 */ public static void main(String[] args) { new ZhuTi(); } } class ZhuTi extends Frame{ private TextField tf; private Button send; private Button log; private Button clear; private Button shake; private TextArea viewText; private TextArea sendText; private DatagramSocket socket; private BufferedWriter bw; public ZhuTi() { chuangti(); //创建一个窗体 southPanel(); //创建南边的panel centerPanel(); //创建中间的panel event(); //监听事件 } public void event() { this.addWindowListener(new WindowAdapter() { //窗口监听,关闭窗口 @Override public void windowClosing(WindowEvent e) { socket.close(); try { bw.close(); } catch (IOException e1) { e1.printStackTrace(); } System.exit(0); } }); 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},tf.getText()); //因为震动是点击震动按钮让对方震动,相当于给对方发送了一个象征着震动的信息 } catch (IOException e1) { e1.printStackTrace(); } } }); sendText.addKeyListener(new KeyAdapter() { @Override public void keyReleased(KeyEvent e) { if(e.getKeyCode()==KeyEvent.VK_ENTER && e.isControlDown()) { //isControlDown() ctrl键是否被按下 try { send(); } catch (IOException e1) { e1.printStackTrace(); } } } }); } public void shake() { int x = this.getLocation().x; //获取横坐标位置 int y = this.getLocation().y; //获取纵坐标位置 try { this.setLocation(x+10, y); 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 (InterruptedException e) { e.printStackTrace(); } } private void logFile() throws IOException { bw.flush(); //刷新缓冲区 FileInputStream fis = new FileInputStream("config.txt"); //读取文件 ByteArrayOutputStream baos = new ByteArrayOutputStream(); //在内存中创建缓冲区 int len; byte [] arr = new byte[8192]; while((len=fis.read(arr))!=-1) { baos.write(arr,0,len); } String str = baos.toString(); //将内存中的内容转换成了字符串 viewText.setText(str); fis.close(); } private void send(byte[]arr,String ip) throws IOException { DatagramPacket packet = new DatagramPacket(arr,arr.length, InetAddress.getByName(ip), 9999); socket.send(packet); //发送数据 } private void send() throws IOException { String message = sendText.getText(); //获取发送区域的内容 String ip = tf.getText(); //获取IP地址 ip=ip.trim().length()==0?"255.255.255.255":ip; send(message.getBytes(),ip); String time = getCurrentTime(); //获取当前时间 String str = time+" 我对:"+(ip.equals("255.255.255.255")?"所有人":ip)+"说\r\n"+message+"\r\n\r\n"; //alt+shift+l抽取局部变量 viewText.append(str); //将信息添加到显示区域中 bw.write(str); //将信息写到数据库中(用文本文档模拟的) sendText.setText(""); //发送区域清空 } public String getCurrentTime() { Date d = new Date(); //创建当前日期对象 SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss"); return sdf.format(d); //将时间格式化返回 } public void centerPanel() { Panel center = new Panel(); //创建中间的panel viewText = new TextArea(); sendText = new TextArea(5,1); center.setLayout(new BorderLayout()); //设置为边界布局管理器 center.add(sendText,BorderLayout.SOUTH); //发送的文本区域在南边 center.add(viewText, BorderLayout.CENTER); //显示的区域放在中间 viewText.setEditable(false); //设置显示区域不可以编辑 viewText.setBackground(Color.WHITE); //设置显示区域的背景颜色 viewText.setFont(new Font("XXX", Font.PLAIN, 15));//设置显示区域字体 sendText.setFont(new Font("XXX", Font.PLAIN, 15));//设置发送区域字体 this.add(center,BorderLayout.CENTER); //将中间的panel放到frame中去 } public void southPanel() { Panel south = new Panel(); //创建南边的panel tf = new TextField(15); tf.setText("127.0.0.1"); send = new Button("发送"); log = new Button("记录"); clear = new Button("清屏"); shake = new Button("震动"); south.add(tf); //将文本字段加入到panel south.add(send); //将按钮加入到panel south.add(log); south.add(clear); south.add(shake); this.add(south,BorderLayout.SOUTH); //将southPanel放在Frame的南边 } public void chuangti() { this.setLocation(500, 50); //设置位置 this.setSize(400, 600); //设置大小 new Receive().start(); try { socket = new DatagramSocket(); bw = new BufferedWriter(new FileWriter("config.txt",true)); } catch (Exception e) { e.printStackTrace(); } this.setVisible(true); //设置可见 } private class Receive extends Thread{ //接受和发送需要同时执行,所以定义成多线程 @Override public void 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) { //如果发过来的数组第一个存储的值是-1,并且数组长度是1 shake(); //调用震动方法 continue; //如果出现这种情况,就跳出本次循环,因为震动后不需要执行下面的代码 } String message = new String(arr, 0, len); //将数据转换成字符串 String time = getCurrentTime(); //获取当前时间 String ip = packet.getAddress().getHostAddress(); //获取ip String str = time+" "+ip+" 对我说:\r\n"+message+"\r\n\r\n"; viewText.append(str); bw.write(str); } } catch (IOException e) { e.printStackTrace(); } } } }
是有些简陋哈,嘿嘿!
再接再厉!