iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >怎么使用QGraphicsView实现气泡聊天窗口+排雷功能
  • 182
分享到

怎么使用QGraphicsView实现气泡聊天窗口+排雷功能

2023-06-30 10:06:23 182人浏览 独家记忆
摘要

这篇“怎么使用QGraphicsView实现气泡聊天窗口+排雷功能”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“怎么使用QG

这篇“怎么使用QGraphicsView实现气泡聊天窗口+排雷功能”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“怎么使用QGraphicsView实现气泡聊天窗口+排雷功能”文章吧。

最终效果:

怎么使用QGraphicsView实现气泡聊天窗口+排雷功能

存在问题:无法选择文字及跨选(但理论上可以通过重写鼠标相关事件,达到模拟选择的效果)

左侧和右侧的消息分别是封装的两个Item,而这两个Item又从同一个基类继承而来。
气泡通过重写void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);函数,在里面根据文字的宽高计算气泡的位置并画上去,然后再把字写上去。
并且当窗口大小发生变化时,需要重新计算文字尺寸,进行绘制。

#pragma once#include <QGraphicsRectItem>//聊天元素所有item的基类class ChatBaseItem : public QGraphicsRectItem{public:    ChatBaseItem();    virtual ~ChatBaseItem();    virtual int Resize(int width);      //传入值为viewport宽,返回值为item高};
#include "chatbaseitem.h"ChatBaseItem::ChatBaseItem()    : QGraphicsRectItem(){}ChatBaseItem::~ChatBaseItem()int ChatBaseItem::Resize(int width)    return 0;

左侧聊天气泡Item

#pragma once#include "chatbaseitem.h"#include <QDateTime>class OtherMsgitem : public ChatBaseItem{public:    OtherMsgItem(QPixmap icon, QString name, QString msg, QDateTime datetime = QDateTime());    virtual ~OtherMsgItem();    virtual int Resize(int width);  //返回整个item的高度protected:    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);    virtual QRectF boundingRect() const;private:    QGraphicsPixmapitem icon_item_;    QGraphiCSSimpleTextItem name_item_;    QString text_;    QSize text_size_;     //文字尺寸    QDateTime datetime_;};
#include <QPainter>#include <QMargins>#include <QtextOption>#include "othermsgitem.h"const int kMsgFontSize = 14;const int kNameFontSize = 13;const QPoint kNamePos = QPoint(64, 0);const QPoint kIconPos = QPoint(20, 8);const QPoint kBorderPos = QPoint(kNamePos.x(), kNamePos.y()+18);const QMargins kMargins = QMargins(12,11,12,11);        //文字距边框的距离const QPoint kTextPos = QPoint(kBorderPos.x()+ kMargins.left(), kBorderPos.y() + kMargins.top());const int kMarginRight = 40;                           //边框距窗口右侧的距离OtherMsgItem::OtherMsgItem(QPixmap icon, QString name, QString msg, QDateTime datetime )    : ChatBaseItem()    , datetime_(datetime){    icon_item_.setPixmap(icon);    icon_item_.setPos(kIconPos);    text_ = msg;    QFont font("Microsoft YaHei");    font.setPixelSize(kNameFontSize);        name_item_.setText(name);    name_item_.setPos(kNamePos);    name_item_.setFont(font);    name_item_.setBrush(QColor(153, 153, 153));    icon_item_.setParentItem(this);    name_item_.setParentItem(this);}OtherMsgItem::~OtherMsgItem()int OtherMsgItem::Resize(int width)    //每行最大可容纳文字的宽度    int row_width = width - kTextPos.x() - kMarginRight-kMargins.right();    //计算文字总共需要多宽    font.setPixelSize(kMsgFontSize);    QFontMetrics font_matrics(font);    int text_total_width = font_matrics.width(text_);    int text_row_height = font_matrics.lineSpacing();    if(row_width<text_total_width)    {        int row = text_total_width / row_width;        ++row;        int text_total_height = row* text_row_height;        text_size_.setWidth(row_width);        text_size_.setHeight(text_total_height);    }    else        text_size_.setWidth(text_total_width);        text_size_.setHeight(text_row_height);    return text_size_.height()+kMargins.top()+kMargins.bottom()+kBorderPos.y();void OtherMsgItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)    QSize rnd(17,17);    QRectF border(kBorderPos.x(), kBorderPos.y(), text_size_.width()+kMargins.left()+ kMargins.right(),text_size_.height() + kMargins.top() + kMargins.bottom());    //气泡加边    painter->setPen(QPen(QColor(229, 229, 229), 1, Qt::SolidLine));    painter->drawRoundedRect(border.x(), border.y(), border.width(), border.height(), rnd.width(), rnd.height());    //气泡    painter->setBrush(QBrush(Qt::white));    painter->setPen(Qt::NoPen);    painter->drawRoundedRect(border.x()+1, border.y()+1, border.width()-2, border.height()-2, rnd.width(), rnd.height());    //三角,用矩形实现    QRect rect1(border.x()+1, border.y()+1, 20, 20);    painter->drawRect(rect1);    //三角加边    QPen pen;    pen.setColor(QColor(229, 229, 229));    painter->setPen(pen);    painter->drawLine(border.x() , border.y() , border.x() +20, border.y() );    painter->drawLine(border.x() , border.y() , border.x() , border.y() +20);    QPen penText;    penText.setColor(QColor(51, 51, 51));    painter->setPen(penText);    QTextOption option1(Qt::AlignLeft);    option1.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);    painter->setFont(font);    QRectF text_rect(kTextPos.x(), kTextPos.y(), text_size_.width(), text_size_.height());    painter->drawText(text_rect, text_, option1);QRectF OtherMsgItem::boundingRect() const    QRectF border(kBorderPos.x(), kBorderPos.y(), text_size_.width() + kMargins.left() + kMargins.right(), text_size_.height() + kMargins.top() + kMargins.bottom());    return QRectF(0,0,border.width(),border.height());

