怎么使用QGraphicsView实现气泡聊天窗口+排雷功能(qgraphicsview,开发技术)

时间:2024-05-06 16:54:37 作者 : 石家庄SEO 分类 : 开发技术
  • TAG :

最终效果:

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

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

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

#pragmaonce#include<QGraphicsRectItem>//聊天元素所有item的基类classChatBaseItem:publicQGraphicsRectItem{public:ChatBaseItem();virtual~ChatBaseItem();virtualintResize(intwidth);//传入值为viewport宽,返回值为item高};
#include"chatbaseitem.h"ChatBaseItem::ChatBaseItem():QGraphicsRectItem(){}ChatBaseItem::~ChatBaseItem()intChatBaseItem::Resize(intwidth)return0;

左侧聊天气泡Item

#pragmaonce#include"chatbaseitem.h"#include<QDateTime>classOtherMsgItem:publicChatBaseItem{public:OtherMsgItem(QPixmapicon,QStringname,QStringmsg,QDateTimedatetime=QDateTime());virtual~OtherMsgItem();virtualintResize(intwidth);//返回整个item的高度protected:voidpaint(QPainter*painter,constQStyleOptionGraphicsItem*option,QWidget*widget);virtualQRectFboundingRect()const;private:QGraphicsPixmapItemicon_item_;QGraphicsSimpleTextItemname_item_;QStringtext_;QSizetext_size_;//文字尺寸QDateTimedatetime_;};
#include<QPainter>#include<QMargins>#include<QTextOption>#include"othermsgitem.h"constintkMsgFontSize=14;constintkNameFontSize=13;constQPointkNamePos=QPoint(64,0);constQPointkIconPos=QPoint(20,8);constQPointkBorderPos=QPoint(kNamePos.x(),kNamePos.y()+18);constQMarginskMargins=QMargins(12,11,12,11);//文字距边框的距离constQPointkTextPos=QPoint(kBorderPos.x()+kMargins.left(),kBorderPos.y()+kMargins.top());constintkMarginRight=40;//边框距窗口右侧的距离OtherMsgItem::OtherMsgItem(QPixmapicon,QStringname,QStringmsg,QDateTimedatetime/*=QDateTime()*/):ChatBaseItem(),datetime_(datetime){icon_item_.setPixmap(icon);icon_item_.setPos(kIconPos);text_=msg;QFontfont("MicrosoftYaHei");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()intOtherMsgItem::Resize(intwidth)//每行最大可容纳文字的宽度introw_width=width-kTextPos.x()-kMarginRight-kMargins.right();//计算文字总共需要多宽font.setPixelSize(kMsgFontSize);QFontMetricsfont_matrics(font);inttext_total_width=font_matrics.width(text_);inttext_row_height=font_matrics.lineSpacing();if(row_width<text_total_width){introw=text_total_width/row_width;++row;inttext_total_height=row*text_row_height;text_size_.setWidth(row_width);text_size_.setHeight(text_total_height);}elsetext_size_.setWidth(text_total_width);text_size_.setHeight(text_row_height);returntext_size_.height()+kMargins.top()+kMargins.bottom()+kBorderPos.y();voidOtherMsgItem::paint(QPainter*painter,constQStyleOptionGraphicsItem*option,QWidget*widget)QSizernd(17,17);QRectFborder(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());//三角,用矩形实现QRectrect1(border.x()+1,border.y()+1,20,20);painter->drawRect(rect1);//三角加边QPenpen;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);QPenpenText;penText.setColor(QColor(51,51,51));painter->setPen(penText);QTextOptionoption1(Qt::AlignLeft);option1.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);painter->setFont(font);QRectFtext_rect(kTextPos.x(),kTextPos.y(),text_size_.width(),text_size_.height());painter->drawText(text_rect,text_,option1);QRectFOtherMsgItem::boundingRect()constQRectFborder(kBorderPos.x(),kBorderPos.y(),text_size_.width()+kMargins.left()+kMargins.right(),text_size_.height()+kMargins.top()+kMargins.bottom());returnQRectF(0,0,border.width(),border.height());

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

