A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© shiweiCao 中级黑马   /  2013-6-7 19:34  /  1679 人查看  /  3 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 曹睿翔 于 2013-6-8 08:30 编辑

  1. <P> package com.itheima.udp.exercise;

  2. import java.awt.BorderLayout;
  3. import java.awt.Button;
  4. import java.awt.Color;
  5. import java.awt.Dimension;
  6. import java.awt.Frame;
  7. import java.awt.Panel;
  8. import java.awt.Point;
  9. import java.awt.TextArea;
  10. import java.awt.TextField;
  11. import java.awt.event.ActionEvent;
  12. import java.awt.event.ActionListener;
  13. import java.awt.event.KeyAdapter;
  14. import java.awt.event.KeyEvent;
  15. import java.awt.event.WindowAdapter;
  16. import java.awt.event.WindowEvent;
  17. import java.io.BufferedWriter;
  18. import java.io.ByteArrayOutputStream;
  19. import java.io.FileInputStream;
  20. import java.io.FileWriter;
  21. import java.io.IOException;
  22. import java.net.DatagramPacket;
  23. import java.net.DatagramSocket;
  24. import java.net.InetAddress;
  25. import java.text.SimpleDateFormat;
  26. import java.util.Date;

  27. public class GUI_Chat extends Frame {

  28. private static final long serialVersionUID = 1L;

  29. private TextArea viewTextArea = new TextArea(); // 用来显示聊天记录的文本域
  30. private TextArea sendTextArea = new TextArea(5, 1); // 用来输入消息的文本域(指定行数和列数,
  31. // 列数由于是边界布局所以无效)
  32. private TextField textField = new TextField(20); // 用来输入IP的文本框
  33. private Button sendButton = new Button("发送");
  34. private Button clearButton = new Button("清屏");
  35. private Button logButton = new Button("记录");
  36. private Button shakeButton = new Button("震动");
  37. private Panel southPanel = new Panel(); // 放在南边的面板(TextField, 4个Button)
  38. private Panel cenerPanel = new Panel(); // 放在中间的面板(2个TextArea)

  39. private DatagramSocket socket;
  40. private BufferedWriter bw;

  41. /*
  42. * 构造函数
  43. */
  44. public GUI_Chat() {
  45. init(); // 初始化
  46. generateSouthPanel(); // 构造南边的面板
  47. generateCenterPanel(); // 构造中间的面板
  48. addListener(); // 添加监听器
  49. setVisible(true); // 显示
  50. new ReceiveThread().start(); // 开启接收数据的线程
  51. }

  52. /*
  53. * 初始化 设置Frame的标题, 大小, 位置 创建了Socket对象
  54. */
  55. private void init() {
  56. setTitle("GUI聊天室");
  57. setSize(400, 600);
  58. setLocation(800, 50);
  59. setMinimumSize(new Dimension(400, 300));
  60. try {
  61. socket = new DatagramSocket(); // 发送端Socket可以不用指定地址(本机)和端口(随机的)
  62. bw = new BufferedWriter(new FileWriter("log.txt", true));
  63. } catch (Exception e) {
  64. e.printStackTrace();
  65. }
  66. }

  67. /*
  68. * 构造南边的面板 把TextField和4个Button一起放入Panel 把Panel放在南边
  69. */
  70. private void generateSouthPanel() {
  71. southPanel.add(textField);
  72. southPanel.add(sendButton);
  73. southPanel.add(clearButton);
  74. southPanel.add(logButton);
  75. southPanel.add(shakeButton);
  76. add(southPanel, BorderLayout.SOUTH); // 把面板放在Frame的南边
  77. }

  78. /*
  79. * 构造中间的面板 把两个TextArea装入Panel 把Panel放在中间
  80. */
  81. private void generateCenterPanel() {
  82. cenerPanel.setLayout(new BorderLayout()); // 把面板改为边界布局
  83. cenerPanel.add(viewTextArea, BorderLayout.CENTER); // 用来显示的文本域放在中间
  84. cenerPanel.add(sendTextArea, BorderLayout.SOUTH); // 用来发送的文本域放在下面
  85. add(cenerPanel, BorderLayout.CENTER); // 把整个面板放在Frame的中间
  86. viewTextArea.setEditable(false); // 设置为不可编辑, 会改变背景色为灰色
  87. viewTextArea.setBackground(Color.WHITE); // 设置背景色为白色
  88. }

  89. /*
  90. * 给各个组件添加添加监听器
  91. */
  92. private void addListener() {
  93. addWindowListener(new WindowAdapter() { // 关闭窗体时, 释放资源, 退出程序
  94. public void windowClosing(WindowEvent e) {
  95. try {
  96. bw.close();
  97. socket.close();
  98. System.exit(0);
  99. } catch (IOException ex) {
  100. ex.printStackTrace();
  101. }
  102. }
  103. });
  104. sendButton.addActionListener(new ActionListener() { // 点击发送按钮时
  105. public void actionPerformed(ActionEvent e) {
  106. send();
  107. }
  108. });
  109. clearButton.addActionListener(new ActionListener() {
  110. public void actionPerformed(ActionEvent e) {
  111. viewTextArea.setText("");
  112. }
  113. });
  114. logButton.addActionListener(new ActionListener() {
  115. public void actionPerformed(ActionEvent e) {
  116. showLog();
  117. }
  118. });
  119. sendTextArea.addKeyListener(new KeyAdapter() {
  120. public void keyPressed(KeyEvent e) {
  121. if (e.isControlDown() && e.getKeyCode() == KeyEvent.VK_ENTER
  122. || e.isAltDown() && e.getKeyCode() == KeyEvent.VK_S) {
  123. send();
  124. e.consume(); // 取消这个事件
  125. }
  126. }
  127. });
  128. shakeButton.addActionListener(new ActionListener() {
  129. public void actionPerformed(ActionEvent e) {
  130. sendShake();
  131. }
  132. });
  133. }

  134. private void sendShake() {
  135. try {
  136. String ip = textField.getText().trim();
  137. DatagramPacket packet = new DatagramPacket(new byte[] { -1 }, 1,
  138. InetAddress.getByName(ip), 20000);
  139. socket.send(packet);
  140. } catch (Exception e) {
  141. e.printStackTrace();
  142. }
  143. }

  144. /*
  145. * 发送消息
  146. */
  147. private void send() {
  148. String msg = sendTextArea.getText(); // 获取要发送的内容
  149. String ip = textField.getText().trim(); // 获取目标地址
  150. ip = ip.length() == 0 ? "255.255.255.255" : ip; // 如果没填IP, 默认改为群发地址

  151. try {
  152. DatagramPacket packet = new DatagramPacket(msg.getBytes(),
  153. msg.getBytes().length, InetAddress.getByName(ip), 20000); // 创建Packet
  154. String time = getTimeString();
  155. String info = time + " 我对 "
  156. + (ip.equals("255.255.255.255") ? "所有人" : ip) + " 说:\r\n"
  157. + msg + "\r\n\r\n";
  158. synchronized (this) {
  159. socket.send(packet); // 发送
  160. viewTextArea.append(info); // 显示发送的内容到TextView
  161. bw.write(info); // 保存聊天记录
  162. }
  163. sendTextArea.setText(""); // 清空文本域
  164. sendTextArea.requestFocus(); // 控制文本域重新获得焦点
  165. } catch (Exception e) {
  166. e.printStackTrace();
  167. }
  168. }

  169. /*
  170. * 获取当前时间字符串
  171. */
  172. private String getTimeString() {
  173. Date date = new Date();
  174. SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  175. return sdf.format(date);
  176. }

  177. /*
  178. * 用来接收数据的线程 不停地循环接收数据 收到数据后显示到TextArea中
  179. */
  180. private class ReceiveThread extends Thread {
  181. public void run() {
  182. try {
  183. DatagramSocket socket = new DatagramSocket(20000);
  184. DatagramPacket packet = new DatagramPacket(
  185. new byte[1024 * 1024], 1024 * 1024);
  186. while (true) {
  187. socket.receive(packet); // 收取数据
  188. byte[] arr = packet.getData(); // 获取packet中的数据
  189. int len = packet.getLength(); // 获取长度
  190. if (len == 1 && arr[0] == -1) {
  191. shake();
  192. continue;
  193. }
  194. String msg = new String(arr, 0, len); // 把字节数据转为String
  195. String ip = packet.getAddress().getHostAddress(); // 从packet中获取发送端的获取IP
  196. String time = getTimeString(); // 获取当前时间
  197. String info = time + " " + ip + " 对我说:\r\n" + msg
  198. + "\r\n\r\n";
  199. synchronized (GUI_Chat.this) { // 用外部类对象当作锁对象
  200. viewTextArea.append(info); // 显示到TextView
  201. bw.write(info); // 保存聊天记录
  202. }
  203. }
  204. } catch (Exception e) {
  205. e.printStackTrace();
  206. }
  207. }
  208. }

  209. /*
  210. * 从文件中读取聊天记录 显示到TextArea中
  211. */
  212. private void showLog() {
  213. try {
  214. bw.flush(); // 把缓冲区中数据刷出

  215. FileInputStream fis = new FileInputStream("log.txt");
  216. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  217. byte[] buffer = new byte[1024];
  218. int len;
  219. while ((len = fis.read(buffer)) != -1)
  220. // 从文件读取到内存
  221. baos.write(buffer, 0, len);
  222. fis.close();
  223. baos.close();

  224. String log = new String(baos.toByteArray()); // 从内存获取数据转为字符串
  225. viewTextArea.setText(log); // 显示
  226. } catch (Exception e) {
  227. e.printStackTrace();
  228. }
  229. }

  230. private void shake() {
  231. try {
  232. Point p = getLocation();
  233. setLocation(p.x - 20, p.y - 20);
  234. Thread.sleep(20);
  235. setLocation(p.x + 20, p.y + 20);
  236. Thread.sleep(20);
  237. setLocation(p.x + 20, p.y - 20);
  238. Thread.sleep(20);
  239. setLocation(p.x - 20, p.y + 20);
  240. Thread.sleep(20);
  241. setLocation(p);
  242. } catch (InterruptedException e) {
  243. e.printStackTrace();
  244. }
  245. }

  246. public static void main(String[] args) {
  247. new GUI_Chat();
  248. }

  249. }
  250. </P>
复制代码

评分

参与人数 1技术分 +1 收起 理由
曹睿翔 + 1 很给力!

查看全部评分

3 个回复

倒序浏览
用代码块会好看点!
回复 使用道具 举报
曹睿翔 发表于 2013-6-7 22:07
用代码块会好看点!

嗯,谢谢, 以后会注意的.
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马