#include "../PaintHelper/painthelper.h" #include "globalmsgmgr.h" #include #include #include GlobalMsgMgr::GlobalMsgMgrGarbo GlobalMsgMgr::garbo; GlobalMsgMgr* GlobalMsgMgr::sm_pInstance = new GlobalMsgMgr(nullptr); //初始化静态单例(饿汉): const int g_nSpacing = 20; //弹出消息的间距 const int g_nFlyDistance = 60; //飞入飞出的距离 //const QSize g_sizeWeakHint = QSize(380,48); //弱提示的尺寸(对应窗口的高度还要加上飞入飞出的距离) const int g_nWeakHintHeight = 48; //弱提示的高度(对应窗口的高度还要加上飞入飞出的距离) const int g_nSpeed = 3; //每update间隔时间里移动的像素 const int g_nUpdateInterval = 10; //update间隔时间 const int g_nPaddingTop = 20; //距离上方的高度 const int g_nTextPaddingL = 60; //文本左间距 const int g_nTextPaddingR = 24; //文本右间距 GlobalMsgWidget::GlobalMsgWidget(const QString &msg, HintMode mode, QWidget *parent) : QWidget(parent) , m_mode(mode) , m_strMsg(msg) { setAttribute(Qt::WA_TransparentForMouseEvents); setAttribute(Qt::WA_TranslucentBackground); setWindowFlag(Qt::FramelessWindowHint); QFontMetrics fMetrics(FontEx(fontInfo().family(), 14)); QSize textSize = fMetrics.size(Qt::TextSingleLine, msg); int width = qBound(380, g_nTextPaddingL + g_nTextPaddingR + textSize.width(), 800); m_strMsg = fMetrics.elidedText(msg, Qt::ElideRight, width - g_nTextPaddingL - g_nTextPaddingR); resize(QSize(width, g_nWeakHintHeight + g_nFlyDistance)); m_animFlyInOut.setDuration(g_nFlyDistance/g_nSpeed*g_nUpdateInterval); m_animFlyInOut.setStartValue(0); m_animFlyInOut.setEndValue(g_nFlyDistance); connect(&m_animFlyInOut, &QVariantAnimation::valueChanged, [&](const QVariant &){update();}); connect(&m_animFlyInOut, &QVariantAnimation::finished, [&](){ if(m_animFlyInOut.direction() == QVariantAnimation::Backward) deleteLater(); }); m_animFlyInOut.start(); m_dtStart = QDateTime::currentDateTime(); connect(&m_timerCheckIfStay, &QTimer::timeout, this, &GlobalMsgWidget::CheckIfStay); m_timerCheckIfStay.start(10); } void GlobalMsgWidget::CheckIfStay() { QPoint cursorPos = mapFromGlobal(QCursor::pos()); QRect rectContent(0,m_animFlyInOut.currentValue().toInt(),width(),40); if(rectContent.contains(cursorPos)) { m_dtStart = QDateTime::currentDateTime(); return; } if(m_dtStart.msecsTo(QDateTime::currentDateTime()) >= 3000) { m_animFlyInOut.setDirection(QVariantAnimation::Backward); m_animFlyInOut.start(); m_timerCheckIfStay.stop(); emit sig_Hide(this); } } QColor GlobalMsgWidget::GetBGColor(HintMode mode, int alpha) { if(mode == Success) return QColor(240,249,235,alpha); if(mode == Warn) return QColor(253,246,236,alpha); if(mode == Normal) return QColor(237,242,252,alpha); if(mode == Error) return QColor(254,240,240,alpha); return QColor(30,30,30,alpha); } QColor GlobalMsgWidget::GetTextColor(HintMode mode, int alpha) { if(mode == Success) return QColor(103,194,58,alpha); if(mode == Warn) return QColor(230,162,60,alpha); if(mode == Normal) return QColor(144,147,153,alpha); if(mode == Error) return QColor(245,108,108,alpha); return QColor(30,30,30,alpha); } QString GlobalMsgWidget::GetIconPath(HintMode mode) { if(mode == Success) return QString(":/GlobalMsg/success.png"); if(mode == Warn) return QString(":/GlobalMsg/warn.png"); if(mode == Normal) return QString(":/GlobalMsg/normal.png"); if(mode == Error) return QString(":/GlobalMsg/error.png"); return QString(":/GlobalMsg/normal.png"); } void GlobalMsgWidget::paintEvent(QPaintEvent *) { PainterEx painter(this); QRect rectContent(0,m_animFlyInOut.currentValue().toInt(),width(),g_nWeakHintHeight); double startValue = m_animFlyInOut.startValue().toDouble(); double endValue = m_animFlyInOut.endValue().toDouble(); double curValue = m_animFlyInOut.currentValue().toDouble(); int alpha = qRound((curValue - startValue)/(endValue - startValue) * 255); {//底色 painter.DrawRoundedRect(rectContent, 4, GetBGColor(m_mode,alpha)); } {//图标 QRect iconRect(rectContent.topLeft()+QPoint(28,14), QSize(20,20)); painter.DrawPixmap(iconRect, GetIconPath(m_mode), alpha); } {//文字 QRect textRect(g_nTextPaddingL, rectContent.top(), width() - g_nTextPaddingL - g_nTextPaddingR, g_nWeakHintHeight); painter.setFont(FontEx(painter.fontInfo().family(), 14)); painter.DrawText(textRect, m_strMsg, GetTextColor(m_mode,alpha), Qt::AlignLeft|Qt::AlignVCenter); } } GlobalMsgMgr::GlobalMsgMgr(QObject *parent) : QObject(parent) , m_pRootWidget(nullptr) { connect(&m_timerUpdate, &QTimer::timeout, this, &GlobalMsgMgr::OnUpdate); } void GlobalMsgMgr::SetRootWidget(QWidget *rootWidget) { m_pRootWidget = rootWidget; } void GlobalMsgMgr::Popup(const QString &msg, GlobalMsgWidget::HintMode mode) { //动画思路:单个消息窗, 飞入飞出+淡入淡出; 多个消息窗, 单个本身动画不变, 多个组成队列 //某个消息窗开始飞出时, 它后面的所有消息窗同时上移 //新消息窗飞入时, 从头部位置飞入; 头部位置随着[新消息飞入]和[所有窗口同时上移]而改变, [新消息飞入]则加一个单位, [所有窗口同时上移]则减一个单位 //单个消息窗的[飞入飞出+淡入淡出]用paintevent实现; [所有窗口同时上移]在OnUpdate实现 if(m_pRootWidget == nullptr) return; GlobalMsgWidget *weakWidget = new GlobalMsgWidget(msg, mode); connect(weakWidget, &GlobalMsgWidget::sig_Hide, this, &GlobalMsgMgr::OnWeakHintHide); weakWidget->setWindowFlag(Qt::ToolTip); weakWidget->setParent(m_pRootWidget); int x = (m_pRootWidget->width()-weakWidget->width())/2; int offset = m_listWeakHints.count()*(g_nSpacing + g_nWeakHintHeight); weakWidget->move(x, offset - g_nFlyDistance + g_nPaddingTop); weakWidget->show(); m_listWeakHints.append(weakWidget); if(!m_timerUpdate.isActive()) m_timerUpdate.start(g_nUpdateInterval); } void GlobalMsgMgr::Popup(const QString &msg, QWidget *parentWidget, GlobalMsgWidget::HintMode mode) { //动画思路:单个消息窗, 飞入飞出+淡入淡出; 多个消息窗, 单个本身动画不变, 多个组成队列 //某个消息窗开始飞出时, 它后面的所有消息窗同时上移 //新消息窗飞入时, 从头部位置飞入; 头部位置随着[新消息飞入]和[所有窗口同时上移]而改变, [新消息飞入]则加一个单位, [所有窗口同时上移]则减一个单位 //单个消息窗的[飞入飞出+淡入淡出]用paintevent实现; [所有窗口同时上移]在OnUpdate实现 if(parentWidget == nullptr) return; GlobalMsgWidget *weakWidget = new GlobalMsgWidget(msg, mode); connect(weakWidget, &GlobalMsgWidget::sig_Hide, this, &GlobalMsgMgr::OnWeakHintHide); weakWidget->setWindowFlag(Qt::ToolTip); weakWidget->setParent(parentWidget); int x = (parentWidget->width()-weakWidget->width())/2; int offset = m_listWeakHints.count()*(g_nSpacing + g_nWeakHintHeight); weakWidget->move(x, offset - g_nFlyDistance + g_nPaddingTop); weakWidget->show(); m_listWeakHints.append(weakWidget); if(!m_timerUpdate.isActive()) m_timerUpdate.start(g_nUpdateInterval); } void GlobalMsgMgr::Clear(QWidget *parentWidget) { for(auto weakHint=m_listWeakHints.begin();weakHint!=m_listWeakHints.end();){ if((*weakHint)->parent() == parentWidget) weakHint = m_listWeakHints.erase(weakHint); else ++weakHint; } } void GlobalMsgMgr::OnUpdate() { for(GlobalMsgWidget* weakHint: m_listWeakHints) { int offset = m_listWeakHints.indexOf(weakHint)*(g_nSpacing + g_nWeakHintHeight); int targetPosY = offset - g_nFlyDistance + g_nPaddingTop; QPoint curPos = weakHint->pos(); if(curPos.y() == targetPosY) continue; if(targetPosY > curPos.y()) { int newPosY = qMin(curPos.y()+g_nSpeed, targetPosY); QPoint newPos = QPoint(curPos.x(), newPosY); weakHint->move(newPos); } if(targetPosY < curPos.y()) { int newPosY = qMax(curPos.y()-g_nSpeed, targetPosY); QPoint newPos = QPoint(curPos.x(), newPosY); weakHint->move(newPos); } } } void GlobalMsgMgr::OnWeakHintHide(GlobalMsgWidget* pWeakHint) { if(m_listWeakHints.contains(pWeakHint)) m_listWeakHints.removeOne(pWeakHint); }