globalmsgmgr.cpp 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. #include "../PaintHelper/painthelper.h"
  2. #include "globalmsgmgr.h"
  3. #include <QPainter>
  4. #include <QTimer>
  5. #include <QDebug>
  6. GlobalMsgMgr::GlobalMsgMgrGarbo GlobalMsgMgr::garbo;
  7. GlobalMsgMgr* GlobalMsgMgr::sm_pInstance = new GlobalMsgMgr(nullptr); //初始化静态单例(饿汉):
  8. const int g_nSpacing = 20; //弹出消息的间距
  9. const int g_nFlyDistance = 60; //飞入飞出的距离
  10. //const QSize g_sizeWeakHint = QSize(380,48); //弱提示的尺寸(对应窗口的高度还要加上飞入飞出的距离)
  11. const int g_nWeakHintHeight = 48; //弱提示的高度(对应窗口的高度还要加上飞入飞出的距离)
  12. const int g_nSpeed = 3; //每update间隔时间里移动的像素
  13. const int g_nUpdateInterval = 10; //update间隔时间
  14. const int g_nPaddingTop = 20; //距离上方的高度
  15. const int g_nTextPaddingL = 60; //文本左间距
  16. const int g_nTextPaddingR = 24; //文本右间距
  17. GlobalMsgWidget::GlobalMsgWidget(const QString &msg, HintMode mode, QWidget *parent)
  18. : QWidget(parent)
  19. , m_mode(mode)
  20. , m_strMsg(msg)
  21. {
  22. setAttribute(Qt::WA_TransparentForMouseEvents);
  23. setAttribute(Qt::WA_TranslucentBackground);
  24. setWindowFlag(Qt::FramelessWindowHint);
  25. QFontMetrics fMetrics(FontEx(fontInfo().family(), 14));
  26. QSize textSize = fMetrics.size(Qt::TextSingleLine, msg);
  27. int width = qBound(380, g_nTextPaddingL + g_nTextPaddingR + textSize.width(), 800);
  28. m_strMsg = fMetrics.elidedText(msg, Qt::ElideRight, width - g_nTextPaddingL - g_nTextPaddingR);
  29. resize(QSize(width, g_nWeakHintHeight + g_nFlyDistance));
  30. m_animFlyInOut.setDuration(g_nFlyDistance/g_nSpeed*g_nUpdateInterval);
  31. m_animFlyInOut.setStartValue(0);
  32. m_animFlyInOut.setEndValue(g_nFlyDistance);
  33. connect(&m_animFlyInOut, &QVariantAnimation::valueChanged, [&](const QVariant &){update();});
  34. connect(&m_animFlyInOut, &QVariantAnimation::finished, [&](){
  35. if(m_animFlyInOut.direction() == QVariantAnimation::Backward) deleteLater();
  36. });
  37. m_animFlyInOut.start();
  38. m_dtStart = QDateTime::currentDateTime();
  39. connect(&m_timerCheckIfStay, &QTimer::timeout, this, &GlobalMsgWidget::CheckIfStay);
  40. m_timerCheckIfStay.start(10);
  41. }
  42. void GlobalMsgWidget::CheckIfStay()
  43. {
  44. QPoint cursorPos = mapFromGlobal(QCursor::pos());
  45. QRect rectContent(0,m_animFlyInOut.currentValue().toInt(),width(),40);
  46. if(rectContent.contains(cursorPos))
  47. {
  48. m_dtStart = QDateTime::currentDateTime();
  49. return;
  50. }
  51. if(m_dtStart.msecsTo(QDateTime::currentDateTime()) >= 3000)
  52. {
  53. m_animFlyInOut.setDirection(QVariantAnimation::Backward);
  54. m_animFlyInOut.start();
  55. m_timerCheckIfStay.stop();
  56. emit sig_Hide(this);
  57. }
  58. }
  59. QColor GlobalMsgWidget::GetBGColor(HintMode mode, int alpha)
  60. {
  61. if(mode == Success) return QColor(240,249,235,alpha);
  62. if(mode == Warn) return QColor(253,246,236,alpha);
  63. if(mode == Normal) return QColor(237,242,252,alpha);
  64. if(mode == Error) return QColor(254,240,240,alpha);
  65. return QColor(30,30,30,alpha);
  66. }
  67. QColor GlobalMsgWidget::GetTextColor(HintMode mode, int alpha)
  68. {
  69. if(mode == Success) return QColor(103,194,58,alpha);
  70. if(mode == Warn) return QColor(230,162,60,alpha);
  71. if(mode == Normal) return QColor(144,147,153,alpha);
  72. if(mode == Error) return QColor(245,108,108,alpha);
  73. return QColor(30,30,30,alpha);
  74. }
  75. QString GlobalMsgWidget::GetIconPath(HintMode mode)
  76. {
  77. if(mode == Success) return QString(":/GlobalMsg/success.png");
  78. if(mode == Warn) return QString(":/GlobalMsg/warn.png");
  79. if(mode == Normal) return QString(":/GlobalMsg/normal.png");
  80. if(mode == Error) return QString(":/GlobalMsg/error.png");
  81. return QString(":/GlobalMsg/normal.png");
  82. }
  83. void GlobalMsgWidget::paintEvent(QPaintEvent *)
  84. {
  85. PainterEx painter(this);
  86. QRect rectContent(0,m_animFlyInOut.currentValue().toInt(),width(),g_nWeakHintHeight);
  87. double startValue = m_animFlyInOut.startValue().toDouble();
  88. double endValue = m_animFlyInOut.endValue().toDouble();
  89. double curValue = m_animFlyInOut.currentValue().toDouble();
  90. int alpha = qRound((curValue - startValue)/(endValue - startValue) * 255);
  91. {//底色
  92. painter.DrawRoundedRect(rectContent, 4, GetBGColor(m_mode,alpha));
  93. }
  94. {//图标
  95. QRect iconRect(rectContent.topLeft()+QPoint(28,14), QSize(20,20));
  96. painter.DrawPixmap(iconRect, GetIconPath(m_mode), alpha);
  97. }
  98. {//文字
  99. QRect textRect(g_nTextPaddingL, rectContent.top(), width() - g_nTextPaddingL - g_nTextPaddingR, g_nWeakHintHeight);
  100. painter.setFont(FontEx(painter.fontInfo().family(), 14));
  101. painter.DrawText(textRect, m_strMsg, GetTextColor(m_mode,alpha), Qt::AlignLeft|Qt::AlignVCenter);
  102. }
  103. }
  104. GlobalMsgMgr::GlobalMsgMgr(QObject *parent)
  105. : QObject(parent)
  106. , m_pRootWidget(nullptr)
  107. {
  108. connect(&m_timerUpdate, &QTimer::timeout, this, &GlobalMsgMgr::OnUpdate);
  109. }
  110. void GlobalMsgMgr::SetRootWidget(QWidget *rootWidget)
  111. {
  112. m_pRootWidget = rootWidget;
  113. }
  114. void GlobalMsgMgr::Popup(const QString &msg, GlobalMsgWidget::HintMode mode)
  115. {
  116. //动画思路:单个消息窗, 飞入飞出+淡入淡出; 多个消息窗, 单个本身动画不变, 多个组成队列
  117. //某个消息窗开始飞出时, 它后面的所有消息窗同时上移
  118. //新消息窗飞入时, 从头部位置飞入; 头部位置随着[新消息飞入]和[所有窗口同时上移]而改变, [新消息飞入]则加一个单位, [所有窗口同时上移]则减一个单位
  119. //单个消息窗的[飞入飞出+淡入淡出]用paintevent实现; [所有窗口同时上移]在OnUpdate实现
  120. if(m_pRootWidget == nullptr) return;
  121. GlobalMsgWidget *weakWidget = new GlobalMsgWidget(msg, mode);
  122. connect(weakWidget, &GlobalMsgWidget::sig_Hide, this, &GlobalMsgMgr::OnWeakHintHide);
  123. weakWidget->setWindowFlag(Qt::ToolTip);
  124. weakWidget->setParent(m_pRootWidget);
  125. int x = (m_pRootWidget->width()-weakWidget->width())/2;
  126. int offset = m_listWeakHints.count()*(g_nSpacing + g_nWeakHintHeight);
  127. weakWidget->move(x, offset - g_nFlyDistance + g_nPaddingTop);
  128. weakWidget->show();
  129. m_listWeakHints.append(weakWidget);
  130. if(!m_timerUpdate.isActive()) m_timerUpdate.start(g_nUpdateInterval);
  131. }
  132. void GlobalMsgMgr::Popup(const QString &msg, QWidget *parentWidget, GlobalMsgWidget::HintMode mode)
  133. {
  134. //动画思路:单个消息窗, 飞入飞出+淡入淡出; 多个消息窗, 单个本身动画不变, 多个组成队列
  135. //某个消息窗开始飞出时, 它后面的所有消息窗同时上移
  136. //新消息窗飞入时, 从头部位置飞入; 头部位置随着[新消息飞入]和[所有窗口同时上移]而改变, [新消息飞入]则加一个单位, [所有窗口同时上移]则减一个单位
  137. //单个消息窗的[飞入飞出+淡入淡出]用paintevent实现; [所有窗口同时上移]在OnUpdate实现
  138. if(parentWidget == nullptr) return;
  139. GlobalMsgWidget *weakWidget = new GlobalMsgWidget(msg, mode);
  140. connect(weakWidget, &GlobalMsgWidget::sig_Hide, this, &GlobalMsgMgr::OnWeakHintHide);
  141. weakWidget->setWindowFlag(Qt::ToolTip);
  142. weakWidget->setParent(parentWidget);
  143. int x = (parentWidget->width()-weakWidget->width())/2;
  144. int offset = m_listWeakHints.count()*(g_nSpacing + g_nWeakHintHeight);
  145. weakWidget->move(x, offset - g_nFlyDistance + g_nPaddingTop);
  146. weakWidget->show();
  147. m_listWeakHints.append(weakWidget);
  148. if(!m_timerUpdate.isActive()) m_timerUpdate.start(g_nUpdateInterval);
  149. }
  150. void GlobalMsgMgr::Clear(QWidget *parentWidget)
  151. {
  152. for(auto weakHint=m_listWeakHints.begin();weakHint!=m_listWeakHints.end();){
  153. if((*weakHint)->parent() == parentWidget)
  154. weakHint = m_listWeakHints.erase(weakHint);
  155. else
  156. ++weakHint;
  157. }
  158. }
  159. void GlobalMsgMgr::OnUpdate()
  160. {
  161. for(GlobalMsgWidget* weakHint: m_listWeakHints)
  162. {
  163. int offset = m_listWeakHints.indexOf(weakHint)*(g_nSpacing + g_nWeakHintHeight);
  164. int targetPosY = offset - g_nFlyDistance + g_nPaddingTop;
  165. QPoint curPos = weakHint->pos();
  166. if(curPos.y() == targetPosY) continue;
  167. if(targetPosY > curPos.y())
  168. {
  169. int newPosY = qMin(curPos.y()+g_nSpeed, targetPosY);
  170. QPoint newPos = QPoint(curPos.x(), newPosY);
  171. weakHint->move(newPos);
  172. }
  173. if(targetPosY < curPos.y())
  174. {
  175. int newPosY = qMax(curPos.y()-g_nSpeed, targetPosY);
  176. QPoint newPos = QPoint(curPos.x(), newPosY);
  177. weakHint->move(newPos);
  178. }
  179. }
  180. }
  181. void GlobalMsgMgr::OnWeakHintHide(GlobalMsgWidget* pWeakHint)
  182. {
  183. if(m_listWeakHints.contains(pWeakHint)) m_listWeakHints.removeOne(pWeakHint);
  184. }