【资料图】
使用QQ时,当有消息过来时,托盘的图标一闪一闪的,鼠标悬浮时出现消息通知列表,显示名字和数量,Qt有自带的消息托盘,那没有鼠标悬浮事件,这里通知定时器查找鼠标的坐标,在托盘范围内时显示消息列表,离开托盘范围时隐藏列表,消息列表采用Qt的Model、View加自定义委托实现,代码实现如下:
#ifndef ITEMDEFINE_H#define ITEMDEFINE_H#include #include #include #define PrintTime (QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:"))//托盘消息结构typedef struct STTrayInfo{QString strAvatar{""};//头像QString strName{""};int unReadCount{0};//未读数}TrayInfo;Q_DECLARE_METATYPE(TrayInfo)#endif // ITEMDEFINE_H
#ifndef CITEMDELEGATE_H#define CITEMDELEGATE_H#include #include #include class CItemDelegate : public QStyledItemDelegate{Q_OBJECTpublic:explicit CItemDelegate(QObject *parent = nullptr);~CItemDelegate();//重画函数void paint(QPainter * painter,const QStyleOptionViewItem & option,const QModelIndex & index) const;QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;private:QFont font = QFont("Microsoft YaHei");};#endif // CITEMDELEGATE_H
#include ""#include #include #include #include #include #include #include ""CItemDelegate::CItemDelegate(QObject *parent) :QStyledItemDelegate(parent){(10);}CItemDelegate::~CItemDelegate(){}void CItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const{if(()){painter->save();QVariant variant = (Qt::UserRole+1);//根据角色取值TrayInfo data = ();QStyleOptionViewItem viewOption(option);//用来在视图中画一个itemQRectF rect;(());(());(()-1);(()-1);if((QStyle::State_Selected))//选中画背景{painter->setPen(QPen(Qt::blue));painter->setBrush(QColor(229, 241, 255));painter->drawRect(rect);}else if((QStyle::State_MouseOver))//鼠标悬浮画背景{painter->setPen(QPen(Qt::green));painter->setBrush(QColor(189, 193, 217));//bdc1d9painter->drawRect(rect);}// else{//默认状态// painter->setPen(QPen(Qt::gray));// painter->setBrush(Qt::NoBrush);// painter->drawRect(path);// }//画头像QPixmap pix();if(())(":/image/system_");pix = (30, 30, Qt::KeepAspectRatio, Qt::SmoothTransformation);QRect imageRect = QRect(() + 5, ()+5, 30, 30);painter->drawPixmap(imageRect, pix);//画名字QFontMetrics fontMetrics(font);//如果当前字体下,字符串长度大于100QString fileName = ;if((fileName) >150){fileName = QFontMetrics(font).elidedText(fileName, Qt::ElideRight, 150);}QRect NameRect = QRect(() + 40, ()+10, 150, 18);painter->setRenderHints(QPainter::Antialiasing|QPainter::TextAntialiasing, true);//抗锯齿painter->setPen(QPen(Qt::blue));painter->setFont(font);painter->drawText(NameRect, Qt::AlignLeft, fileName);//画圆QRect circle = QRect(() + 200, ()+5, 30, 20);painter->setBrush(Qt::red);//画填充painter->setPen(QPen(Qt::red));painter->drawRoundedRect(circle, 10, 10, Qt::RelativeSize);//圆角矩形//画统计数字QRect UnReadRect = QRect(() + 200, ()+5, 30, 20);painter->setPen(QPen(Qt::white));painter->setFont(font);painter->drawText(UnReadRect, Qt::AlignCenter, QString("%1").arg());painter->restore();}}QSize CItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const{return QSize(260, 40);}
#ifndef CNOTICELIST_H#define CNOTICELIST_H#include #include #include ""#include ""#include #include namespace Ui {class CNoticeList;}class CNoticeList : public QWidget{Q_OBJECTpublic:explicit CNoticeList(QWidget *parent = nullptr);~CNoticeList();void initView();void initData();void initConnect();void initModelData();void setWidgetHeight();int rowCount();void deleteListItem(const TrayInfo &sessionInfo);void changeListItem(const TrayInfo &sessionInfo);public slots:void slotItemClicked(const QModelIndex &index);void slotIgnoreAll();protected:void mouseReleaseEvent(QMouseEvent *event);private:Ui::CNoticeList *ui;QStandardItemModel *m_model{nullptr};CItemDelegate *m_delegate{nullptr};int m_nMessageTotal{0};QMutex m_MutexNotice;QMap>m_mapMsgid;};#endif // CNOTICELIST_H
#include ""#include "ui_"#include #include #include #include #include CNoticeList::CNoticeList(QWidget *parent) :QWidget(parent),ui(new Ui::CNoticeList){ui->setupUi(this);setWindowFlags(Qt::FramelessWindowHint | Qt::WindowMinimizeButtonHint | Qt::WindowStaysOnTopHint //不显示菜单栏| Qt::Tool);//不显示任务栏图标initView();initData();initConnect();}CNoticeList::~CNoticeList(){delete ui;}void CNoticeList::initView(){ui->pushButton_ignoreAll->setStyleSheet("QPushButton{""font-family: \"Microsoft YaHei\";""font-size: 12px;""color: blue;}");ui->label_newMesage->setStyleSheet("QLabel{font-family: \"Microsoft YaHei\";font-size: 12px;}");ui->label_count->setStyleSheet("QLabel{font-family: \"Microsoft YaHei\";font-size: 12px;}");ui->listView->verticalScrollBar()->setStyleSheet("QScrollBar:vertical{width:8px;background:rgba(0,0,0,0%);""margin:0px,0px,0px,0px;padding-top:9px;padding-bottom:9px;}"// 留出9px给上面和下面的箭头"QScrollBar::handle:vertical{width:8px;background:rgba(0,0,0,25%);""border-radius:4px;min-height:20;}"// 滚动条两端变成椭圆"QScrollBar::handle:vertical:hover{width:8px;background:rgba(0,0,0,50%);""border-radius:4px;min-height:20;}");// 鼠标放到滚动条上的时候,颜色变深ui->listView->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);ui->listView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);}void CNoticeList::initData(){m_delegate = new CItemDelegate();m_model = new QStandardItemModel();ui->listView->setItemDelegate(m_delegate);ui->listView->setModel(m_model);ui->listView->setSpacing(0);initModelData();}void CNoticeList::initConnect(){connect(ui->listView, &QListView::clicked, this, &CNoticeList::slotItemClicked);connect(ui->pushButton_ignoreAll, &QPushButton::clicked, this, &CNoticeList::slotIgnoreAll);}void CNoticeList::initModelData(){QStringListModel *stringlistModel = new QStringListModel(QColor::colorNames(), this);//获取颜色值QStringList colorList = stringlistModel->stringList();for (int i = 1; i < 7; ++i){QStandardItem *Item = new QStandardItem;TrayInfo itemData; = QString(":/image/%").arg(i); = colorList[i]; = 1;m_nMessageTotal += 1;Item->setData(, Qt::UserRole); // 单一存取 这个用来匹配过滤条件Item->setData(QVariant::fromValue(itemData), Qt::UserRole+1);//整体存取m_model->insertRow(0, Item); //追加Item}setWidgetHeight();}void CNoticeList::setWidgetHeight(){//刷新消息数量if(m_nMessageTotal >0)ui->label_count->setText(QString("%1").arg(m_nMessageTotal));elseui->label_count->setText("");if(m_model->rowCount() < 5){ui->listView->setMinimumHeight(m_model->rowCount() * 40 + 4);ui->listView->setMaximumHeight(m_model->rowCount() * 40 + 4);this->setMinimumHeight(ui->listView->height() + 60);this->setMaximumHeight(ui->listView->height() + 60);}else{ui->listView->setMinimumHeight(204);ui->listView->setMaximumHeight(204);this->setMinimumHeight(264);this->setMaximumHeight(264);}}int CNoticeList::rowCount(){if(nullptr == m_model)return 0;elsem_model->rowCount();}void CNoticeList::mouseReleaseEvent(QMouseEvent *event){if(event->button() == Qt::LeftButton)this->hide();}void CNoticeList::deleteListItem(const TrayInfo &info){for(int i = 0; i < m_model->rowCount(); ++i){QStandardItem *Item = m_model->item(i);QString strName = Item->data(Qt::UserRole).toString();if(0 == ()){QVariant variant = Item->data(Qt::UserRole+1);//根据角色取值TrayInfo data = ();m_nMessageTotal -= ;//总消息数减去这个会话消息数if(m_nMessageTotal < 0)m_nMessageTotal = 0;m_model->removeRow(i);break;}}setWidgetHeight();}void CNoticeList::slotItemClicked(const QModelIndex &index){QMutexLocker locker(&m_MutexNotice);QVariant variant = (Qt::UserRole+1);//根据角色取值TrayInfo data = ();//删除这个itemdeleteListItem(data);//隐藏自己this->hide();}void CNoticeList::slotIgnoreAll(){QMutexLocker locker(&m_MutexNotice);if(m_model->rowCount() >0){m_model->clear();m_nMessageTotal = 0;this->hide();}}
#ifndef CUSTOMSYSTEMTRAY_H#define CUSTOMSYSTEMTRAY_H#include #include #include #include #include #include ""#include ""#include ""class QAction;class QMemu;class QSystemTrayIcon;class QWidget;class QWidgetAction;class QPushButton;class QToolButton;class QLabel;class QHBoxLayout;class QPainter;class QTimer;class CustomSystemTray : public QSystemTrayIcon{Q_OBJECTpublic:explicit CustomSystemTray(QObject *parent = nullptr);void initData();void checkMousePosition();//Qt的托盘没有悬停事件,通过鼠标光标位置来判断悬浮事件void initConnect();public slots:void slotMessageNotice();void slotFlashTimerOut();private:QTimer *m_pMessageNotice{nullptr};//模拟消息通知QTimer *m_pTimerFlash{nullptr};//图标闪烁int m_flashCount{0};CNoticeList *m_noticList{nullptr};};#endif // CUSTOMSYSTEMTRAY_H
#include ""#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include CustomSystemTray::CustomSystemTray(QObject *parent) :QSystemTrayIcon(parent){initData();}void CustomSystemTray::initData(){m_noticList = new CNoticeList();m_pTimerFlash = new QTimer;connect(m_pTimerFlash, &QTimer::timeout, this, &CustomSystemTray::slotFlashTimerOut);m_pTimerFlash->start(500);}void CustomSystemTray::checkMousePosition(){//托盘位置24X40QRect currentRect = geometry();int xMin = ();int xMax = () + ();int yMin = ();int yMax = () + ();int x = QCursor::pos().x();int y = QCursor::pos().y();if(xMin<=x && x<=xMax && yMin<=y && y<=yMax){QRect menuRect;(xMin);(yMin - m_noticList->height());(m_noticList->width());(m_noticList->height());m_noticList->setGeometry(menuRect);if(m_noticList->rowCount() >0)m_noticList->show();elsem_noticList->hide();}else if((nullptr != m_noticList) && (!m_noticList->isHidden())){//如果是显示的消息框,鼠标在显示框范围内不隐藏int pxMin = xMin;int pxMax = xMin + m_noticList->width();int pyMin = yMin - m_noticList->height();int pyMax = yMin;if(pxMin<=x && x<=pxMax && pyMin<=y && y<=pyMax)m_noticList->show();elsem_noticList->hide();}}void CustomSystemTray::initConnect(){// 此处使用定时器模拟消息的发送m_pMessageNotice = new QTimer;connect(m_pMessageNotice, &QTimer::timeout, this, &CustomSystemTray::slotMessageNotice);m_pMessageNotice->start(3000);}void CustomSystemTray::slotMessageNotice(){m_flashCount = 0;if (m_pTimerFlash == nullptr){m_pTimerFlash = new QTimer;connect(m_pTimerFlash, &QTimer::timeout, this, &CustomSystemTray::slotFlashTimerOut);m_pTimerFlash->start(500);}}void CustomSystemTray::slotFlashTimerOut(){if(m_noticList->rowCount() < 1){this->setIcon(QIcon(":/image/"));return;}//qDebug() << "slotFlashTimerOut============m_flashCount=====" << m_flashCount;// 消息通知,使用定时器刷新图标m_flashCount++;checkMousePosition();if (m_flashCount % 2 == 1){this->setIcon(QIcon(":/image/"));}else{this->setIcon(QIcon(":/image/"));}}
运行效果
【领 QT开发教程 学习资料, 点击下方链接莬费领取↓↓ ,先码住不迷路~】
点击这里:
关键词:
-
QT托盘消息模拟QQ消息通知
使用QQ时,当有消息过来时,托盘的图标一闪一闪的,鼠标悬浮时出现消息通知列表,显示名字和数量,Qt有自带
-
词圣是苏轼还是辛弃疾_词圣
1、至圣:孔子,名丘,字仲尼,鲁国人,春秋时期伟大的思想家、政治家、教育家,儒家学派的创始人。2、诗圣
-
全球热门:家庭篇章:美满幸福的准则
家庭篇章:美满幸福的准则实事求是的讲,您原生家庭如何?家里是否有喋喋不休的争吵?是否父亲和母亲因为琐
-
河北三河通报城管与货车司机肢体接触:涉事人员停职调查
情况通报5月29日上午九时左右,三河市城市管理综合行政执法局执法人员在燕郊汉王路进行环境综合整治过程中
-
天天要闻:麦格米特:5月29日融资买入323.62万元,融资融券余额1.08亿元
5月29日,麦格米特(002851)融资买入323 62万元,融资偿还292 51万元,融资净买入31 11万元,融资余额1 03
-
今日热闻!“吴谢宇弑母案”二审公开宣判:驳回上诉 维持原判
2023年5月30日,福建省高级人民法院对吴谢宇故意杀人、诈骗、买卖身份证件上诉一案二审公开宣判,裁定驳回
-
法雷奥战略投资滴滴自动驾驶 联合研发L4级无人驾驶出租车智能安全解决方案
5月29日,滴滴自动驾驶与法雷奥签署战略合作及投资意向书,法雷奥将对滴滴自动驾驶进行战略投资,并共同开
-
消息!北京普降小雨,带来“夏日福利”,明天还有雨
北京日报客户端|记者骆倩雯停歇了两天,雨水又来眷顾京城了。截至目前,全市已普降小雨,降雨仍在继续。据
-
全球今热点:「LG杯世界棋王赛」中国军团首轮狂飙,柯洁明日期待“复仇战”
文 羊城晚报全媒体记者赵亮晨29日,第28届LG杯世界棋王赛在韩国京畿道战罢首轮,首轮出战的中国棋手斩获4胜
-
肇庆:狂奔在新能源汽车产业新赛道上
本报记者姜业庆风起于青萍之末,浪成于微澜之间。新能源汽车产业对于肇庆而言,何尝不是如此:从汽车零部件
-
西樵山门票优惠对象及办法(西樵山门票优惠对象及办法有哪些)-世界视点
免票:6周岁(含)以下或身高1 2米(含)以下儿童及65周岁(含)以上老年人、残疾人、现役军人、宗教人士、全国医
-
今头条!又赚一笔!姆巴佩自宣留队,9月可领忠诚奖金9000万欧
北京时间今天凌晨,巴黎法国前锋姆巴佩被评为本赛季法甲最佳球员,这也是他个人连续第4次获得该奖项。与此
-
亚运会LPL下路到底选谁?GALA和Elk谁能胜任
2022年亚洲运动会即将举行,中国国家队的选拔也正在进行中。作为电竞项目中的一员,英雄联盟韩国国家队名单
-
微头条丨四部门启动高校毕业生等青年就业创业政策宣传周活动
人社部会同教育部、共青团中央、全国工商联印发通知,从5月29日起,在全国启动“就业扬帆政策护航”高校毕
-
环球今亮点!财经观察:着重激发创新源头活力 科技让生活更精彩
“AIGC元宇宙虚拟数字人”项目展示的元宇宙虚拟走秀;集光电技术、生物学技术和物联网技术造就的“植物工厂
-
MEETANDFUCKGAMES在线视频_meetandfuck 世界快讯
1、我也想要2016的。2、我只有2013到2015的。本文到此分享完毕,希望对大家有所帮助。
-
环球视讯!看起来三星将在2023年采取更简约的外观
今天早些时候,我们第一次看到了三星的设计精神在2023年会是什么样子。这种洞察力的来源是史蒂夫·海默斯托
-
环球今热点:2023上海SNEC,中电电气三箭齐发 探索绿色发展新未来
5月24-26日,第十六届(2023)国际太阳能光伏与智慧能源(上海)大会暨展览会在上海新国际博览中心盛大开展
-
环球热点评!宣亚国际(300612.SZ):目前未与英伟达有直接合作,与英博数科等合作伙伴的相关合作尚处于探索初期
格隆汇5月29日丨有投资者在投资者互动平台向宣亚国际(300612)(300612 SZ)提问,“贵公司与英伟达有相关合作
-
打牢基础建强阵地 昆明市碧谷街道切实发挥党校育人促乡村振兴作用
昆明市碧谷街道党校自2020年4月挂牌成立以来,在“建、管、用”上持续发力,接轨乡村振兴,突显人才培育