#pragmaonce#include"chatbaseitem.h"#include<QDateTime>classSelfMsgItem:publicChatBaseItem{public:SelfMsgItem(QPixmapicon,QStringmsg,QDateTimedatetime=QDateTime());virtual~SelfMsgItem();virtualintResize(intwidth);//返回整个item的高度protected:voidpaint(QPainter*painter,constQStyleOptionGraphicsItem*option,QWidget*widget);virtualQRectFboundingRect()const;private:QGraphicsPixmapItemicon_item_;QStringtext_;QSizetext_size_;//文字尺寸QDateTimedatetime_;intport_width_;};
#include<QPen>#include<QPainter>#include"selfmsgitem.h"constintkMsgFontSize=14;constintkNameFontSize=13;constintkIconY=0;constintkBorderY=10;constintkIconWidth=34;constQMarginskIconMargins=QMargins(10,0,20,0);constQMarginskMargins=QMargins(12,11,12,11);//文字距边框的距离constintkMarginLeft=40;//边框距窗口左侧的距离SelfMsgItem::SelfMsgItem(QPixmapicon,QStringmsg,QDateTimedatetime/*=QDateTime()*/):ChatBaseItem(),datetime_(datetime),text_(msg){icon_item_.setPixmap(icon);icon_item_.setY(kIconY);icon_item_.setParentItem(this);}SelfMsgItem::~SelfMsgItem(){}intSelfMsgItem::Resize(intwidth){port_width_=width;//每行最大可容纳文字的宽度introw_width=width-kMarginLeft-kMargins.left()-kMargins.right()-kIconWidth-kIconMargins.left()-kIconMargins.right();//计算文字总共需要多宽QFontfont("MicrosoftYaHei");font.setPixelSize(kMsgFontSize);QFontMetricsfont_matrics(font);inttext_total_width=font_matrics.width(text_);inttext_row_height=font_matrics.lineSpacing();if(row_width<text_total_width){introw=text_total_width/row_width;inttext_total_height=(row+1)*text_row_height;//row从零开始,需要补加1text_size_.setWidth(row_width);text_size_.setHeight(text_total_height);}else{text_size_.setWidth(text_total_width);text_size_.setHeight(text_row_height);}returntext_size_.height()+kMargins.top()+kMargins.bottom()+kBorderY;}voidSelfMsgItem::paint(QPainter*painter,constQStyleOptionGraphicsItem*option,QWidget*widget){QSizernd(17,17);//气泡聊天框左端点需要根据控件宽度计算QRectFborder(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());//三角,用矩形实现QRectrect1(border.x()+border.width()-20,border.y(),20,20);painter->setPen(Qt::NoPen);painter->setBrush(QBrush(QColor(149,182,57)));painter->drawRect(rect1);QPenpenText;penText.setColor(QColor(255,255,255));painter->setPen(penText);QTextOptionoption1(Qt::AlignLeft);option1.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);QFontfont("MicrosoftYaHei");font.setPixelSize(kMsgFontSize);painter->setFont(font);QRectFtext_rect(border.x()+kMargins.left(),border.y()+kMargins.top(),text_size_.width(),text_size_.height());painter->drawText(text_rect,text_,option1);}QRectFSelfMsgItem::boundingRect()const{QRectFborder(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());returnQRectF(0,0,border.width(),border.height());}

接下是view调用