右侧气泡和左侧气泡不同,计算位置时,左端点需要根据窗口宽度事实计算。

#pragma once#include "chatbaseitem.h"#include <QDateTime>class SelfMsgItem : public ChatBaseItem{public:    SelfMsgItem(QPixmap icon, QString msg, QDateTime datetime = QDateTime());    virtual ~SelfMsgItem();    virtual int Resize(int width);  //返回整个item的高度protected:    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);    virtual QRectF boundingRect() const;private:    QGraphicsPixmapItem icon_item_;    QString text_;    QSize text_size_;     //文字尺寸    QDateTime datetime_;    int port_width_;};
#include <QPen>#include <QPainter>#include "selfmsgitem.h"const int kMsgFontSize = 14;const int kNameFontSize = 13;const int kIconY = 0;const int kBorderY = 10;const int kIconWidth = 34;const QMargins kIconMargins = QMargins(10,0,20,0);const QMargins kMargins = QMargins(12, 11, 12, 11);        //文字距边框的距离const int kMarginLeft = 40;                                //边框距窗口左侧的距离SelfMsgItem::SelfMsgItem(QPixmap icon, QString msg, QDateTime datetime )    : ChatBaseItem()    , datetime_(datetime)    , text_(msg){    icon_item_.setPixmap(icon);    icon_item_.setY(kIconY);    icon_item_.setParentItem(this);}SelfMsgItem::~SelfMsgItem(){}int SelfMsgItem::Resize(int width){    port_width_ = width;    //每行最大可容纳文字的宽度    int row_width = width - kMarginLeft - kMargins.left() - kMargins.right() - kIconWidth - kIconMargins.left() - kIconMargins.right();    //计算文字总共需要多宽    QFont font("Microsoft YaHei");    font.setPixelSize(kMsgFontSize);    QFontMetrics font_matrics(font);    int text_total_width = font_matrics.width(text_);    int text_row_height = font_matrics.lineSpacing();    if (row_width < text_total_width)    {        int row = text_total_width / row_width;        int text_total_height = (row+1)* text_row_height;   //row从零开始,需要补加1        text_size_.setWidth(row_width);        text_size_.setHeight(text_total_height);    }    else    {        text_size_.setWidth(text_total_width);        text_size_.setHeight(text_row_height);    }    return text_size_.height() + kMargins.top() + kMargins.bottom() + kBorderY;}void SelfMsgItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget){    QSize rnd(17, 17);    //气泡聊天框左端点需要根据控件宽度计算    QRectF border(port_width_- kIconMargins.left()-kIconMargins.right()-kIconWidth-text_size_.width()-kMargins.left()-kMargins.right()        , kBorderY        , text_size_.width() + kMargins.left() + kMargins.right()        , text_size_.height() + kMargins.top() + kMargins.bottom());    icon_item_.setX(border.x()+ border.width() + 10);    //气泡    painter->setBrush(QBrush(QColor(149,182,57)));    painter->setPen(Qt::NoPen);    painter->drawRoundedRect(border.x(), border.y(), border.width(), border.height(), rnd.width(), rnd.height());    //三角,用矩形实现    QRect rect1(border.x() + border.width() - 20, border.y(), 20, 20);    painter->setPen(Qt::NoPen);    painter->setBrush(QBrush(QColor(149, 182, 57)));    painter->drawRect(rect1);    QPen penText;    penText.setColor(QColor(255, 255, 255));    painter->setPen(penText);    QTextOption option1(Qt::AlignLeft);    option1.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);    QFont font("Microsoft YaHei");    font.setPixelSize(kMsgFontSize);    painter->setFont(font);    QRectF text_rect(border.x()+kMargins.left(), border.y() + kMargins.top(), text_size_.width(), text_size_.height());    painter->drawText(text_rect, text_, option1);}QRectF SelfMsgItem::boundingRect() const{    QRectF border(port_width_ - kIconMargins.left() - kIconMargins.right() - kIconWidth - text_size_.width() - kMargins.left() - kMargins.right()        , kBorderY        , text_size_.width() + kMargins.left() + kMargins.right()        , text_size_.height() + kMargins.top() + kMargins.bottom());    return QRectF(0, 0, border.width(), border.height());}

