QT实现带动态弹出动画的自定义通知提示框
资源内容介绍
Qt中经常会用到提示框,用于交互操作!QMessageBox是被大多数人用到的,用起来是很方便,但是控件类型、大小、布局、样式、往往不是开发者想要的。本实例实现的Notification控件,是一种悬浮在角落的通知提醒框 #include "notification.h"#include <QPainter>#include <QStyleOption>#include <QGraphicsDropShadowEffect>#include <QScrollBar>#include <QPropertyAnimation>#include <QApplication>#include <QScreen>static int nAppearTime = 200; // 出现的时间200msstatic int nDisappearTime = 200; // 消失的时间200msNotification::Notification(QObject *parent) : QObject(parent){ QWidget* pWidget = qobject_cast<QWidget*>(parent); if(pWidget == nullptr) throw std::runtime_error("parent of notification error!"); m_size = pWidget->size(); m_vecItem.reserve(30);}Notification::~Notification(){}void Notification::Push(NotifyType type, NotifyPosition pos, QString title, QString content, int nLive){ std::lock_guard<std::mutex> lck(m_vecMtx); NotificationItem* pItem = new NotificationItem(qobject_cast<QWidget*>(parent()), type, pos, title, content, nLive); connect(pItem, &NotificationItem::itemRemoved, this, &Notification::itemRemoved); int currentHeight = 0; int currentX = 0; if(pos == NotifyPosition::Pos_Top_Right) { currentX = m_size.width(); currentHeight = nMargin; } else if(pos == NotifyPosition::Pos_Top_Left) { currentX = -pItem->width(); currentHeight = nMargin; } else if(pos == NotifyPosition::Pos_Bottom_Left) { currentX = -pItem->width(); currentHeight = m_size.height() - nMargin - pItem->height(); } else { currentX = m_size.width(); currentHeight = m_size.height() - nMargin - pItem->height(); } for_each(m_vecItem.begin(), m_vecItem.end(), [&](NotificationItem* item) { if(item->GetPosType() == pos) { if(pos == NotifyPosition::Pos_Top_Right) { currentHeight += (item->height() + nMargin); } else if(pos == NotifyPosition::Pos_Top_Left) { currentHeight += (item->height() + nMargin); } else if(pos == NotifyPosition::Pos_Bottom_Left) { currentHeight -= (item->height() + nMargin); } else { currentHeight -= (item->height() + nMargin); } } }); pItem->move(currentX, currentHeight); m_vecItem.emplace_back(pItem); pItem->Show();}void Notification::itemRemoved(NotificationItem *pRemoved){ std::unique_lock<std::mutex> lck(m_vecMtx); int currentY = 0; bool bFirst = true; NotifyPosition pos = pRemoved->GetPosType(); for(auto itr = m_vecItem.begin(); itr != m_vecItem.end();) { if(*itr == pRemoved) { m_vecItem.erase(itr); break; } else ++itr; } for_each(m_vecItem.begin(), m_vecItem.end(), [&, pos, bFirst, currentY](NotificationItem* item) mutable { if(item->GetPosType() == pos) { if(bFirst) { if(pos == NotifyPosition::Pos_Top_Right) { currentY = nMargin; } else if(pos == NotifyPosition::Pos_Top_Left) { currentY = nMargin; } else if(pos == NotifyPosition::Pos_Bottom_Left) { currentY = m_size.height() - nMargin - item->height(); } else { currentY = m_size.height() - nMargin - item->height(); } bFirst = false; } else { if(item->IsAppearEnd()) { if(pos == NotifyPosition::Pos_Top_Right) { currentY += (item->height() + nMargin); } else if(pos == NotifyPosition::Pos_Top_Left) { currentY += (item->height() + nMargin); } else if(pos == NotifyPosition::Pos_Bottom_Left) { currentY -= (item->height() + nMargin); } else { currentY -= (item->height() + nMargin); } } } if(item->IsAppearEnd()) { QPropertyAnimation* pAnimation1 = new QPropertyAnimation(item, "geometry", this); pAnimation1->setDuration(nDisappearTime); pAnimation1->setStartValue(QRect(item->pos().x(), item->pos().y(), item->width(), item->height())); pAnimation1->setEndValue(QRect(item->pos().x(), currentY, item->width(), item->height())); pAnimation1->start(QAbstractAnimation::DeletionPolicy::DeleteWhenStopped); } } });}///////////////////////////////////////////////////////////////NotificationItem::NotificationItem(QWidget *parent, NotifyType type, NotifyPosition pos, QString title, QString content, int nLife) : QWidget(parent), m_enPos(pos), m_bAppearEnd(false){ setObjectName(QStringLiteral("notification_item")); QLabel* pTitle = new QLabel(title, this); pTitle->setObjectName(QStringLiteral("label_title")); NotificationLabel* pContent = new NotificationLabel(this, nFixedWidth - 10, content); QFont font; font.setPointSize(11); font.setFamily(QStringLiteral("Microsoft Yahei")); pContent->setFont(font); QPushButton* pClose = new QPushButton(this); pClose->setFixedSize(16, 16); pClose->setObjectName(QStringLiteral("btn_close")); pClose->setCursor(QCursor(Qt::PointingHandCursor)); setStyleSheet(QStringLiteral("QWidget#notification_item{border:none;border-radius:8px;background-color:white;}" "QLabel#label_title{border:none;background-color:white;font-family:Microsoft Yahei;font-size:20px;font-weight:700;color:#303133;}" "QPushButton#btn_close{border:none;background-color:white;background-position:center;border-image:url(:/skin/notification_close.png);}" "QPushButton:hover#btn_close{border-image:url(:/skin/notification_close_hover.png);}")); // 标题设置 pTitle->setAlignment(Qt::AlignLeft | Qt::AlignTop); QFontMetrics fontWidth(pTitle->font()); QString elideNote = fontWidth.elidedText(pTitle->text(), Qt::ElideRight, 120); pTitle->setText(elideNote); pTitle->setToolTip(title); pTitle->adjustSize(); // 内容设置 pContent->Adjust(); // 布局 if(type != NotifyType::Notify_Type_None) { QLabel* pIcon = new QLabel(this); pIcon->setStyleSheet(QStringLiteral("QLabel{border:none;background-color:white;}")); if(type == NotifyType::Notify_Type_Success) { pIcon->setPixmap(QPixmap(":/skin/type_success.png")); } else if(type == NotifyType::Notify_Type_Error) { pIcon->setPixmap(QPixmap(":/s