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