接下是view调用

#pragma once#include <QGraphicsView>#include <QDateTime>#include <QMap>class ChatBaseItem;class ChatView : public QGraphicsView{    Q_OBJECTpublic:    ChatView(QWidget *parent);    ~ChatView();    void Resize(int width);    void ClearAll();    void AppendSelfMessage(QPixmap icon, QString msg, QDateTime datetime);    void AppendOtherMessage(QPixmap icon,QString name, QString msg, QDateTime datetime);protected:    virtual void mousePressEvent(QMouseEvent *e);private:    void CheckTime(QDateTime datetime);               //检查是否需要插入时间,传入值为当前消息时间    void AppendTime(QDateTime datetime, QString time);    QMap<QDateTime, ChatBaseItem*> items_;};
#include <QDebug>#include <QTextEdit>#include <QScrollBar>#include <QGraphicsScene>#include "chatview.h"#include "chatbaseitem.h"#include "selfmsgitem.h"#include "othermsgitem.h"#include "chattimeitem.h"#include "src/vapplication.h"const int kMarkRole = Qt::UserRole;const int kRoleOtherMsg = kMarkRole + 1;const int kRoleSelfMsg = kRoleOtherMsg + 1;const int kRoleTime = kRoleSelfMsg + 1;ChatView::ChatView(QWidget *parent)    : QGraphicsView(parent){    setScene(new QGraphicsScene());    this->setAlignment(Qt::AlignLeft | Qt::AlignTop);    setStyleSheet("background: rgb(245,245,245) ;border:0px");    this->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);    this->verticalScrollBar()->setStyleSheet(theStyleSheet["scrollbar"]);}ChatView::~ChatView(){    ClearAll();}void ChatView::Resize(int width){    int height = 20;    for (ChatBaseItem* item : items_)    {        item->setPos(0, height);        height = height + item->Resize(width);        height += 20;    }    this->scene()->setSceneRect(QRectF(0, 0, width, height));}void ChatView::ClearAll(){    for (auto it = items_.begin(); it != items_.end();)    {        ChatBaseItem* item = it.value();        it = items_.erase(it);        delete item;    }}void ChatView::AppendSelfMessage(QPixmap icon, QString msg, QDateTime datetime){    ChatBaseItem* item = new SelfMsgItem(icon, msg, datetime);    item->setData(kMarkRole,kRoleSelfMsg);    CheckTime(datetime);    scene()->addItem(item);    items_.insert(datetime, item);    Resize(this->viewport()->width());    update();    //滚动到底部    QScrollBar *vScrollBar = verticalScrollBar();    vScrollBar->setValue(vScrollBar->maximum());}void ChatView::AppendOtherMessage(QPixmap icon, QString name, QString msg, QDateTime datetime){    ChatBaseItem* item = new OtherMsgItem(icon, name, msg, datetime);    item->setData(kMarkRole, kRoleOtherMsg);    CheckTime(datetime);    scene()->addItem(item);    items_.insert(datetime, item);    Resize(this->viewport()->width());    update();    QScrollBar *vScrollBar = verticalScrollBar();    vScrollBar->setValue(vScrollBar->maximum());}void ChatView::mousePressEvent(QMouseEvent *e){    //截获鼠标点击事件}void ChatView::CheckTime(QDateTime datetime){    if (items_.size() == 0|| datetime.secsTo(items_.lasTKEy())>60 * 5)    {        //第一条消息前插入时间        QDateTime dt = datetime.addMSecs(-1);        AppendTime(dt,dt.toString("hh:mm:ss"));    }}void ChatView::AppendTime(QDateTime datetime, QString time){    ChatBaseItem* item = new ChatTimeItem(time);    item->setData(kMarkRole, kRoleTime);    scene()->addItem(item);    items_.insert(datetime, item);    Resize(this->viewport()->width());    update();}
#pragma once#include "chatbaseitem.h"#include <QGraphicsRectItem>class ChatTimeItem : public ChatBaseItem{public:    ChatTimeItem(QString time);    virtual ~ChatTimeItem();    virtual int Resize(int width);protected:    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);private:    QGraphicsSimpleTextItem text_item_;    QString text_;    int port_width_;};
#include <QFont>#include <QPen>#include "chattimeitem.h"#include "color.h"ChatTimeItem::ChatTimeItem(QString time)    : ChatBaseItem(){    text_item_.setText(time);    item_tool::SetFontColor(&text_item_, 13, false, colorspace::GetTextLightColor());    text_item_.setParentItem(this);}ChatTimeItem::~ChatTimeItem()int ChatTimeItem::Resize(int width)    port_width_ = width;    return text_item_.boundingRect().height();void ChatTimeItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)    int width = text_item_.boundingRect().width();    text_item_.setX((port_width_ - width) / 2);

