本帖最后由 曹睿翔 于 2013-6-8 08:30 编辑
- <P> package com.itheima.udp.exercise;
- import java.awt.BorderLayout;
- import java.awt.Button;
- import java.awt.Color;
- import java.awt.Dimension;
- import java.awt.Frame;
- import java.awt.Panel;
- import java.awt.Point;
- 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 GUI_Chat extends Frame {
- private static final long serialVersionUID = 1L;
- private TextArea viewTextArea = new TextArea(); // 用来显示聊天记录的文本域
- private TextArea sendTextArea = new TextArea(5, 1); // 用来输入消息的文本域(指定行数和列数,
- // 列数由于是边界布局所以无效)
- private TextField textField = new TextField(20); // 用来输入IP的文本框
- private Button sendButton = new Button("发送");
- private Button clearButton = new Button("清屏");
- private Button logButton = new Button("记录");
- private Button shakeButton = new Button("震动");
- private Panel southPanel = new Panel(); // 放在南边的面板(TextField, 4个Button)
- private Panel cenerPanel = new Panel(); // 放在中间的面板(2个TextArea)
- private DatagramSocket socket;
- private BufferedWriter bw;
- /*
- * 构造函数
- */
- public GUI_Chat() {
- init(); // 初始化
- generateSouthPanel(); // 构造南边的面板
- generateCenterPanel(); // 构造中间的面板
- addListener(); // 添加监听器
- setVisible(true); // 显示
- new ReceiveThread().start(); // 开启接收数据的线程
- }
- /*
- * 初始化 设置Frame的标题, 大小, 位置 创建了Socket对象
- */
- private void init() {
- setTitle("GUI聊天室");
- setSize(400, 600);
- setLocation(800, 50);
- setMinimumSize(new Dimension(400, 300));
- try {
- socket = new DatagramSocket(); // 发送端Socket可以不用指定地址(本机)和端口(随机的)
- bw = new BufferedWriter(new FileWriter("log.txt", true));
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- /*
- * 构造南边的面板 把TextField和4个Button一起放入Panel 把Panel放在南边
- */
- private void generateSouthPanel() {
- southPanel.add(textField);
- southPanel.add(sendButton);
- southPanel.add(clearButton);
- southPanel.add(logButton);
- southPanel.add(shakeButton);
- add(southPanel, BorderLayout.SOUTH); // 把面板放在Frame的南边
- }
- /*
- * 构造中间的面板 把两个TextArea装入Panel 把Panel放在中间
- */
- private void generateCenterPanel() {
- cenerPanel.setLayout(new BorderLayout()); // 把面板改为边界布局
- cenerPanel.add(viewTextArea, BorderLayout.CENTER); // 用来显示的文本域放在中间
- cenerPanel.add(sendTextArea, BorderLayout.SOUTH); // 用来发送的文本域放在下面
- add(cenerPanel, BorderLayout.CENTER); // 把整个面板放在Frame的中间
- viewTextArea.setEditable(false); // 设置为不可编辑, 会改变背景色为灰色
- viewTextArea.setBackground(Color.WHITE); // 设置背景色为白色
- }
- /*
- * 给各个组件添加添加监听器
- */
- private void addListener() {
- addWindowListener(new WindowAdapter() { // 关闭窗体时, 释放资源, 退出程序
- public void windowClosing(WindowEvent e) {
- try {
- bw.close();
- socket.close();
- System.exit(0);
- } catch (IOException ex) {
- ex.printStackTrace();
- }
- }
- });
- sendButton.addActionListener(new ActionListener() { // 点击发送按钮时
- public void actionPerformed(ActionEvent e) {
- send();
- }
- });
- clearButton.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- viewTextArea.setText("");
- }
- });
- logButton.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- showLog();
- }
- });
- sendTextArea.addKeyListener(new KeyAdapter() {
- public void keyPressed(KeyEvent e) {
- if (e.isControlDown() && e.getKeyCode() == KeyEvent.VK_ENTER
- || e.isAltDown() && e.getKeyCode() == KeyEvent.VK_S) {
- send();
- e.consume(); // 取消这个事件
- }
- }
- });
- shakeButton.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- sendShake();
- }
- });
- }
- private void sendShake() {
- try {
- String ip = textField.getText().trim();
- DatagramPacket packet = new DatagramPacket(new byte[] { -1 }, 1,
- InetAddress.getByName(ip), 20000);
- socket.send(packet);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- /*
- * 发送消息
- */
- private void send() {
- String msg = sendTextArea.getText(); // 获取要发送的内容
- String ip = textField.getText().trim(); // 获取目标地址
- ip = ip.length() == 0 ? "255.255.255.255" : ip; // 如果没填IP, 默认改为群发地址
- try {
- DatagramPacket packet = new DatagramPacket(msg.getBytes(),
- msg.getBytes().length, InetAddress.getByName(ip), 20000); // 创建Packet
- String time = getTimeString();
- String info = time + " 我对 "
- + (ip.equals("255.255.255.255") ? "所有人" : ip) + " 说:\r\n"
- + msg + "\r\n\r\n";
- synchronized (this) {
- socket.send(packet); // 发送
- viewTextArea.append(info); // 显示发送的内容到TextView
- bw.write(info); // 保存聊天记录
- }
- sendTextArea.setText(""); // 清空文本域
- sendTextArea.requestFocus(); // 控制文本域重新获得焦点
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- /*
- * 获取当前时间字符串
- */
- private String getTimeString() {
- Date date = new Date();
- SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- return sdf.format(date);
- }
- /*
- * 用来接收数据的线程 不停地循环接收数据 收到数据后显示到TextArea中
- */
- private class ReceiveThread extends Thread {
- public void run() {
- try {
- DatagramSocket socket = new DatagramSocket(20000);
- DatagramPacket packet = new DatagramPacket(
- new byte[1024 * 1024], 1024 * 1024);
- while (true) {
- socket.receive(packet); // 收取数据
- byte[] arr = packet.getData(); // 获取packet中的数据
- int len = packet.getLength(); // 获取长度
- if (len == 1 && arr[0] == -1) {
- shake();
- continue;
- }
- String msg = new String(arr, 0, len); // 把字节数据转为String
- String ip = packet.getAddress().getHostAddress(); // 从packet中获取发送端的获取IP
- String time = getTimeString(); // 获取当前时间
- String info = time + " " + ip + " 对我说:\r\n" + msg
- + "\r\n\r\n";
- synchronized (GUI_Chat.this) { // 用外部类对象当作锁对象
- viewTextArea.append(info); // 显示到TextView
- bw.write(info); // 保存聊天记录
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- /*
- * 从文件中读取聊天记录 显示到TextArea中
- */
- private void showLog() {
- try {
- bw.flush(); // 把缓冲区中数据刷出
- FileInputStream fis = new FileInputStream("log.txt");
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- byte[] buffer = new byte[1024];
- int len;
- while ((len = fis.read(buffer)) != -1)
- // 从文件读取到内存
- baos.write(buffer, 0, len);
- fis.close();
- baos.close();
- String log = new String(baos.toByteArray()); // 从内存获取数据转为字符串
- viewTextArea.setText(log); // 显示
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- private void shake() {
- try {
- Point p = getLocation();
- setLocation(p.x - 20, p.y - 20);
- Thread.sleep(20);
- setLocation(p.x + 20, p.y + 20);
- Thread.sleep(20);
- setLocation(p.x + 20, p.y - 20);
- Thread.sleep(20);
- setLocation(p.x - 20, p.y + 20);
- Thread.sleep(20);
- setLocation(p);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- public static void main(String[] args) {
- new GUI_Chat();
- }
- }
- </P>
复制代码 |