package UDP;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.Point;
import java.awt.TextArea;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
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;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class Demo01_GUI extends JFrame {
public static void main(String[] args) {
gui1 = new Demo01_GUI();
gui1.southPanel();
gui1.centerPanel();
gui1.init();
gui1.event();
}
private JPanel south;
private JButton log;
private JTextField tf; // 存ip
private JButton send;
private JButton clear;
private JButton shake;
private JPanel center;
private TextArea viewText;
private TextArea sendText;
private DatagramSocket socket1;
private DatagramSocket socket;
private static Demo01_GUI gui1;
private BufferedWriter bw;
public Demo01_GUI() {
super("即时通讯");
}
/**
* 初始化窗体JFrame
*/
public void init() {
this.setSize(400, 600);// 设置窗体的大小
Point point = new Point(800, 300);// 设置显示坐标
this.setLocation(point);// 设置窗体的位置
this.setVisible(true);// 显示出设置好的窗体
try {
bw = new BufferedWriter(new FileWriter("config.txt", true));// 初始化的时候就要创建出这个写入文件
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
new Receive().start();// 启动接收消息线程
}
/**
* 创建Frame窗体中南边的JPanel
*/
public void southPanel() {
south = new JPanel();// 创建南边的JPanel
tf = new JTextField(8);// 创建文本字段,存储IP地址
tf.setText("127.0.0.1");// 给文本框设置默认的IP地址
send = new JButton("发送");// 创建第一个发送按钮
log = new JButton("记录");// 创建第一个记录按钮
clear = new JButton("清除");// 创建第一个清屏按钮
shake = new JButton("震动");// 创建第一个震动按钮
// 先要把创建好的这些按钮和文本字段放到这个Panel里面
south.add(tf);
south.add(send);
south.add(log);
south.add(clear);
south.add(shake);
// 然后再把这个Panel添加到Frame框的南边(下边)
this.add(south, BorderLayout.SOUTH);
}
/**
* 创建Frame窗体中中间的JPanel
*/
public void centerPanel() {
center = new JPanel(); // 创建中间的JPanel
// 中间的panel需要两个Textarea
viewText = new TextArea(); // 显示文本的区域
sendText = new TextArea(4, 1); // 发送文本的区域
center.setLayout(new BorderLayout());// 将JPanel设置为边界布局管理器
// 设置完Panel为边界布局管理器之后,就可以吧viewText和sendText分别设置到中间和南边
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);// 然后再把这个JPanel添加到JFrame框的中间
}
/**
* 设置关闭窗体按钮
*/
public void event() {
// 这个是表示在窗口添加一个Windows事件消息,目的是我们关闭窗口的时候可以正常的退出
this.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
try {
socket1.close();// 点击关闭窗体之前停止接收线程
bw.close();// 关闭这个流
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
System.exit(0);
}
});
send.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
try {
send();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
});
log.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
try {
logFile();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
/**
* 获取聊天记录
*/
private void logFile() throws IOException {
// TODO Auto-generated method stub
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();
}
});
/**
* 清屏功能
*/
clear.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
viewText.setText("");
}
});
/**
* 触发屏幕震动功能
*/
shake.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
try {
send(new byte[] { -1 }, tf.getText());// 调用给指定ip发送消息这个方法
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
});
/**
* 监听点击键盘回车键发送消息
*/
sendText.addKeyListener(new KeyAdapter() {
@Override
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
try {
send();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
});
}
/**
* 屏幕震动功能
*/
private void shake() {
int x = this.getLocation().x;// 获取横坐标位置
int y = this.getLocation().y;// 获取纵坐标位置
for (int i = 0; i < 10; i++) { // 循环改变窗体的位置
try {
this.setLocation(x + 20, y + 20);
Thread.sleep(20);
this.setLocation(x + 20, y - 20);
Thread.sleep(20);
this.setLocation(x - 20, y + 20);
Thread.sleep(20);
this.setLocation(x - 20, y - 20);
Thread.sleep(20);
this.setLocation(x, y);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* 接收和发送需要同时进行,所以定义成多线程的
*
* @author lenovo 接收消息
*/
private class Receive extends Thread {
public void run() {
try {
socket1 = new DatagramSocket(9996);
DatagramPacket packet = new DatagramPacket(new byte[8192], 8192);
while (true) {
socket1.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\r\n" + message + "\r\n\r\n";
bw.write(str);// 将接收的消息写入数据库
viewText.append(str);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 给指定ip发送消息
*
* @param arr
* @param ip
* @throws IOException
*/
private void send(byte[] arr, String ip) throws IOException {
DatagramPacket packet = new DatagramPacket(arr, arr.length, InetAddress.getByName(ip), 9996);
socket.send(packet);// 发送数据
}
/**
* 发送消息
*
* @throws IOException
*/
private void send() throws IOException {
// TODO Auto-generated method stub
String message = sendText.getText(); // 获取发送区域的内容
String ip = tf.getText(); // 获取ip地址
ip = ip.trim().length() == 0 ? "255.255.255.255" : ip;
socket = new DatagramSocket();
send(message.getBytes(), ip);// 调用send方法给指定ip发送消息
String time = getCurrentTime(); // 拿到当前时间
String str = time + "我对:" + (ip.equals("255.255.255.255") ? "所有人" : ip) + "说 \r\n\r\n" + message + "\r\n\r\n"; // alt+shift+L 抽取局部变量
viewText.append(str); // 将发送的信息添加到显示区域中
bw.write(str); // 将发送的消息写入数据库中
sendText.setText("");// 清空发送区域
}
/**
* 获取到当前系统时间
*
* @return
*/
private String getCurrentTime() {
Date date = new Date(); // 创建当前日期对象
SimpleDateFormat sdf = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss");// 格式化
return sdf.format(date); // 返回格式化后的时间
}
}