在子类化Item时,一定要注意重写virtual QRectF boundingRect() const;方法,返回实际item的尺寸,让scene知道,并且要加入const,不然当消息左上角超出窗口范围时,会出现无法触发paint的问题。

以上就是关于“怎么使用QGraphicsView实现气泡聊天窗口+排雷功能”这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注编程网精选频道。

--结束END--

本文标题: 怎么使用QGraphicsView实现气泡聊天窗口+排雷功能

本文链接: https://www.lsjlt.com/news/328112.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 使用QGraphicsView实现气泡聊天窗口+排雷功能
    经过多方调查,用Qt实现气泡聊天窗口的方式有如下几个: 使用QWebEngineView控件内嵌html+CSS使用QTextEdit内嵌html使用QGraphicsView实现使...
    99+
    2022-11-13
  • 怎么使用QGraphicsView实现气泡聊天窗口+排雷功能
    这篇“怎么使用QGraphicsView实现气泡聊天窗口+排雷功能”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“怎么使用QG...
    99+
    2023-06-30
  • Vue怎么实现微信聊天窗口展示组件功能
    这篇文章主要介绍“Vue怎么实现微信聊天窗口展示组件功能”,在日常操作中,相信很多人在Vue怎么实现微信聊天窗口展示组件功能问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Vue怎么实现微信聊天窗口展示组件功能...
    99+
    2023-07-04
  • 怎么在python中使用PyQt5实现一个窗口功能
    怎么在python中使用PyQt5实现一个窗口功能?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。python主要应用领域有哪些1、云计算,典型应用OpenSta...
    99+
    2023-06-14
  • 怎么使用electron实现百度网盘悬浮窗口功能
    这篇文章将为大家详细讲解有关怎么使用electron实现百度网盘悬浮窗口功能,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。相关依赖里面使用了vuex vue vue-ro...
    99+
    2022-10-19
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作