import java.awt.BorderLayout; import java.awt.Button; import java.awt.Color;import java.awt.Dimension; import java.awt.Font; import java.awt.Frame; import java.awt.Panel; import java.awt.Point; import java.awt.TextArea; importjava.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.File;import java.io.FileWriter; import java.io.IOException;import .DatagramPacket; import .DatagramSocket; import.InetAddress;import java.text.SimpleDateFormat; import java.util.Date; import java.util.Scanner;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class GUI_Chat extends Frame {private static final long serialVersionUID = 1L;private TextArea viewTextArea = new TextArea(20, 1; private TextArea sendTextArea = new TextArea(; private TextField ipTextField = new TextField(20; private Button sendButton = new Button(" 发送" ; private Button clearButton = new Button(" 清屏" ; private Button logButton = new Button(" 记录" ; private Button shakeButton = new Button(" 震动" ; private Panel panel = new Panel(; private DatagramSocket socket ;private Lock lock = new ReentrantLock(; private FileWriter fw ;public GUI_Chat( throws Exception {socket = new DatagramSocket(20000;fw = new FileWriter("log.txt" , true ;generateUI(; addListener(;new ReceiveThread(.start(;// 开启接收数据的线程}private void generateUI( { setTitle("GUI 聊天室" ; setSize(400, 600; setLocation(600, 50;setMinimumSize(new Dimension(400, 600; // 设置最小尺寸Font font = new Font("Courier New", Font.PLAIN , 15;viewTextArea .setFont(font; // 设置字体viewTextArea .setEditable(false ; // 设置不可编辑(会改变背景色viewTextArea .setBackground(Color.WHITE ; // 设置背景色add(viewTextArea , BorderLayout.NORTH ; // 把viewTextArea 放在上面sendTextArea .setFont(font;add(sendTextArea , BorderLayout.CENTER ; // 把sendTextArea 放在中间panel .add(ipTextField ; panel .add(sendButton ; panel .add(clearButton ; panel .add(logButton ;panel .add(shakeButton ;add(panel , BorderLayout.SOUTH ;// 把Panel 放在下面}private void addListener( { addWindowListener(new WindowAdapter( { // 关闭窗体public void windowClosing(WindowEvent e { try {fw .close(;} catch (IOException e1 { e1.printStackTrace(; }System. exit (0; } };sendButton .addActionListener(new ActionListener( { // 发送功能public void actionPerformed(ActionEvent e {send(;} };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(; // 取消当前事件 } } };clearButton .addActionListener(new ActionListener( { // 清屏功能 public void actionPerformed(ActionEvent e { viewTextArea .setText("" ; } };logButton .addActionListener(new ActionListener( { // 聊天记录public void actionPerformed(ActionEvent e { showLog(; } };shakeButton .addActionListener(new ActionListener( { public void actionPerformed(ActionEvent e { sendShake(; } }; }private void sendShake( { try {String ip = ipTextField .getText(; sendData(ip, new byte [] { -1 }; // 向执行IP 发送一个特殊的消息 } catch (Exception e { e.printStackTrace(; }}private void showLog( {try (Scanner scanner = new Scanner(new File("log.txt" ;{ viewTextArea .setText("" ; // 清屏fw .flush(;// 把未保存的数据写入文件while (scanner.hasNextLine( // 如过文件中有数据就进入循环viewTextArea .append(scanner.nextLine( + "\r\n"; // 从文件读取一行, 追加到viewTextArea 中} catch (Exception e { e.printStackTrace(; } }private void send( { try { String msg = sendTextArea .getText(; // 获取要发的内容String ip = ipTextField .getText(; // 获取目标地址ip = ip.trim(.length( == 0 ? "255.255.255.255" : ip;String content = getTime( + " 我对 <" + (ip.equals("255.255.255.255" ? " 所有人" : ip + "> 说: \r\n" + msg + "\r\n\r\n";lock .lock(; // 开始同步 sendData(ip, msg.getBytes(; // 发送数据sendTextArea .setText("" ; // 清空viewTextArea .append(content; // 把要显示的内容追加到viewTextArea 中fw .write(content; // 保存聊天记录 lock .unlock(; // 结束同步 } catch (Exception e { e.printStackTrace(; } }private void sendData(String ip, byte [] data throws Exception { DatagramPacket packet = new DatagramPacket(data, data. length , InetAddress. getByName (ip, 20000; socket .send(packet;// UDP发送数据}private String getTime( { Date date = new Date(;SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"; return sdf.format(date; // 返回当前时间字符串 }private class ReceiveThread extends Thread { public void run( {DatagramPacket packet = new DatagramPacket(new byte [8192], 8192; while (true { try {socket .receive(packet;byte [] arr = packet.getData(; int length = packet.getLength(;String s = new String(arr, 0, length; // 接收到的字符串String ip = packet.getAddress(.getHostAddress(;String content = getTime( + " <" + ip + "> 对我说:\r\n" + s + "\r\n\r\n"; // 在viewTextArea 中显示的内容if (length == 1 && arr[0] == -1 { // 判断是否收到震动消息 doShake(; // 震动(改变位置 continue ; // 进入下一次循环 }lock .lock(; // 开始同步viewTextArea .append(content;fw .write(content; // 保存聊天记录 lock .unlock(;// 结束同步} catch (IOException e { e.printStackTrace(; }}}}private void doShake( { //震动方法 (通过改变窗体的位置实现 try {Point point = getLocation(; for (int i = 0; i < 5; i++ { Thread. sleep (30;setLocation(point.x + 5, point.y ; Thread. sleep (30;setLocation(point.x - 5, point.y + 5; }setLocation(point;} catch (InterruptedException e { e.printStackTrace(; } }public static void main(String[] args throws Exception { new GUI_Chat(.setVisible(true ; }}。