核心类
核心类设计逻辑
数据结构设计(data.h)
- 用户信息
- 用户ID
- 用户网名
- 用户个人签名
- 用户手机号码
- 用户头像
- 聊天会话信息
- 会话编号
- 会话名称(单聊则是对方网名,群聊则是群名)
- 最新消息
- 会话图标(单聊对方头像,群聊则群聊头像)
- 判断单聊还是群聊
- 消息信息
- 消息类型
- 文本消息
- 图片消息
- 文件消息
- 语音消息
- 消息的编号
- 消息所属文件的编号
- 消息的时间
- 发送者的信息
- 消息内容
- 文件的消息身份标识(除文本消息外,其他消息生效)
- 文件名称(只有文件消息的时候有效,因为文件消息是不需要实时显示)
工厂设计模式构建消息信息
- 目的:根据消息类型,返回一个对应的消息类型的信息
- 类中成员函数说明
- makeId:利用uuID创建一个唯一的ID标识
namespace model
{
//用户信息
class UserInfo
{
public:
QString userId = ""; // 用户编号
QString nickname = ""; // 用户昵称
QString description = ""; // 用户签名
QString phone = ""; // 手机号码
QIcon avatar; // 用户头像
};
//消息信息
enum MessageType{
TEXT_TYPE, // 文本消息
IMAGE_TYPE, // 图片消息
FILE_TYPE, // 文件消息
SPEECH_TYPE // 语音消息
};
class Message{
public:
QString messageId = ""; // 消息编号
QString chatSessionId = ""; // 消息所属会话编号
QString time = ""; // 消息时间
MessageType messageType = TEXT_TYPE;// 消息类型
UserInfo sender; // 发送者的信息
QByteArray content; // 消息的正文内容
QString fileId = ""; // 文件的身份标识
QString fileName = ""; // 文件名称
//获取指定类型的消息信息
static Message makeMessage(MessageType messageType,const QString&chatSessionId,const UserInfo&sender,
const QByteArray&content,const QString&extraInfo)
{
if (messageType == TEXT_TYPE) {
return makeTextMessage(chatSessionId, sender, content);
} else if (messageType == IMAGE_TYPE) {
return makeImageMessage(chatSessionId, sender, content);
} else if (messageType == FILE_TYPE) {
return makeFileMessage(chatSessionId, sender, content, extraInfo);
} else if (messageType == SPEECH_TYPE) {
return makeSpeechMessage(chatSessionId, sender, content);
} else {
// 触发了未知的消息类型
return Message();
}
}
};
//会话消息
class ChatSessionInfo{
public:
QString chatSessionId = ""; // 会话编号
QString chatSessionName = ""; // 会话名字
Message lastMessage; // 表示最新的消息.
QIcon avatar; // 会话头像
QString userId = ""; // 对于单聊来说
};
}
获取唯一ID
static QString makeId()
{
return "M" + QUuid::createUuid().toString().sliced(25,12);
}
工具函数设计逻辑
格式化时间工具
- 通过将时间戳转变为格式化时间
- 逻辑:先将时间戳转化为QDateTime对象,然后将该对象转换为具体的时间即可
static inline QString formatTime(uint64_t timestamp)
{
QDateTime dateTime = QDateTime::fromSecsSinceEpoch(timestamp);
return dateTime.toString("MM-dd HH:mm:ss");
}
获取秒级时间
static inline int64_t getTime(){
return QDateTime::currentSecsSinceEpoch();
}
根据QByteArray转换为QIcon
- 通过QPixmap加载QByteArry,然后将其转换为QIcon
static inline QIcon makeIcon(const QByteArray&byteArray)
{
QPixmap pixmap;
pixmap.loadFromData(byteArray);
QIcon icon(pixmap);
return icon;
}
从文件中读取二进制内容,得到QByteArray
static inline QByteArray loadFileToByteArray(const QString&path)
{
QFile file(path);
bool ok = file.open(QFile::ReadOnly);
if(!ok)
{
//打开失败逻辑
return QByteArray();
}
QByteArray constent = file.readAll();
file.close();
return constent;
}
QByteArry内容写入到指定文件中
static inline void writeByteArrayToFile(const QString&path,const QByteArray&content)
{
QFile file(path);
bool ok = file.open(QFile::WriteOnly);
if(!ok)
{
return;
}
file.write(content);
file.flush();//缓冲区刷新
file.close();
}
简单日志
构建一个简单日志打印模块
static inline QString getFileName(const QString& path) {
QFileInfo fileInfo(path);
return fileInfo.fileName();
}
#define TAG QString("[%1:%2]").arg(model::getFileName(__FILE__), QString::number(__LINE__))
#define LOG() qDebug().noquote() << TAG
主界面设计
单例获取主窗口
主窗口设计成单例
主界面总体布局设计
设计主界面的基础布局
左侧导航栏
左侧导航栏设计
通过信号槽实现点击左侧按钮其他图标变色功能,为了方便,将槽函数进行封装,统一在构造函数中执行
中间布局设计
中间布局:搜索框、添加按钮、会话好友区
- 创建一个类,专门负责好友列表的区域,即sessionFriendArea(下文分析)
会话好友区设计,滚动条效果设计
滚动区域中Item的实现
Item背景色不一致问题
问题:QT中如果是给QWidget子类通过QSS设置背景色,默认可能不生效,参考下方官方文档解释
解决方法:添加官方文档对应函数即可
实现逻辑理解
- 实现QSS类似于画笔在QPainter中绘制,相对于QT中自带的类,预先已经在paintEvent中处理好了相关逻辑
- 其中自己创建的类,则需要手动实现上述绘制过程
- 注:绘制只是方便理解,而非真的绘制
功能实现:点击Item的时候变色,同时保证其他Item不变色
功能实现:鼠标悬停在某个聊天的时候就变色
好友会话区:获取指定的Item
继承基类Item实现会话Item
- 会话Item实现
- 逻辑:点击后,在主界面右侧消息展示区加载对饮管道消息列表
- 好友Item实现
- 逻辑:点击后,实现选中对应会话功能
- 好友申请Item实现
- 逻辑:点击后,只有同意和拒绝两个按钮实现触发对应功能
好友申请界面逻辑实现
右侧布局设计
页面布局:右侧主窗口
右侧窗口:消息展示区的实现,使用一个单独类(messageShowArea)
- 设计分析
- 消息类型是多样的,所以采用工厂设计模式,从而实现对不同消息类型的展示
- 实现四种消息的创建,后期也方便对消息类型进行拓展
消息正文设计逻辑
- 设计目标:确保其文字和区域尺寸是匹配的
- 高度:文字高度加上上下边距
- 换行时,高度需要重新计算,文本总宽度/一行摆放宽度 = 行数
- 宽度:文字宽度加上左右边距
- 需要考虑到,当消息长度超过一定长度的时候需要换行,通过设置阈值实现
- 确认长宽后,再绘制消息气泡(难点在于计算其消息最终占有的面积)
右侧窗口:消息编辑区实现,同上(messageEditArea)