qt 气泡聊天界面_微信聊天气泡框素材

qt 气泡聊天界面_微信聊天气泡框素材目录由于最近的项目需要,做了些相关IM的工作。所以聊天框也是必不可少的一部分。聊天框的制作分很多种,本文以QListWidget+QPainter绘制的Item做了一个Demo。该Demo只是做一个示例,代码已公布如下,需要的拿去!目录效果图实现原理调用样例实现类代码分享效果图实现原理气泡式聊天的显示是由QListWidget作为控件,每个…

大家好,又见面了,我是你们的朋友全栈君。

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); // 整个的size
qDebug() << "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


版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/135037.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • webstorm2021 永久激活码(JetBrains全家桶)

    (webstorm2021 永久激活码)这是一篇idea技术相关文章,由全栈君为大家提供,主要知识点是关于2021JetBrains全家桶永久激活码的内容https://javaforall.cn/100143.htmlIntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,上面是详细链接哦~2JTX0APX6F-eyJsaWNlb…

  • Springboot整合SSM

    Springboot整合SSM1.1创建SSM模块1.1.1系统架构图1.1.2项目结构1.1.3需求访问:http://localhost:8080/car/get返回:{“name”:”BMW”,”color”:”red”,”price”:9.9}1.1.4准备表,数据CREATETABLE`car`(`id`int(11)NOTNULLauto_increment,`name`varchar(10)defaultNULL,`color`varchar(10)d

  • linux下svn配置http访问「建议收藏」

    linux下svn配置http访问「建议收藏」CentOS服务器部署svn+apachehttp+sslhttps访问,本文详细介绍了svn配置apachehttp访问安装及配置过程。

  • Oracle 11g AMM与ASMM切换

    Oracle 11g AMM与ASMM切换现在的Oracle正在往智能化方向发展。如果我们现在找一些8i/9i时代的Oracle书籍,怎么样配置合适的数据库各内存池大小是非常重要的话题。但是进入10g之后,自动内存池调节成为一个重要Oracle特性。在10g时,Oracle推出了ASMM(AutomaticSharedMemoryManagement),实现了OracleSGA和PGA内部结构的自调节。进入11g之后,AMM(A…

  • python做微信回复机器人_Python自动化脚本

    python做微信回复机器人_Python自动化脚本Python几十行代码轻松实现微信自动回复机器人最近因为太无聊了就考虑能不能做一些好玩的东西出来,正好在CSDN的推荐上看到大佬做的微信自动回复机器人,觉得很有趣,因此想着自己也能动手做一个。在此就写下我的具体思路和实现过程吧。首先,我是选择先找一个具有自动回复功能的机器,调用其API,上网搜索了一下,发现大家伙都推荐图灵机器人,然后我就溜过去找了一下图灵机器人,最后发现:它收费!!!可恶啊,难道刚开始就要结束了吗?后来我又开始了百度大法,最后发现了一个免费的机器人API:青云客。测试了一手

  • django 用户注册_支付宝注册用户数量

    django 用户注册_支付宝注册用户数量前言我们使用django创建用户可以使用注册接口的方式,也可以使用django自带的后台管理系统,这里就介绍使用后台管理系统创建用户admin后台管理系统在使用之前我们可以使用第三方的插件,来美

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号