在上章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动图表情包、消息聊天、拖动缩放窗口)的更多相关文章

  1. 28.qt quick-ListView高仿微信好友列表和聊天列表

    1.视图模型介绍  在Qml中.常见的View视图有: ListView: 列表视图,视图中数据来自ListModel.XmlListModel或c++中继承自QAbstractItemModel或Q ...

  2. 31.qt quick-使用SwipeView添加滑动视图-高仿微信V2版本

    在上章我们学习了ListView,然后实现了: 28.qt quick-ListView高仿微信好友列表和聊天列表,本章我们来学习SwipeView滑动视图,并出高仿微信V2版本: 1.Contain ...

  3. iOS天气动画、高仿QQ菜单、放京东APP、高仿微信、推送消息等源码

    iOS精选源码 TYCyclePagerView iOS上的一个无限循环轮播图组件 iOS高仿微信完整项目源码 想要更简单的推送消息,看本文就对了 ScrollView嵌套ScrolloView解决方 ...

  4. 转-Fragment+ViewPager组件(高仿微信界面)

    http://www.cnblogs.com/lichenwei/p/3982302.html 什么是ViewPager? 关于ViewPager的介绍和使用,在之前我写过一篇相关的文章<安卓开 ...

  5. GSD_WeiXin(高仿微信)应用源码

    高仿微信计划:已经实现功能 1.微信首页(cell侧滑编辑.下拉眼睛动画.下拉拍短视频.点击进入聊天详情界面) 2.通讯录(联系人字母排序.搜索界面) 3.发现(朋友圈) 4.我(界面) 待实现功能( ...

  6. Android高仿微信(一)——如何消除启动时的白屏

    默认情况下,APP启动时会先把屏幕刷成白色,然后才绘制第一个Activity中的View,这两个步骤之间的延迟会造成启动后先看到白屏(时间大概为1秒左右).时间不长,但是我们也看到,一般的APP时不存 ...

  7. 安卓开发笔记——Fragment+ViewPager组件(高仿微信界面)

    什么是ViewPager? 关于ViewPager的介绍和使用,在之前我写过一篇相关的文章<安卓开发复习笔记——ViewPager组件(仿微信引导界面)>,不清楚的朋友可以看看,这里就不再 ...

  8. 实例源码--IOS高仿微信打飞机游戏(完整功能)

    下载源码 技术要点: 1. IOS游戏开发基础框架 2. 高仿打飞机游戏 3. 游戏背景音频技术 4.源码详细的中文注释 ……. 详细介绍: 1. IOS游戏开发基础框架 此套源码为涉及IOS游戏开发 ...

  9. Android 高仿微信实时聊天 基于百度云推送

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38799363 ,本文出自:[张鸿洋的博客] 一直在仿微信界面,今天终于有幸利用百 ...

随机推荐

  1. Spring Cloud02:Eureka Server注册中心

    一.Eureka是什么 Eureka是Netflix开源的基于REST的服务治理方案,Spring Cloud集成了Eureka,提供服务治理和服务发现功能,可以和基于Spring Boot搭建的微服 ...

  2. 【Azure 应用服务】Azure Web App的服务(基于Windows 操作系统部署)在被安全漏洞扫描时发现了TCP timestamps漏洞

    问题背景 什么是TCP timestamps(TCP 时间戳)? The remote host implements TCP Timestamps, as defined by RFC1323 (h ...

  3. Java IO学习笔记二:DirectByteBuffer与HeapByteBuffer

    作者:Grey 原文地址:Java IO学习笔记二:DirectByteBuffer与HeapByteBuffer ByteBuffer.allocate()与ByteBuffer.allocateD ...

  4. Etcd中Raft joint consensus的实现

    Joint consensus 分为2个阶段,first switches to a transitional configuration we call joint consensus; once ...

  5. UI自动化在RobotFramework中采用的分层设计

    RF测试数据 RF测试数据由4种表数据组成.这些测试数据由表的第一个单元格标识,名称和用法如下: 表名 用法 别名 设置表 导入测试库,资源文件和变量文件.为测试套件和测试用例定义元数据 Settin ...

  6. ld-linux-x86-64消耗大量的CPU

    1.现象: 服务器CPU使用率很高 top查看cpu使用进程: 2.进程用户是oracle,根据spid查看是否是数据库进程,经过查询发现:不是数据库内部的进程 select a.sql_id,a.s ...

  7. perror()函数的使用

    perror()函数的功能是打印一个系统错误信息.        perror()函数在Linux系统中属于库函数,在头文件中有如下定义: #include <stdio.h>       ...

  8. 撸了几天的sofa-tracer之后,我悟了!

    什么是分布式链路跟踪 简而言之,在分布式系统下,用于跟踪链路而衍生出的一项技术. 应用场景如下: 应用A,B,C,D,E 以一个层级关系依赖, 当用户向 应用A 发起请求,但是返回了个异常,为了排查这 ...

  9. 案例 | 腾讯广告 AMS 的容器化之路

    作者 张煜,15年加入腾讯并从事腾讯广告维护工作.20年开始引导腾讯广告技术团队接入公司的TKEx-teg,从业务的日常痛点并结合腾讯云原生特性来完善腾讯广告自有的容器化解决方案 项目背景 腾讯广告承 ...

  10. 解决两个相邻的span,或者input和button中间有间隙,在css中还看不到

    <span id="time"></span><span id="second"></span> <inp ...