40.qt quick- 高仿微信实现局域网聊天V4版本(支持gif动图表情包、消息聊天、拖动缩放窗口)
在上章37.qt quick- 高仿微信实现局域网聊天V3版本(添加登录界面、UDP校验登录、皮肤更换、3D旋转),我们已经实现了:
- 添加登录界面、
- UDP校验登录、
- 皮肤更换、
- 3D旋转(主界面和登录界面之间切换) 、
所以本章实现:
- 2、支持拖动和更改窗口大小、
- 3、可以单独聊天、也可以在聊天室所有人聊天、
- 4、支持收发gif表情包(支持粘贴复制)、
- 5、自动刷新当前好友在线人数等、
1.界面展示
界面布局如下所示:

界面截图如下所示:

效果图如下所示:

有点大,可能加载不了,不过已经上传到bilibili了https://www.bilibili.com/video/BV1Ao4y1S7zX
由于代码量有点多,所以讲解重点的部分
2.Text中的gif管理
2.1 在Text中加入一个gif
// 添加一个gif
void GifTextHandler::inset(QString fileName)
{
if (!m_documnt)
return; QTextCursor cursor = QTextCursor(m_documnt->textDocument());
cursor.setPosition(m_cursorStart);
if (m_cursorStart > m_cursorEnd) {
cursor.setPosition(0);
} else if (m_cursorStart != m_cursorEnd)
cursor.setPosition(m_cursorEnd, QTextCursor::KeepAnchor); addMovie(fileName); // 通过QMovie加载一个gif
QTextImageFormat imageFormat;
imageFormat.setName(fileName);
imageFormat.setWidth(m_width);
imageFormat.setHeight(m_height);
cursor.insertImage(imageFormat, QTextFrameFormat::InFlow); }
添加一个gif后,又如何去管理这个gif,假如我当前文本把这个gif删除了,那么这个QMovie也应该释放才行,否则就内存溢出啦.
2.2 gif动态释放与管理
所以每隔1秒就去读取下文本,gif是否还存在,如果不存在则释放QMovie:
QList<QString> list = m_movies.keys();
for(int i=0;i<list.length();i++) {
m_movies[list[i]]->setProperty("status",false);
} QTextBlock block = m_documnt->textDocument()->firstBlock();
QVector<QTextFormat> allFormats = m_documnt->textDocument()->allFormats();
while(block.isValid()) {
QTextBlockFormat blockFmt = block.blockFormat();
for(QTextBlock::iterator it = block.begin(); !it.atEnd(); it++) {
QTextCharFormat charFmt = it.fragment().charFormat(); // fragment是存放文字,位置的类
if (charFmt.objectType() == QTextFormat::ImageObject) {
QString file = charFmt.property(QTextFormat::ImageName).toString();
if (!m_movies.contains(file)) {
addMovie(file);
}
m_movies[file]->setProperty("status",true);
// qDebug()<<"status: "<<file;
}
}
block = block.next();
} for(int i=0;i<list.length();i++) {
if (m_movies[list[i]]->property("status") == false) {
qDebug()<<"释放gif:"<<i<<list[i];
delete m_movies[list[i]];
m_movies.remove(list[i]);
continue;
}
}
如果文本释放了,那么就遍历整个gif表,释放所有:
GifTextHandler::~GifTextHandler() // 释放资源
{
QList<QString> list = m_movies.keys();
for(int i=0;i<list.length();i++) { // 释放所有GIF
delete m_movies[list[i]];
}
m_movies.clear();
}
2.3 文本发送
由于文本中包含了gif图,所以发送的时候,我们需要将文本内容(包含gif)进行编码,转换成字符串,代码如下所示:
QString GifTextHandler::coding()
{
QString ret("");
QTextBlock block = m_documnt->textDocument()->firstBlock();
QVector<QTextFormat> allFormats = m_documnt->textDocument()->allFormats(); while(block.isValid()) {
for(QTextBlock::iterator it = block.begin(); !it.atEnd(); it++) {
QTextCharFormat charFmt = it.fragment().charFormat(); // fragment是存放文字,位置的类
if (charFmt.objectType() == QTextFormat::ImageObject) {
ret.append("["+charFmt.property(QTextFormat::ImageName).toString().remove(GIF_PREFIXDIR)+"]");
} else {
ret.append(it.fragment().text());
}
}
if (block.next().isValid()) // QTextBlock以换行为分割成每个块,所以每次块遍历完后需要加换行符
ret.append("\r\n"); block = block.next();
}
return ret;
}
2.4 文本接收
由于接收到的数据是一段字符串,所以我们需要解码,将gif标志显示成一个gif动图,代码如下所示:
void GifTextHandler::encoding(QString text)
{
if (!m_documnt) {
qDebug()<<"encoding: m_documnt == nullptr";
return;
}
QTextCursor cursor = QTextCursor(m_documnt->textDocument());
cursor.setPosition(0);
QRegularExpression re("\\[\\d+\\.gif\\]");
QRegularExpressionMatch match;
int offset = 0;
int fileNum;
QString file;
QString ret;
while (offset < text.length()) {
match = re.match(text,offset);
if (match.hasMatch()) {
sscanf(match.captured(0).toLocal8Bit(),"[%d.gif]", &fileNum);
file = QString(GIF_PREFIXDIR+"%1.gif").arg(fileNum);
cursor.insertText(text.mid(offset, match.capturedStart(0) - offset)); // 添加前面的
ret.append(text.mid(offset, match.capturedStart(0) - offset));
addMovie(file);
QTextImageFormat imageFormat;
imageFormat.setName(file);
imageFormat.setWidth(m_width);
imageFormat.setHeight(m_height);
cursor.insertImage(imageFormat, QTextFrameFormat::InFlow);
offset = match.capturedEnd(0);
} else {
ret.append(text.mid(offset, text.length() - offset));
cursor.insertText(text.mid(offset, text.length() - offset)); // 添加前面的
break;
}
}
}
3.C++ QAbstractListModel类
qml中使用的是ListView,而model数据是使用C++ model(继承于QAbstractListModel).
所以当有好友上线时,我们需要往model中添加一行好友数据,并通知ListView刷新局部数据,代码如下所示:
void FriendModel::addFriend(MessageDesc* msg)
{
for (int i=1; i < m_data.count(); i++) {
if (m_data[i]->title() == msg->srcUser) {
return;
}
}
// 将头像 Arr数据转换成jpg文件
QPixmap pixmap;
QString str = AppCfg::getInstance()->read(AppCfg::FriendHeadDir).remove("file:///")+msg->srcUser+".jpg";
qDebug()<<msg->headArr.length()<<pixmap.loadFromData((uchar *)msg->headArr.data(), msg->headArr.length());
bool ret = pixmap.save(str);
AppCfg::getInstance()->fileLogWrite(QString("addFriend str%1 str%2 ret%3").arg(str).arg(QUrl::fromLocalFile(str).toString()).
arg(ret)); beginInsertRows(QModelIndex(), 1, 1); // 由于聊天室始终顶置,所以只能插入到第2行
m_data.insert(1, new FriendChatData(msg->srcUser, QUrl::fromLocalFile(str).toString()));
endInsertRows();
hintInsetChatRoom("\""+msg->srcUser+"\" 于"+QDateTime::currentDateTime().toString(" hh:mm ")+"上线!");
}
当好友下线时,则需要删除好友数据,代码如下所示:
void FriendModel::removeFriend(MessageDesc* msg)
{
for (int i=1; i < m_data.count(); i++) {
if (m_data[i]->title() == msg->srcUser) {
beginRemoveRows(QModelIndex(), i, i); // 假如聊天界面的model等于当前下线的好友,那么需要释放聊天model数据,并刷新视图
if (m_chat != NULL && m_chat->data() == m_data[i]) {
delete m_chat;
m_chat = NULL;
emit removeFriendcloseChat();
}
delete m_data[i];
m_data.removeAt(i);
endRemoveRows();
hintInsetChatRoom("\""+msg->srcUser+"\" 于"+QDateTime::currentDateTime().toString(" hh:mm ")+"下线!");
break;
}
}
}
其它的好友收发消息,则依葫芦画瓢,通通实现一遍即可.
40.qt quick- 高仿微信实现局域网聊天V4版本(支持gif动图表情包、消息聊天、拖动缩放窗口)的更多相关文章
- 28.qt quick-ListView高仿微信好友列表和聊天列表
1.视图模型介绍 在Qml中.常见的View视图有: ListView: 列表视图,视图中数据来自ListModel.XmlListModel或c++中继承自QAbstractItemModel或Q ...
- 31.qt quick-使用SwipeView添加滑动视图-高仿微信V2版本
在上章我们学习了ListView,然后实现了: 28.qt quick-ListView高仿微信好友列表和聊天列表,本章我们来学习SwipeView滑动视图,并出高仿微信V2版本: 1.Contain ...
- iOS天气动画、高仿QQ菜单、放京东APP、高仿微信、推送消息等源码
iOS精选源码 TYCyclePagerView iOS上的一个无限循环轮播图组件 iOS高仿微信完整项目源码 想要更简单的推送消息,看本文就对了 ScrollView嵌套ScrolloView解决方 ...
- 转-Fragment+ViewPager组件(高仿微信界面)
http://www.cnblogs.com/lichenwei/p/3982302.html 什么是ViewPager? 关于ViewPager的介绍和使用,在之前我写过一篇相关的文章<安卓开 ...
- GSD_WeiXin(高仿微信)应用源码
高仿微信计划:已经实现功能 1.微信首页(cell侧滑编辑.下拉眼睛动画.下拉拍短视频.点击进入聊天详情界面) 2.通讯录(联系人字母排序.搜索界面) 3.发现(朋友圈) 4.我(界面) 待实现功能( ...
- Android高仿微信(一)——如何消除启动时的白屏
默认情况下,APP启动时会先把屏幕刷成白色,然后才绘制第一个Activity中的View,这两个步骤之间的延迟会造成启动后先看到白屏(时间大概为1秒左右).时间不长,但是我们也看到,一般的APP时不存 ...
- 安卓开发笔记——Fragment+ViewPager组件(高仿微信界面)
什么是ViewPager? 关于ViewPager的介绍和使用,在之前我写过一篇相关的文章<安卓开发复习笔记——ViewPager组件(仿微信引导界面)>,不清楚的朋友可以看看,这里就不再 ...
- 实例源码--IOS高仿微信打飞机游戏(完整功能)
下载源码 技术要点: 1. IOS游戏开发基础框架 2. 高仿打飞机游戏 3. 游戏背景音频技术 4.源码详细的中文注释 ……. 详细介绍: 1. IOS游戏开发基础框架 此套源码为涉及IOS游戏开发 ...
- Android 高仿微信实时聊天 基于百度云推送
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38799363 ,本文出自:[张鸿洋的博客] 一直在仿微信界面,今天终于有幸利用百 ...
随机推荐
- jmeter链接mysql数据库
一.下载与MySQL对应的jar包 1.1.查询MySQL的版本, 命令语句 :SELECT VERSION(); 1.2.MySQL官网下载jar包 ,https://downloads.mysql ...
- Django(59)验证和授权
验证和授权概述 Django有一个内置的授权系统.他用来处理用户.分组.权限以及基于cookie的会话系统.Django的授权系统包括验证和授权两个部分.验证是验证这个用户是否是他声称的人(比如用 ...
- JSP三大指令是什么?
JSP页面中的指令JSP指令用来设置整个JSP页面相关的属性,如网页的编码方式和脚本语言等.语法规则:<%@ 指令名 属性=值 属性=值 ... %>指令可以有很多个属性,它们以键值对的形 ...
- 微信小程序 -- 基于 movable-view 实现拖拽排序
微信小程序 -- 基于 movable-view 实现拖拽排序 项目基于colorui样式组件 ColorUI组件库 (color-ui.com) 1.实现效果 2. 设计思路 movable-vie ...
- python django框架+vue.js前后端分离
本文用于学习django+vue.js实现web前后端分离协作开发.以一个添加和删除数据库书籍应用为实例. django框架官方地址:https://www.djangoproject.com/ vu ...
- Java 设置Word文本框中的文字旋转方向
Word文档中可添加文本框,并设置文本框为横向文本排列或是纵向文本排列,或者设置文本框中的文字旋转方向等.通过Java程序代码,也可以实现以上文本框的操作.下面以Java代码示例展示具体的实现步骤.另 ...
- 01-Tkinter教程-窗口的管理与设置
Tkinter介绍 官方用的GUI工具包--Tkinter(IDLE就是用这个开发的). Tkinter是Python的标准GUI库,它实际是建立在Tk技术上的.在大多数Unix平台以及Windows ...
- Unity的AnimationCurve
转自:风宇冲Unity3D教程学院http://blog.sina.com.cn/s/blog_471132920101f8nv.html,本文有多处增删减改,详细内容请查看原文. 1.介绍 Anim ...
- 24、dhcp服务搭建
1.dhcp介绍: DHCP(Dynamic Host Configuration Protocol),动态主机配置协议,DHCP 协议主要是用来自动为局域网中的客户机分配 TCP/IP 信息的网络协 ...
- __sync_fetch_and_add函数(Redis源码学习)
__sync_fetch_and_add函数(Redis源码学习) 在学习redis-3.0源码中的sds文件时,看到里面有如下的C代码,之前从未接触过,所以为了全面学习redis源码,追根溯源,学习 ...