文章目录

  • 1、简介
  • 2、效果图
  • 3、实现原理
  • 4、核心代码
    • 4.1、头文件
    • 4.2、源文件
  • 5、代码分享
    • 5.1、Github
    • 5.2、码云

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

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);}
}

5、代码分享

5.1、Github

地址:https://github.com/ShaShiDiZhuanLan/Demo_MessageChat_Qt

5.2、码云

地址:https://gitee.com/ShaShiDiZhuanLan/Demo_MessageChat


Qt5气泡式聊天框——QListWidget+QPainter实现相关推荐

  1. Qt5气泡式聊天框,QT聊天软件

    一直想做一款聊天软件.最近终于有了时间和机会.源代码已经开放.欢迎关注和贡献代码啊.嘿嘿 https://github.com/qcdong2016/Octopus

  2. qq聊天框java_jQuery实现简单QQ聊天框

    本文实例为大家分享了jQuery实现简单QQ聊天框的具体代码,供大家参考,具体内容如下 先放一张效果图! 1.首先我们把基本框架搭出来,还要准备三张图片用来当作头像,下面是html的内容 关闭(C) ...

  3. 基于socket的线上聊天框

    聊天框1.0 使用说明: 要求Linux环境,虚拟机或者WSL均可 命令行执行 g++ Server.cpp -o Server 和 g++ Client.cpp -o Client 进行编译 线程A ...

  4. 山寨一把QQ移动终端聊天框,网页版效果其实也很好的!

    手机QQ的聊天框很漂亮,包括好多短信交互框也做成类似的风格,各种效果,各种炫,至于不规则形状的那种(称为手绘风格),比较麻烦,这里使用CSS3新特性,border-radius,进行信息框交互内容的设 ...

  5. 纯CSS实现气泡聊天框的方法

    <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...

  6. php类似微信聊天框,仿微信聊天功能

    摘要: 微信聊天 window.onload = () => { // 获取按钮 let btn = document.getElementById('btn'); // 获取输入框 let t ...

  7. Andriod 实现一个微信聊天框(一)

    Andriod 实现一个微信聊天框(一) 这周做了第一次Andriod作业,虽然是对着老师的视频桥的代码,还是遇到了相当多的技术问题和bug,再次记录一下解决问题的过程,以便于后期复习使用. 这次实验 ...

  8. 我的世界服务器无法发送聊天信息,我的世界聊天框指令传送 | 手游网游页游攻略大全...

    发布时间:2017-04-26 我的世界聊天框有什么用?相信大部分玩家在玩游戏的时候聊天框只是一个聊天用的工具,可是你想过这些聊天框也能玩出花样吗?今天游戏园小编就为大家带来了我的世界跳舞的聊天框,来 ...

  9. php做到聊天发图片,网页聊天框发送表情图片实现方法

    话不多说,单刀直入正题. NO 1:标签定义方法 这种方法和平常使用的输入框没什么区别,一个textarea解决问题,原理是输入特定格式的文字符号,显示的时候通过定义的规则解析,显示表情,至于图片则是 ...

最新文章

  1. 晶科能源坐稳全球光伏组件制造商“头把交椅”
  2. Windows Tftpd32 DHCP服务器 使用
  3. Manjaro使用笔记-使用中国源的方法
  4. Visual Studio 2010快捷键大全
  5. AMD Cubemapgen for physically based rendering
  6. MongoDB 学习-MongoDB 的基本操作(二)
  7. android log 码率,webrtc之Android视频质量提升:保帧率降码率
  8. ant里面table嵌套子表格_ElementUI el-table行内编辑验证,动态增减行
  9. 算法真的“难”吗?其实也不见得...
  10. 区块链学习之《区块链技术指南》读书笔记
  11. android wifi信号检测工具,推荐4个专业又实用的WiFi检测工具,了解一下
  12. echarts地图各种点位实现
  13. 关于oracle端口映射的远程连接
  14. mongodb一致性协议_Mongodb选举机制
  15. js:为窗口盒子添加拖拽事件
  16. opencv去除图片水印
  17. 根据经纬度计算指定范围内或者附近的人(java)
  18. 声纹识别概述(1)初识
  19. SQL语句一二三之SQL基本语句
  20. MFC TabControl插件 子对话框调用主对话框功能函数和变量

热门文章

  1. Todesk远程连接时一直显示密码错误
  2. GEE学习:按照行列号筛选鄱阳湖湖区影像数据并查询相关信息
  3. 关于ELF格式文件里面的调试信息解读
  4. RationalDMIS 7.1 建立坐标系(3-2-1法)
  5. 最小二乘法直线拟合、圆拟合
  6. c++ primer--容器的综合应用:文本查询程序
  7. 最全的基于c++的serialport.cpp与serialport.h类文件(解析版)
  8. 学生用什么台灯对眼睛最好呢?一起来看看选哪些护眼灯吧
  9. [植树造林小游戏1.1]
  10. 笔记代码(各种算法实现)