pyqt5 仿微信 聊天界面以及聊天界面的气泡怎么实现?

最近在用pyqt5做一个仿微信的GUI 但是在聊天界面中遇到了聊天展示的问题 想用气泡展示且想要如下效果 类似下图pyqt5 仿微信 聊天界面以及聊天界面的气泡怎么实现?

上图是一个使用C++和QT的博主写的 奈何看不懂C++,有没有大佬可以以pyqt5的方式写出来,大概实现逻辑是 使用Qlistwidget 每个气泡是由QListWidgetItem提升成QWidget来实现

C++代码如下
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

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.jpg");

m_rightPixmap = QPixmap(":/img/CustomerService.jpg");

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

}

}

转自出处:https://shazhenyu.blog.csdn.n...

以上是 pyqt5 仿微信 聊天界面以及聊天界面的气泡怎么实现? 的全部内容, 来源链接: utcz.com/p/938347.html

回到顶部