1、简介

由于最近的项目需要,做了些相关IM的工作。所以聊天框也是必不可少的一部分。聊天框的制作分很多种,本文以QListWidget+QPainter绘制的Item做了一个Demo。该Demo只是做一个示例,代码已公布如下,需要的拿去!

2、效果图

3、实现原理

气泡式聊天的显示是由QListWidget作为控件,每个气泡是由QListWidgetItem提升成QWidget来实现的。每个气泡可以理解位是一个QWidget,这样可以自由布置QWidget里面的内容。每个Item保存聊天的对话、发送状态、时间、种类等。

这个QWidget主要是显示一个头像+气泡,气泡里面是聊天的内容等。 气泡是在paintEvent事件中,采用QPainter来绘制的。

4、核心代码

4.1、头文件

#ifndef QNCHATMESSAGE_H
#define QNCHATMESSAGE_H#include <QWidget>class QPaintEvent;
class QPainter;
class QLabel;
class QMovie;class QNChatMessage : public QWidget
{ Q_OBJECT
public:explicit QNChatMessage(QWidget *parent = nullptr);enum User_Type{ User_System,//系统User_Me,    //自己User_She,   //用户User_Time,  //时间};void setTextSuccess();void setText(QString text, QString time, QSize allSize, User_Type userType);QSize getRealString(QString src);QSize fontRect(QString str);inline QString text() { return m_msg;}inline QString time() { return m_time;}inline User_Type userType() { return m_userType;}
protected:void paintEvent(QPaintEvent *event);
private:QString m_msg;QString m_time;QString m_curTime;QSize m_allSize;User_Type m_userType = User_System;int m_kuangWidth;int m_textWidth;int m_spaceWid;int m_lineHeight;QRect m_iconLeftRect;QRect m_iconRightRect;QRect m_sanjiaoLeftRect;QRect m_sanjiaoRightRect;QRect m_kuangLeftRect;QRect m_kuangRightRect;QRect m_textLeftRect;QRect m_textRightRect;QPixmap m_leftPixmap;QPixmap m_rightPixmap;QLabel* m_loading = Q_NULLPTR;QMovie* m_loadingMovie = Q_NULLPTR;bool m_isSending = false;
};#endif // QNCHATMESSAGE_H

本文福利,费领取Qt开发学习资料包、技术视频,内容包括(C++语言基础,Qt编程入门,QT信号与槽机制,QT界面开发-图像绘制,QT网络,QT数据库编程,QT项目实战,QT嵌入式开发,Quick模块,面试题等等)↓↓↓↓↓↓见下面↓↓文章底部点击莬费领取↓↓

4.2、源文件

#include "qnchatmessage.h"
#include <QFontMetrics>
#include <QPaintEvent>
#include <QDateTime>
#include <QPainter>
#include <QMovie>
#include <QLabel>
#include <QDebug>QNChatMessage::QNChatMessage(QWidget *parent) : QWidget(parent)
{ QFont te_font = this->font();te_font.setFamily("MicrosoftYaHei");te_font.setPointSize(12);
// te_font.setWordSpacing(0);
// te_font.setLetterSpacing(QFont::PercentageSpacing,0);
// te_font.setLetterSpacing(QFont::PercentageSpacing, 100); //300%,100为默认 //设置字间距%
// te_font.setLetterSpacing(QFont::AbsoluteSpacing, 0); //设置字间距为3像素 //设置字间距像素值this->setFont(te_font);m_leftPixmap = QPixmap(":/img/Customer Copy.png");m_rightPixmap = QPixmap(":/img/CustomerService.png");m_loadingMovie = new QMovie(this);m_loadingMovie->setFileName(":/img/loading4.gif");m_loading = new QLabel(this);m_loading->setMovie(m_loadingMovie);m_loading->resize(16,16);m_loading->setAttribute(Qt::WA_TranslucentBackground , true);m_loading->setAutoFillBackground(false);
}void QNChatMessage::setTextSuccess()
{ m_loading->hide();m_loadingMovie->stop();m_isSending = true;
}void QNChatMessage::setText(QString text, QString time, QSize allSize, QNChatMessage::User_Type userType)
{ m_msg = text;m_userType = userType;m_time = time;m_curTime = QDateTime::fromTime_t(time.toInt()).toString("hh:mm");m_allSize = allSize;if(userType == User_Me) { if(!m_isSending) { m_loading->move(m_kuangRightRect.x() - m_loading->width() - 10, m_kuangRightRect.y()+m_kuangRightRect.height()/2- m_loading->height()/2);m_loading->show();m_loadingMovie->start();}} else { m_loading->hide();}this->update();
}QSize QNChatMessage::fontRect(QString str)
{ m_msg = str;int minHei = 30;int iconWH = 40;int iconSpaceW = 20;int iconRectW = 5;int iconTMPH = 10;int sanJiaoW = 6;int kuangTMP = 20;int textSpaceRect = 12;m_kuangWidth = this->width() - kuangTMP - 2*(iconWH+iconSpaceW+iconRectW);m_textWidth = m_kuangWidth - 2*textSpaceRect;m_spaceWid = this->width() - m_textWidth;m_iconLeftRect = QRect(iconSpaceW, iconTMPH, iconWH, iconWH);m_iconRightRect = QRect(this->width() - iconSpaceW - iconWH, iconTMPH, iconWH, iconWH);QSize size = getRealString(m_msg); // 整个的sizeqDebug() << "fontRect Size:" << size;int hei = size.height() < minHei ? minHei : size.height();m_sanjiaoLeftRect = QRect(iconWH+iconSpaceW+iconRectW, m_lineHeight/2, sanJiaoW, hei - m_lineHeight);m_sanjiaoRightRect = QRect(this->width() - iconRectW - iconWH - iconSpaceW - sanJiaoW, m_lineHeight/2, sanJiaoW, hei - m_lineHeight);if(size.width() < (m_textWidth+m_spaceWid)) { m_kuangLeftRect.setRect(m_sanjiaoLeftRect.x()+m_sanjiaoLeftRect.width(), m_lineHeight/4*3, size.width()-m_spaceWid+2*textSpaceRect, hei-m_lineHeight);m_kuangRightRect.setRect(this->width() - size.width() + m_spaceWid - 2*textSpaceRect - iconWH - iconSpaceW - iconRectW - sanJiaoW,m_lineHeight/4*3, size.width()-m_spaceWid+2*textSpaceRect, hei-m_lineHeight);} else { m_kuangLeftRect.setRect(m_sanjiaoLeftRect.x()+m_sanjiaoLeftRect.width(), m_lineHeight/4*3, m_kuangWidth, hei-m_lineHeight);m_kuangRightRect.setRect(iconWH + kuangTMP + iconSpaceW + iconRectW - sanJiaoW, m_lineHeight/4*3, m_kuangWidth, hei-m_lineHeight);}m_textLeftRect.setRect(m_kuangLeftRect.x()+textSpaceRect,m_kuangLeftRect.y()+iconTMPH,m_kuangLeftRect.width()-2*textSpaceRect,m_kuangLeftRect.height()-2*iconTMPH);m_textRightRect.setRect(m_kuangRightRect.x()+textSpaceRect,m_kuangRightRect.y()+iconTMPH,m_kuangRightRect.width()-2*textSpaceRect,m_kuangRightRect.height()-2*iconTMPH);return QSize(size.width(), hei);
}QSize QNChatMessage::getRealString(QString src)
{ QFontMetricsF fm(this->font());m_lineHeight = fm.lineSpacing();int nCount = src.count("\n");int nMaxWidth = 0;if(nCount == 0) { nMaxWidth = fm.width(src);QString value = src;if(nMaxWidth > m_textWidth) { nMaxWidth = m_textWidth;int size = m_textWidth / fm.width(" ");int num = fm.width(value) / m_textWidth;int ttmp = num*fm.width(" ");num = ( fm.width(value) ) / m_textWidth;nCount += num;QString temp = "";for(int i = 0; i < num; i++) { temp += value.mid(i*size, (i+1)*size) + "\n";}src.replace(value, temp);}} else { for(int i = 0; i < (nCount + 1); i++) { QString value = src.split("\n").at(i);nMaxWidth = fm.width(value) > nMaxWidth ? fm.width(value) : nMaxWidth;if(fm.width(value) > m_textWidth) { nMaxWidth = m_textWidth;int size = m_textWidth / fm.width(" ");int num = fm.width(value) / m_textWidth;num = ((i+num)*fm.width(" ") + fm.width(value)) / m_textWidth;nCount += num;QString temp = "";for(int i = 0; i < num; i++) { temp += value.mid(i*size, (i+1)*size) + "\n";}src.replace(value, temp);}}}return QSize(nMaxWidth+m_spaceWid, (nCount + 1) * m_lineHeight+2*m_lineHeight);
}void QNChatMessage::paintEvent(QPaintEvent *event)
{ Q_UNUSED(event);QPainter painter(this);painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);//消锯齿painter.setPen(Qt::NoPen);painter.setBrush(QBrush(Qt::gray));if(m_userType == User_Type::User_She) { // 用户//头像
// painter.drawRoundedRect(m_iconLeftRect,m_iconLeftRect.width(),m_iconLeftRect.height());painter.drawPixmap(m_iconLeftRect, m_leftPixmap);//框加边QColor col_KuangB(234, 234, 234);painter.setBrush(QBrush(col_KuangB));painter.drawRoundedRect(m_kuangLeftRect.x()-1,m_kuangLeftRect.y()-1,m_kuangLeftRect.width()+2,m_kuangLeftRect.height()+2,4,4);//框QColor col_Kuang(255,255,255);painter.setBrush(QBrush(col_Kuang));painter.drawRoundedRect(m_kuangLeftRect,4,4);//三角QPointF points[3] = { QPointF(m_sanjiaoLeftRect.x(), 30),QPointF(m_sanjiaoLeftRect.x()+m_sanjiaoLeftRect.width(), 25),QPointF(m_sanjiaoLeftRect.x()+m_sanjiaoLeftRect.width(), 35),};QPen pen;pen.setColor(col_Kuang);painter.setPen(pen);painter.drawPolygon(points, 3);//三角加边QPen penSanJiaoBian;penSanJiaoBian.setColor(col_KuangB);painter.setPen(penSanJiaoBian);painter.drawLine(QPointF(m_sanjiaoLeftRect.x() - 1, 30), QPointF(m_sanjiaoLeftRect.x()+m_sanjiaoLeftRect.width(), 24));painter.drawLine(QPointF(m_sanjiaoLeftRect.x() - 1, 30), QPointF(m_sanjiaoLeftRect.x()+m_sanjiaoLeftRect.width(), 36));//内容QPen penText;penText.setColor(QColor(51,51,51));painter.setPen(penText);QTextOption option(Qt::AlignLeft | Qt::AlignVCenter);option.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);painter.setFont(this->font());painter.drawText(m_textLeftRect, m_msg,option);}  else if(m_userType == User_Type::User_Me) { // 自己//头像
// painter.drawRoundedRect(m_iconRightRect,m_iconRightRect.width(),m_iconRightRect.height());painter.drawPixmap(m_iconRightRect, m_rightPixmap);//框QColor col_Kuang(75,164,242);painter.setBrush(QBrush(col_Kuang));painter.drawRoundedRect(m_kuangRightRect,4,4);//三角QPointF points[3] = { QPointF(m_sanjiaoRightRect.x()+m_sanjiaoRightRect.width(), 30),QPointF(m_sanjiaoRightRect.x(), 25),QPointF(m_sanjiaoRightRect.x(), 35),};QPen pen;pen.setColor(col_Kuang);painter.setPen(pen);painter.drawPolygon(points, 3);//内容QPen penText;penText.setColor(Qt::white);painter.setPen(penText);QTextOption option(Qt::AlignLeft | Qt::AlignVCenter);option.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);painter.setFont(this->font());painter.drawText(m_textRightRect,m_msg,option);}  else if(m_userType == User_Type::User_Time) { // 时间QPen penText;penText.setColor(QColor(153,153,153));painter.setPen(penText);QTextOption option(Qt::AlignCenter);option.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);QFont te_font = this->font();te_font.setFamily("MicrosoftYaHei");te_font.setPointSize(10);painter.setFont(te_font);painter.drawText(this->rect(),m_curTime,option);}
}

