登录界面
package window;
import chat.ChatInfo;
import pojo.User;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
/**
* @author: 牧心
* @Date: 2020/09/07
* @Description: 登陆界面
*/
public class LoginWindow{
private static final int LOGIN_WINDOW_WIDTH = 500;
private static final int LOGIN_WINDOW_HEIGHT = 400;
private static LoginWindow loginWindow;
private JFrame loginFrame;
private JPanel loginPanel;
private JLabel titleLabel;
private JLabel usernameLabel;
private JTextField usernameInput;
private JButton loginBtn;
private LoginWindow(){
init();
}
/**
* 窗口初始化
*/
private void init(){
// 窗口标题
loginFrame = new JFrame("登录");
// 不可放缩
loginFrame.setResizable(false);
//
Container container = loginFrame.getContentPane();
/**********************/
//获取屏幕的大小
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
//任务栏高度
// int missionBoardHeight = Toolkit.getDefaultToolkit().getScreenInsets(new JFrame().getGraphicsConfiguration()).bottom;
int SCREEN_WIDHTH = (int) screenSize.getWidth();
int SCREEN_HEIGHT = (int)screenSize.getHeight();
/**********************/
// 窗口居中
loginFrame.setSize(LOGIN_WINDOW_WIDTH,
LOGIN_WINDOW_HEIGHT);
loginFrame.setLocation((SCREEN_WIDHTH - LOGIN_WINDOW_WIDTH)/2,
(SCREEN_HEIGHT - LOGIN_WINDOW_HEIGHT)/2);
loginFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
// 创建面板容器
loginPanel = new JPanel();
//
container.add(loginPanel);
// loginFrame.setContentPane(loginPanel);
// null布局
loginPanel.setLayout(null);
// 登录标题
titleLabel = new JLabel("登录");
titleLabel.setVerticalTextPosition(JLabel.CENTER);
titleLabel.setHorizontalTextPosition(JLabel.CENTER);
titleLabel.setFont(new Font(Font.SERIF, Font.BOLD, 50));
titleLabel.setBounds(new Rectangle(190, 40, 120, 60));
loginPanel.add(titleLabel);
// 用户名输入标签
usernameLabel = new JLabel("用户名:");
usernameLabel.setVerticalTextPosition(JLabel.CENTER);
usernameLabel.setHorizontalTextPosition(JLabel.CENTER);
usernameLabel.setFont(new Font(Font.SERIF, Font.BOLD, 20));
usernameLabel.setBounds(new Rectangle(80, 140, 80, 40));
loginPanel.add(usernameLabel);
// 用户名输入框
usernameInput = new JTextField();
usernameInput.setFont(new Font(Font.SERIF, Font.BOLD, 20));
usernameInput.setBounds(160, 140, 260, 40);
loginPanel.add(usernameInput);
// 登录按钮
loginBtn = new JButton("登录");
loginBtn.setVerticalTextPosition(JButton.CENTER);
loginBtn.setHorizontalTextPosition(JButton.CENTER);
// 去除点击按钮时文字周围的线框
loginBtn.setFocusPainted(false);
loginBtn.setFont(new Font(Font.SERIF, Font.BOLD, 30));
loginBtn.setBounds(80, 220, 340, 40);
// 绑定登录事件
loginBtn.addActionListener(e -> loginAction(e));
loginPanel.add(loginBtn);
//
// loginFrame.pack();
// 监听框架关闭按钮事件
loginFrame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
//
usernameInput.addKeyListener(new KeyListener() {
@Override
public void keyTyped(KeyEvent e) {}
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyChar() == KeyEvent.VK_ENTER){
loginBtn.doClick();
}
}
@Override
public void keyReleased(KeyEvent e) {}
});
//
loginFrame.setVisible(true);
}
/**
* 获取登录窗口
* @return
*/
public static LoginWindow getInstance(){
if (loginWindow == null){
loginWindow = new LoginWindow();
}
return loginWindow;
}
/**
* 登录按钮事件
* @param e
*/
private void loginAction(ActionEvent e){
String username = usernameInput.getText().trim();
if ("".equals(username)){
return;
}
// 销毁登录窗口
loginWindow.loginFrame.dispose();
loginWindow = null;
// 存储本机登录用户用户名
User user = new User(username);
ChatInfo.setUser(user);
// 进入群聊界面
ChatWindow.getInstance();
}
}
聊天界面
package window;
import chat.ChatHandler;
import chat.ChatInfo;
import chat.ChatReceiver;
import pojo.Message;
import pojo.User;
import javax.swing.*;
import java.awt.*;
import java.awt.datatransfer.StringSelection;
import java.awt.event.*;
/**
* @author: 牧心
* @Date: 2020/09/07
* @Description: 聊天界面
*/
public class ChatWindow {
private static final int CHAT_WINDOW_WIDTH = 800;
private static final int CHAT_WINDOW_HEIGHT = 620;
private User user;
private static ChatWindow chatWindow;
private JFrame chatFrame;
private JPanel chatPanel;
private JTextField msgInput;
private JButton sendBtn;
private JTextArea msgShowArea;
private JScrollPane scrollPane;
private JPopupMenu popupMenu;
private ChatWindow() {
this.user = ChatInfo.getUser();
init();
// 开启一个消息接收端线程
new Thread(new ChatReceiver()).start();
}
/**
*
*/
private void init() {
// 窗口标题
chatFrame = new JFrame(user.getUsername());
// 不可放缩
chatFrame.setResizable(false);
//
Container container = chatFrame.getContentPane();
/**********************/
//获取屏幕的大小
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
int SCREEN_WIDHTH = (int) screenSize.getWidth();
int SCREEN_HEIGHT = (int) screenSize.getHeight();
/**********************/
// 窗口居中
chatFrame.setSize(CHAT_WINDOW_WIDTH, CHAT_WINDOW_HEIGHT);
chatFrame.setLocation((SCREEN_WIDHTH - CHAT_WINDOW_WIDTH) / 2,
(SCREEN_HEIGHT - CHAT_WINDOW_HEIGHT) / 2);
chatFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
// 创建面板容器
chatPanel = new JPanel();
//
container.add(chatPanel);
// loginFrame.setContentPane(loginPanel);
// null布局
chatPanel.setLayout(null);
// 消息输入框
msgInput = new JTextField();
msgInput.setFont(new Font(Font.SERIF, Font.BOLD, 20));
msgInput.setBounds(20, 520, 620, 40);
// 实现点击enter键发送消息
msgInput.addKeyListener(new KeyListener() {
@Override
public void keyTyped(KeyEvent e) { }
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyChar() == KeyEvent.VK_ENTER) {
sendBtn.doClick();
}
}
@Override
public void keyReleased(KeyEvent e) {
}
});
chatPanel.add(msgInput);
// 发送按钮
sendBtn = new JButton("发送");
sendBtn.setVerticalTextPosition(JButton.CENTER);
sendBtn.setHorizontalTextPosition(JButton.CENTER);
// 去除点击按钮时文字周围的线框
sendBtn.setFocusPainted(false);
sendBtn.setFont(new Font(Font.SERIF, Font.BOLD, 20));
sendBtn.setBounds(660, 520, 120, 40);
//
sendBtn.addActionListener(e -> {
try {
sendMessage();
} catch (Exception e1) {
e1.printStackTrace();
}
});
//
chatPanel.add(sendBtn);
// 消息输入框
msgShowArea = new JTextArea();
msgShowArea.setFont(new Font(Font.SERIF, Font.BOLD, 20));
// msgShowArea.setBounds(20, 20, 760, 470);
// 自动换行
msgShowArea.setLineWrap(true);
//
scrollPane = new JScrollPane(msgShowArea);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
scrollPane.setBounds(20, 20, 760, 470);
// chatPanel.add(msgShowArea);
chatPanel.add(scrollPane);
msgShowArea.setEditable(false);
// 消息展示区右键菜单
popupMenu = new JPopupMenu();
JMenuItem copy = new JMenuItem("复制");
copy.setFont(new Font(Font.SERIF, Font.TRUETYPE_FONT, 18));
copy.setFocusPainted(false);
copy.setSize(160, 30);
// 点击复制,将选中内容复制到截切板
copy.addActionListener(e -> {
String selectText = msgShowArea.getSelectedText().trim();
if (!"".equals(selectText)){
StringSelection selection = new StringSelection(selectText);
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(selection, selection);
}
});
popupMenu.add(copy);
msgShowArea.setComponentPopupMenu(popupMenu);
//
msgShowArea.setSelectedTextColor(Color.orange);
// 监听框架关闭按钮事件
chatFrame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
// 退出程序
System.exit(0);
}
});
//
chatFrame.setVisible(true);
}
/**
* 发送消息
*/
private void sendMessage() throws Exception {
String msg = msgInput.getText().trim();
if (!"".equals(msg)) {
// 清空消息输入框
msgInput.setText("");
// 将消息追加到消息列表
Message message = new Message(user.getUsername(), msg);
// 将消息展示在消息区
ChatHandler.sendMessage(message);
}
}
/**
* 单例模式
* @return
*/
public static ChatWindow getInstance() {
if (chatWindow == null) {
chatWindow = new ChatWindow();
}
return chatWindow;
}
/**
* 像文本域追加消息记录
* @param message
*/
private void showMsg(Message message) {
if (!"".equals(message.getMessage())) {
msgShowArea.append("@");
msgShowArea.append(message.getUsername());
msgShowArea.append("\t");
msgShowArea.append(message.getDatestamp());
msgShowArea.append("\n ");
msgShowArea.append(message.getMessage());
msgShowArea.append("\n");
}
msgShowArea.setCaretPosition(msgShowArea.getText().length());
}
/**
* @param message
*/
public void displayMessage(Message message) {
showMsg(message);
}
}
消息接收线程
package chat;
import pojo.Message;
import window.ChatWindow;
import java.io.ByteArrayInputStream;
import java.io.ObjectInputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
/**
* @author: 牧心
* @Date: 2020/09/07
* @Description: 用来接收消息
*/
public class ChatReceiver implements Runnable {
private DatagramSocket socket;
public ChatReceiver() {
try {
socket = new DatagramSocket(8633);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 接收消息
*/
private void receive() {
try {
byte[] bytes = new byte[1024 * 16];
DatagramPacket packet = new DatagramPacket(bytes, bytes.length);
socket.receive(packet);
// 处理接收到的数据
ByteArrayInputStream bais = new ByteArrayInputStream(packet.getData());
ObjectInputStream ois = new ObjectInputStream(bais);
// 将数据转为Message对象
Message message = (Message) ois.readObject();
// 将数据展示在消息区域
ChatWindow.getInstance().displayMessage(message);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void run() {
while (true) {
receive();
}
}
}
消息发送类
package chat;
import pojo.Message;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
/**
* @author: 牧心
* @Date: 2020/09/07
* @Description: 用来广播消息
*/
public class ChatHandler {
private static DatagramSocket socket;
private static ByteArrayOutputStream baos;
private static ObjectOutputStream oos;
static {
try {
socket = new DatagramSocket();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void sendMessage(Message message) throws Exception {
//
baos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(baos);
oos.writeObject(message);
byte[] bytes = baos.toByteArray();
//
int len = bytes.length;
//广播消息
InetAddress address = InetAddress.getByName("255.255.255.255");
// 创建广播消息数据包
DatagramPacket packet = new DatagramPacket(bytes, len, address, 8633);
oos.flush();
socket.send(packet);
}
}
存储本机登录用户信息
package chat;
import pojo.User;
/**
* @author: 牧心
* @Date: 2020/09/07
* @Description: 存储本机登录用户信息
*/
public class ChatInfo {
private static User self = null;
public static User getUser(){
return self;
}
public static void setUser(User user){
self = user;
}
}
消息体
package pojo;
import utils.DateUtils;
import java.io.Serializable;
/**
* @author: 牧心
* @Date: 2020/09/07
* @Description:
*/
public class Message implements Serializable {
private String username;
private String message;
private String datestamp;
public Message(String username, String message) {
this.username = username;
this.message = message;
this.datestamp = DateUtils.getDateStamp();
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getDatestamp() {
return datestamp;
}
public void setDatestamp(String datestamp) {
this.datestamp = datestamp;
}
@Override
public String toString() {
return "Message{" +
"username='" + username + '\'' +
", message='" + message + '\'' +
", datestamp='" + datestamp + '\'' +
'}';
}
}
用户实体类
package pojo;
/**
* @author: 牧心
* @Date: 2020/09/07
* @Description:
*/
public class User {
public String username;
public User(String username) {
this.username = username;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
时间戳工具类
package utils;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author: 牧心
* @Date: 2020/09/07
* @Description: 日期工具类
*/
public class DateUtils {
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
/**
* 获取当前时间戳字符串
* @return
*/
public static String getDateStamp() {
return dateFormat.format(new Date());
}
}
程序启动类
import window.LoginWindow;
/**
* @author: 牧心
* @Date: 2020/09/07
* @Description: 程序启动类
*/
public class ChatStarter {
public static void main(String[] args){
// 从登陆界面开始
LoginWindow.getInstance();
}
}