实现效果

image.png

代码实现

Demo04MyGUIChat.java

  1. package cn.giteasy.socket;
  2. import java.awt.*;
  3. import java.awt.event.ActionEvent;
  4. import java.awt.event.ActionListener;
  5. import java.awt.event.KeyAdapter;
  6. import java.awt.event.KeyEvent;
  7. import java.awt.event.WindowAdapter;
  8. import java.awt.event.WindowEvent;
  9. import java.io.*;
  10. import java.net.DatagramPacket;
  11. import java.net.DatagramSocket;
  12. import java.net.InetAddress;
  13. import java.text.SimpleDateFormat;
  14. import java.util.Date;
  15. public class Demo04MyGUIChat extends Frame {
  16. private TextField tf;
  17. private Button send;
  18. private Button log;
  19. private Button clear;
  20. private Button shake;
  21. private TextArea viewText;
  22. private TextArea sendText;
  23. private DatagramSocket socket;
  24. private BufferedWriter bw;
  25. public Demo04MyGUIChat() {
  26. init();
  27. southPanel();
  28. centerPanel();
  29. event();
  30. }
  31. public void event() {
  32. this.addWindowListener(new WindowAdapter() {
  33. @Override
  34. public void windowClosing(WindowEvent e) {
  35. try {
  36. socket.close();
  37. bw.close();
  38. } catch (IOException e1) {
  39. e1.printStackTrace();
  40. }
  41. System.exit(0);
  42. }
  43. });
  44. send.addActionListener(new ActionListener() {
  45. @Override
  46. public void actionPerformed(ActionEvent e) {
  47. try {
  48. send();
  49. } catch (IOException e1) {
  50. e1.printStackTrace();
  51. }
  52. }
  53. });
  54. log.addActionListener(new ActionListener() {
  55. @Override
  56. public void actionPerformed(ActionEvent e) {
  57. try {
  58. logFile();
  59. } catch (IOException e1) {
  60. e1.printStackTrace();
  61. }
  62. }
  63. });
  64. clear.addActionListener(new ActionListener() {
  65. @Override
  66. public void actionPerformed(ActionEvent e) {
  67. viewText.setText("");
  68. }
  69. });
  70. shake.addActionListener(new ActionListener() {
  71. @Override
  72. public void actionPerformed(ActionEvent e) {
  73. try {
  74. send(new byte[]{-1},tf.getText());
  75. } catch (IOException e1) {
  76. e1.printStackTrace();
  77. }
  78. }
  79. });
  80. sendText.addKeyListener(new KeyAdapter() {
  81. @Override
  82. public void keyReleased(KeyEvent e) {
  83. //if(e.getKeyCode() == KeyEvent.VK_ENTER && e.isControlDown()) { //isControlDown ctrl是否被按下
  84. if(e.getKeyCode() == KeyEvent.VK_ENTER) {
  85. try {
  86. send();
  87. } catch (IOException e1) {
  88. e1.printStackTrace();
  89. }
  90. }
  91. }
  92. });
  93. }
  94. private void shake() {
  95. int x = this.getLocation().x; //获取横坐标位置
  96. int y = this.getLocation().y; //获取纵坐标位置
  97. for(int i = 0; i < 3; i++) {
  98. try {
  99. this.setLocation(x + 5, y + 5);
  100. Thread.sleep(20);
  101. this.setLocation(x + 5, y - 5);
  102. Thread.sleep(20);
  103. this.setLocation(x - 5, y + 5);
  104. Thread.sleep(20);
  105. this.setLocation(x - 5, y - 5);
  106. Thread.sleep(20);
  107. this.setLocation(x, y);
  108. } catch (InterruptedException e) {
  109. e.printStackTrace();
  110. }
  111. }
  112. }
  113. private void logFile() throws IOException {
  114. bw.flush(); //刷新缓冲区
  115. FileInputStream fis = new FileInputStream("db.txt");
  116. ByteArrayOutputStream baos = new ByteArrayOutputStream(); //在内存中创建缓冲区
  117. int len;
  118. byte[] arr = new byte[8192];
  119. while((len = fis.read(arr)) != -1) {
  120. baos.write(arr, 0, len);
  121. }
  122. String str = baos.toString(); //将内存中的内容转换成了字符串
  123. viewText.setText(str);
  124. fis.close();
  125. }
  126. private void send(byte[] arr, String ip) throws IOException {
  127. DatagramPacket packet =
  128. new DatagramPacket(arr, arr.length, InetAddress.getByName(ip), 9999);
  129. socket.send(packet); //发送数据
  130. }
  131. private void send() throws IOException {
  132. String message = sendText.getText(); //获取发送区域的内容
  133. String ip = tf.getText(); //获取ip地址;
  134. ip = ip.trim().length() == 0 ? "255.255.255.255" : ip;
  135. send(message.getBytes(),ip);
  136. String time = getCurrentTime(); //获取当前时间
  137. String str = time + " 我对:" + (ip.equals("255.255.255.255") ? "所有人" : ip) + "说\r\n" + message + "\r\n\r\n"; //alt + shift + l 抽取局部变量
  138. viewText.append(str); //将信息添加到显示区域中
  139. bw.write(str); //将信息写到数据库中
  140. sendText.setText("");
  141. }
  142. private String getCurrentTime() {
  143. Date d = new Date(); //创建当前日期对象
  144. SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
  145. return sdf.format(d); //将时间格式化
  146. }
  147. public void centerPanel() {
  148. Panel center = new Panel(); //创建中间的Panel
  149. viewText = new TextArea();
  150. sendText = new TextArea(5,1);
  151. center.setLayout(new BorderLayout()); //设置为边界布局管理器
  152. center.add(sendText,BorderLayout.SOUTH); //发送的文本区域放在南边
  153. center.add(viewText,BorderLayout.CENTER); //显示区域放在中间
  154. viewText.setEditable(false); //设置不可以编辑
  155. viewText.setBackground(Color.WHITE); //设置背景颜色
  156. sendText.setFont(new Font("xxx", Font.PLAIN, 15));
  157. viewText.setFont(new Font("xxx", Font.PLAIN, 15));
  158. this.add(center,BorderLayout.CENTER);
  159. }
  160. public void southPanel() {
  161. Panel south = new Panel(); //创建南边的Panel
  162. tf = new TextField(15);
  163. tf.setText("127.0.0.1");
  164. send = new Button("send");
  165. log = new Button("logs");
  166. clear = new Button("clear");
  167. shake = new Button("shake");
  168. south.add(tf);
  169. south.add(send);
  170. south.add(log);
  171. south.add(clear);
  172. south.add(shake);
  173. this.add(south,BorderLayout.SOUTH); //将Panel放在Frame的南边
  174. }
  175. public void init() {
  176. this.setLocation(500, 50);
  177. this.setSize(400, 600);
  178. this.setTitle("聊天室");
  179. this.setIconImage(Toolkit.getDefaultToolkit().createImage(".\\009网络编程\\weixin.png"));
  180. new Receive().start();
  181. try {
  182. socket = new DatagramSocket();
  183. File file = new File("db.txt");
  184. if(!file.exists()){
  185. file.createNewFile();
  186. }
  187. bw = new BufferedWriter(new FileWriter(file,true)); //需要在尾部追加
  188. } catch (Exception e) {
  189. e.printStackTrace();
  190. }
  191. this.setVisible(true);
  192. }
  193. private class Receive extends Thread { //接收和发送需要同时执行,所以定义成多线程的
  194. @Override
  195. public void run() {
  196. try {
  197. DatagramSocket socket = new DatagramSocket(9999);
  198. DatagramPacket packet = new DatagramPacket(new byte[8192], 8192);
  199. while(true) {
  200. socket.receive(packet); //接收信息
  201. byte[] arr = packet.getData(); //获取字节数据
  202. int len = packet.getLength(); //获取有效的字节数据
  203. if(arr[0] == -1 && len == 1) { //如果发过来的数组第一个存储的值是-1,并且数组长度是1
  204. shake(); //调用震动方法
  205. continue; //终止本次循环,继续下次循环,因为震动后不需要执行下面的代码
  206. }
  207. String message = new String(arr,0,len); //转换成字符串
  208. String time = getCurrentTime(); //获取当前时间
  209. String ip = packet.getAddress().getHostAddress(); //获取ip地址
  210. String str = time + " " + ip + " 对我说:\r\n" + message + "\r\n\r\n";
  211. viewText.append(str);
  212. bw.write(str);
  213. }
  214. } catch (Exception e) {
  215. e.printStackTrace();
  216. }
  217. }
  218. }
  219. public static void main(String[] args) {
  220. new Demo04MyGUIChat();
  221. }
  222. }