#pragmaonce#include<QGraphicsView>#include<QDateTime>#include<QMap>classChatBaseItem;classChatView:publicQGraphicsView{Q_OBJECTpublic:ChatView(QWidget*parent);~ChatView();voidResize(intwidth);voidClearAll();voidAppendSelfMessage(QPixmapicon,QStringmsg,QDateTimedatetime);voidAppendOtherMessage(QPixmapicon,QStringname,QStringmsg,QDateTimedatetime);protected:virtualvoidmousePressEvent(QMouseEvent*e);private:voidCheckTime(QDateTimedatetime);//检查是否需要插入时间,传入值为当前消息时间voidAppendTime(QDateTimedatetime,QStringtime);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"constintkMarkRole=Qt::UserRole;constintkRoleOtherMsg=kMarkRole+1;constintkRoleSelfMsg=kRoleOtherMsg+1;constintkRoleTime=kRoleSelfMsg+1;ChatView::ChatView(QWidget*parent):QGraphicsView(parent){setScene(newQGraphicsScene());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();}voidChatView::Resize(intwidth){intheight=20;for(ChatBaseItem*item:items_){item->setPos(0,height);height=height+item->Resize(width);height+=20;}this->scene()->setSceneRect(QRectF(0,0,width,height));}voidChatView::ClearAll(){for(autoit=items_.begin();it!=items_.end();){ChatBaseItem*item=it.value();it=items_.erase(it);deleteitem;}}voidChatView::AppendSelfMessage(QPixmapicon,QStringmsg,QDateTimedatetime){ChatBaseItem*item=newSelfMsgItem(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());}voidChatView::AppendOtherMessage(QPixmapicon,QStringname,QStringmsg,QDateTimedatetime){ChatBaseItem*item=newOtherMsgItem(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());}voidChatView::mousePressEvent(QMouseEvent*e){//截获鼠标点击事件}voidChatView::CheckTime(QDateTimedatetime){if(items_.size()==0||datetime.secsTo(items_.lastKey())>60*5/*5分钟*/){//第一条消息前插入时间QDateTimedt=datetime.addMSecs(-1);AppendTime(dt,dt.toString("hh:mm:ss"));}}voidChatView::AppendTime(QDateTimedatetime,QStringtime){ChatBaseItem*item=newChatTimeItem(time);item->setData(kMarkRole,kRoleTime);scene()->addItem(item);items_.insert(datetime,item);Resize(this->viewport()->width());update();}
#pragmaonce#include"chatbaseitem.h"#include<QGraphicsRectItem>classChatTimeItem:publicChatBaseItem{public:ChatTimeItem(QStringtime);virtual~ChatTimeItem();virtualintResize(intwidth);protected:voidpaint(QPainter*painter,constQStyleOptionGraphicsItem*option,QWidget*widget);private:QGraphicsSimpleTextItemtext_item_;QStringtext_;intport_width_;};
#include<QFont>#include<QPen>#include"chattimeitem.h"#include"color.h"ChatTimeItem::ChatTimeItem(QStringtime):ChatBaseItem(){text_item_.setText(time);item_tool::SetFontColor(&text_item_,13,false,colorspace::GetTextLightColor());text_item_.setParentItem(this);}ChatTimeItem::~ChatTimeItem()intChatTimeItem::Resize(intwidth)port_width_=width;returntext_item_.boundingRect().height();voidChatTimeItem::paint(QPainter*painter,constQStyleOptionGraphicsItem*option,QWidget*widget)intwidth=text_item_.boundingRect().width();text_item_.setX((port_width_-width)/2);

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

 </div> <div class="zixun-tj-product adv-bottom"></div> </div> </div> <div class="prve-next-news">
本文:怎么使用QGraphicsView实现气泡聊天窗口+排雷功能的详细内容,希望对您有所帮助,信息来源于网络。
上一篇:如何使用python opencv库玩转视频帧率下一篇:

6 人围观 / 0 条评论 ↓快速评论↓

(必须)

(必须,保密)

阿狸1 阿狸2 阿狸3 阿狸4 阿狸5 阿狸6 阿狸7 阿狸8 阿狸9 阿狸10 阿狸11 阿狸12 阿狸13 阿狸14 阿狸15 阿狸16 阿狸17 阿狸18