本文福利,费领取Qt开发学习资料包、技术视频,内容包括(C++语言基础,Qt编程入门,QT信号与槽机制,QT界面开发-图像绘制,QT网络,QT数据库编程,QT项目实战,QT嵌入式开发,Quick模块,面试题等等)↓↓↓↓↓↓见下面↓↓文章底部点击莬费领取↓↓

qt 气泡聊天界面_微信聊天气泡框素材相关推荐

  1. 微信气泡主题设置_微信猫和老鼠主题怎么弄?猫和老鼠聊天气泡主题设置教程...

    阅读本文前,请您先点击上面的"科技阿",再点击"关注",这样您就可以继续免费收到文章了.每天都会有分享,都是免费订阅,请您放心关注.  注:本文转载自网络,如有 ...

  2. 微信气泡主题设置_微信皮肤主题怎么弄 微信设置更换修改气泡和主题教程

    对于微信的皮肤主题是可以根据每个人不同的爱好进行设置的,最近呢就上架了一款超级受欢迎的猫和老鼠气泡主题,如果您想要进行更换修改要怎么弄呢,下面小编会带来详细的微信设置更换修改气泡和主题教程. 微信设置 ...

  3. 微信气泡主题设置_微信气泡主题华为手机要怎么弄 华为手机微信气泡主题设置方法介绍...

    4.下载完成后,打开MT管理器,在左侧找到我们下载的气泡主题所在文件夹,点击进入显示[.mm]文件,然后在右侧找到华为手机主题的文件夹[HUAWEI-Themes],然后随便选择一个主题进入(注意不能 ...

  4. 微信气泡主题设置_微信猫和老鼠主题皮肤怎么设置 华为手机设置气泡主题方法...

    微信猫和老鼠气泡主题应该如何设置?趣味主题带来的乐趣超级多,想要了解主题设置的方法,下面会提供详细的操作流程,让大家都能了解猫和老鼠气泡主题的设置技巧,轻松拥有好看又好玩的主题. 华为手机设置微信猫和 ...

  5. #解决仿微信聊天界面键盘遮盖聊天的界面

    解决仿微信聊天界面键盘遮盖聊天的界面 注意聊天界面的activity一定不能处于全屏模式 //第一步设置属性 <!--模拟的布局文件--><?xml version="1. ...

  6. h5聊天页面 jquery_HTML5仿微信聊天界面、微信朋友圈实例代码

    这几天使用H5开发了一个仿微信聊天前端界面,尤其微信底部编辑器那块处理的很好,使用HTML5来开发,虽说功能效果并没有微信那么全,但是也相当不错了,可以发送消息.表情,发送的消息自动回滚定位到底部,另 ...

  7. IM即时通信多房间聊天室仿微信聊天(二)

    IM即时通信多房间聊天室仿微信聊天(服务器自定义处理客户端消息) 在IM即时通信多房间聊天室仿微信聊天(一)中我们已经搭建了基本的通信架构,接下来重点就是如何在自己的后台接收并处理客户端用户的消息了 ...

  8. IM即时通信多房间聊天室仿微信聊天(四)

    聊天记录的保存和展示 IM即时通信多房间聊天室仿微信聊天(一) IM即时通信多房间聊天室仿微信聊天(二) IM即时通信多房间聊天室仿微信聊天(三) 聊天消息的保存我们直接在服务端接收到客户端发送的消息 ...

  9. 微信视频气泡 android,变变微信聊天气泡

    变变微信聊天气泡是一款非常好用的气泡美化软件,让你的聊天框看起来更加个性化,不需要ROOT即可完成气泡设计,更具趣味性,喜欢的小伙们快来下载试试吧! 软件详情 让气泡在你的指尖跳跃吧! 变变聊天气泡( ...

最新文章

  1. IDEA 连接MySQL数据库
  2. Spring MVC配置
  3. sqlalchemy Specified key was too long; max key length is 767 bytes的解决办法
  4. NOIP2018初赛提高组复习提纲(By HGOI LJC)
  5. RAID原理及其使用方法
  6. nginx中js修改不生效的问题
  7. 解决prometheus k8s.gcr.io/addon-resizer:1.8.4镜像无法下载的问题
  8. ITK:将蒙版的反面应用于图像
  9. C运算符解析及优先级
  10. socket api中send()和recv()函数工作原理与要点
  11. ThreadLocal原理、ThreadLocal内存泄漏
  12. 思科CCNP培训日记全接触
  13. kali教程--破解wifi密码
  14. 升级到IE11,IE11调试F12 空白没法调试
  15. dpt rp1 android apk,DPT-RP1 新固件
  16. mybatis insert返回自增主键的id值
  17. Java 初中级程序员如何快速成长?
  18. 专访Barefoot:被Intel收购后的五倍爆发力
  19. 【人脸识别6】用haar+adaboost训练自己的人脸检测器
  20. 2017年中国程序员调查分析:大数据就业前景广阔

热门文章

  1. 计算机BIOS设置和CMOS设置的区别与联系
  2. ubuntu的视频录制功能
  3. 洛达1536u怎么升级固件_洛达1536u-001她来了她来了!!!
  4. 洛谷 P1714 切蛋糕
  5. 用分立元件实现串口通讯TTL/RS232电平转换
  6. maven项目中导入mysql中的jdbc驱动时,有以下错误出现,说明你需要更换驱动包版本
  7. ${pageContext.request.contextPath}不生效的问题
  8. 【年度总结】第一年工作总结
  9. 详解应用图标、启动图片和iPhone屏幕分辨率
  10. 从DIY想到的面向对象的思想