廢話不多說,直接上代碼和效果圖
兩種切換效果(滑動切換,淡入淡出切換)
#include <QWidget> #include <QButtonGroup> #include <vector> #include <QPropertyAnimation> #include <QVBoxLayout> #include <QHBoxLayout> #include <QLabel> #include <QPushButton> #include <windows.h> #include <QParallelAnimationGroup> #include <QTimer> #include <QGraphicsOpacityEffect> #include <QMouseEvent> #include <QDesktopServices> //圖片代表的ID,用完一次自加1 static int g_imageid = 0; enum SCROLL_MODE { FADE,//消失,漸變特效 SLIDE//從右向左滑動 }; struct ScrollImage { int iId; //ID代表着圖片的標志,從窗口開始到結束始終不變 QString qsImagePath;//圖片對應的地址,一般為qrc資源文件的url QString qsUrl;//點擊圖片時的跳轉鏈接,可以為NULL; }; class ScrollImageWidget : public QWidget { Q_OBJECT public: ScrollImageWidget(QWidget *parent=NULL); ~ScrollImageWidget(); public: //添加圖片,圖片可以指定點擊時跳轉的鏈接。函數返回圖片加入后其對應的ID,此ID從當前窗口開始到結束始終不變 int addImage(QString imagePath, QString url = NULL); //開始滾動,可指定滾動效果為消失還是滑動,從第一張圖片開始滾動 void startScroll(int scrollmode=SCROLL_MODE::FADE); //切換圖片到指定索引位置 void switchToImg(int index); //設置按鈕尺寸 void setButtonSize(int diameter); //設置圖片切換的動畫時間 void setSwitchTime(int switchtime); //設置每張圖片等待的時間 void setWaitingTime(int waitingtime); private: //初始化界面布局 void initUi(); //啟動一系列定時器 void startTimer(); //獲取系統縮放比 double getDPI(); protected: //鼠標按壓響應 virtual void mousePressEvent(QMouseEvent *event); //鼠標移動響應 virtual void mouseMoveEvent(QMouseEvent * event); //鼠標釋放響應 virtual void mouseReleaseEvent(QMouseEvent *event); //界面尺寸變化響應 void resizeEvent(QResizeEvent *event); public Q_SLOTS: void OnTimerSwitch(); private: //頂層圖片所在的QLabel QLabel* m_topLabel; //底層層圖片所在的QLabel QLabel* m_bottomLabel; //頁面主布局 QVBoxLayout* m_vMainLayout; //按鈕對應的布局 QHBoxLayout* m_hButtonLayout; //系統縮放比 double m_dpi; //當前滾動動畫類型 int m_currentMode; //當前顯示的圖片的索引 int m_currentindex; //按鈕對應的集合 QButtonGroup* m_pButtonGroup; //圖片資源對應的數組,后續可擴展方法眾多 std::vector<ScrollImage *> m_imageArray; //按鈕對應的數組 std::vector<QPushButton *> m_buttonArray; //切換圖片 QPixmap m_currentPixmap; QPixmap m_nextPixmap; //每張圖片等待的時間對應的定時器 QTimer* m_timerwait; //圖片切換的時候對應的定時器 QTimer* m_timerswitch; //淡入淡出特效切換圖片所用的特效 QGraphicsOpacityEffect* m_opacityeffect; //鼠標按壓標記位 bool m_bMousePress; //圖片與圖片之間間隔時間,不包括圖片切換時間 int m_waitingtime; //圖片之間切換的動畫時間 int m_switchtime; //按鈕的尺寸 int m_buttonsize; //頂層圖片當前的透明度,淡入淡出特效所用 float m_imageopacity = 1; //頂層圖片平移的距離,滑動特效所用 int m_imagepos = 0; };
#include "ScrollImageWidget.h" #define BUTTON_SPACING 10 ScrollImageWidget::ScrollImageWidget(QWidget *parent) : QWidget(parent) { //初始化內部元素 m_bMousePress = false; m_dpi = getDPI(); m_waitingtime = 5000; m_switchtime = 1000; m_buttonsize = 30; //初始化頁面布局 initUi(); //初始化透明度特效 m_opacityeffect = new QGraphicsOpacityEffect(this); m_opacityeffect->setOpacity(m_imageopacity); //初始化定時器,並綁定對應槽函數 m_timerwait = new QTimer(this); m_timerswitch = new QTimer(this); m_timerwait->setSingleShot(true); m_timerswitch->setSingleShot(false); connect(m_timerswitch, SIGNAL(timeout()), this, SLOT(OnTimerSwitch())); connect(m_timerwait, &QTimer::timeout, this, [=](){m_timerswitch->start(100); }); } ScrollImageWidget::~ScrollImageWidget() { //QObject及其派生類的對象,其parent析構時會析構該對象,所以不做處理 //析構存儲圖片信息的容器里元素 for (std::vector<ScrollImage*>::iterator s = m_imageArray.begin(); s != m_imageArray.end(); ++s){ delete *s; } } int ScrollImageWidget::addImage(QString imagePath, QString url /*= NULL*/) { //將圖片元素添加到圖片數組中 ScrollImage* img = new ScrollImage; img->iId = g_imageid; g_imageid++; img->qsImagePath = imagePath; img->qsUrl = url; m_imageArray.push_back(img); //初始化按鈕並將其添加到按鈕組和布局中 QPushButton* btn = new QPushButton(this); btn->setFixedSize(QSize(m_buttonsize, m_buttonsize)); btn->setCheckable(true); btn->setStyleSheet("QPushButton{border-image:url(:/ScrollImage/noselect.png);}\ QPushButton:checked{border-image:url(:/ScrollImage/selected.png);}"); m_buttonArray.push_back(btn); m_pButtonGroup->addButton(btn, m_buttonArray.size() - 1); m_hButtonLayout->addWidget(btn); //設置主布局,每添加一個按鈕,鍵盤布局的大小需要擴大 m_vMainLayout->setContentsMargins((this->width() - m_imageArray.size()*(20 + m_buttonsize)*m_dpi) / 2, this->height() - (BUTTON_SPACING * 2 + m_buttonsize)*m_dpi, (this->width() - m_imageArray.size()*(BUTTON_SPACING * 2 + m_buttonsize)*m_dpi) / 2, BUTTON_SPACING*m_dpi); return img->iId; } void ScrollImageWidget::startScroll(int scrollmode/*=SCROLL_MODE::FADE*/) { m_currentMode = scrollmode; //滾動之前判定目前需要展示的圖片數目,0張和1張都不需要啟動定時器 if (m_imageArray.size() == 0) { QPixmap img(QString(":/ScrollImage/default.png")); m_topLabel->setPixmap(img); } else if (m_imageArray.size() == 1) { QPixmap img(m_imageArray[0]->qsImagePath); m_topLabel->setPixmap(img); m_pButtonGroup->button(0)->setChecked(true); } else { QPixmap img(m_imageArray[0]->qsImagePath); QPixmap nextimg(m_imageArray[1]->qsImagePath); m_currentindex = 0; m_pButtonGroup->button(m_currentindex)->setChecked(true); m_topLabel->setPixmap(img); m_bottomLabel->setPixmap(nextimg); this->startTimer(); } } void ScrollImageWidget::switchToImg(int index) { //改變當前圖片索引 m_currentindex=index; //加載頂層Label和底層Label所需要顯示的圖片 QPixmap currentimg(m_imageArray[m_currentindex]->qsImagePath); QPixmap nextimg; if (m_currentindex + 1 >= m_imageArray.size()) { nextimg.load(m_imageArray[0]->qsImagePath); } else { nextimg.load(m_imageArray[m_currentindex + 1]->qsImagePath); } m_topLabel->setPixmap(currentimg); m_bottomLabel->setPixmap(nextimg); m_pButtonGroup->button(m_currentindex)->setChecked(true); //啟動一系列定時器 this->startTimer(); } void ScrollImageWidget::setButtonSize(int diameter) { m_buttonsize = diameter; } void ScrollImageWidget::setSwitchTime(int switchtime) { m_switchtime = switchtime; } void ScrollImageWidget::setWaitingTime(int waitingtime) { m_waitingtime = waitingtime; } void ScrollImageWidget::initUi() { //初始化圖片 m_bottomLabel = new QLabel(this); m_bottomLabel->setScaledContents(true); m_topLabel = new QLabel(m_bottomLabel); m_topLabel->setScaledContents(true); //初始化布局 m_vMainLayout = new QVBoxLayout(this); this->setLayout(m_vMainLayout); m_hButtonLayout = new QHBoxLayout(this); m_hButtonLayout->setContentsMargins(BUTTON_SPACING*m_dpi, 0, BUTTON_SPACING*m_dpi, 0); m_vMainLayout->addLayout(m_hButtonLayout); //初始化按鈕集合 m_pButtonGroup = new QButtonGroup(this); connect(m_pButtonGroup, static_cast<void (QButtonGroup::*)(int)>(&QButtonGroup::buttonClicked), this, &ScrollImageWidget::switchToImg); } void ScrollImageWidget::startTimer() { //開始定時器時伴隨着停止定時器 m_timerswitch->stop(); if (m_currentMode == SCROLL_MODE::FADE) { //圖片透明度重置為100% m_imageopacity = 1; m_opacityeffect->setOpacity(m_imageopacity); m_topLabel->setGraphicsEffect(m_opacityeffect); } else if (m_currentMode == SCROLL_MODE::SLIDE) { //標記置0 m_imagepos = 0; //圖片移位到初始化位置 m_topLabel->move(0, 0); } //按照用戶指定等待時間啟動定時器 m_timerwait->start(m_waitingtime); } double ScrollImageWidget::getDPI() { double dDpi = 1; //提取桌面的DC句柄 HDC desktopDc = GetDC(NULL); //獲取本地分辨率 float horizontalDPI = GetDeviceCaps(desktopDc, LOGPIXELSX); float verticalDPI = GetDeviceCaps(desktopDc, LOGPIXELSY); //釋放句柄 ReleaseDC(NULL, desktopDc); //計算縮放比 int dpi = (horizontalDPI + verticalDPI) / 2; dDpi = 1 + ((dpi - 96) / 24)*0.25; if (dDpi < 1) { dDpi = 1; } return dDpi; } void ScrollImageWidget::OnTimerSwitch() { if (m_currentMode == SCROLL_MODE::FADE) { //計算下一個定時器周期內圖片透明度 m_imageopacity = m_imageopacity - 100.0 / m_switchtime; //透明度小於0,意味着圖片需要切換了 if (m_imageopacity <= 0) { m_currentindex++; //加載切換后頂層Label和底層Label對應的圖片 if (m_currentindex >= m_imageArray.size()) { m_currentindex = 0; } QPixmap img(m_imageArray[m_currentindex]->qsImagePath); QPixmap nextimg; if (m_currentindex + 1 >= m_imageArray.size()) { nextimg.load(m_imageArray[0]->qsImagePath); } else { nextimg.load(m_imageArray[m_currentindex + 1]->qsImagePath); } m_topLabel->setPixmap(img); m_bottomLabel->setPixmap(nextimg); m_pButtonGroup->button(m_currentindex)->setChecked(true); //啟動一系列定時器 this->startTimer(); } else { m_opacityeffect->setOpacity(m_imageopacity); m_topLabel->setGraphicsEffect(m_opacityeffect); } } else if (m_currentMode == SCROLL_MODE::SLIDE) { m_imagepos += (m_topLabel->width())/(m_switchtime / 100); if (m_imagepos >= m_topLabel->width()) { m_imagepos = 0; m_currentindex++; //加載切換后頂層Label和底層Label對應的圖片 if (m_currentindex >= m_imageArray.size()) { m_currentindex = 0; } QPixmap img(m_imageArray[m_currentindex]->qsImagePath); QPixmap nextimg; if (m_currentindex + 1 >= m_imageArray.size()) { nextimg.load(m_imageArray[0]->qsImagePath); } else { nextimg.load(m_imageArray[m_currentindex + 1]->qsImagePath); } m_topLabel->setPixmap(img); m_bottomLabel->setPixmap(nextimg); m_pButtonGroup->button(m_currentindex)->setChecked(true); //啟動一系列定時器 this->startTimer(); } else { m_topLabel->move(-m_imagepos, 0); } } } void ScrollImageWidget::mousePressEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton) { //鼠標左鍵按壓,並且鼠標位置不在button區域,激活鼠標按壓標記 if (!this->m_hButtonLayout->geometry().contains(this->mapFromGlobal(QCursor::pos()))) { m_bMousePress = true; } } return QWidget::mousePressEvent(event); } void ScrollImageWidget::mouseMoveEvent(QMouseEvent * event) { return QWidget::mouseMoveEvent(event); } void ScrollImageWidget::mouseReleaseEvent(QMouseEvent *event) { if (m_bMousePress) { //鼠標釋放時,當前圖片的連接不為空,則打開對應鏈接 if (m_imageArray[m_currentindex]->qsUrl != NULL) { QDesktopServices::openUrl(m_imageArray[m_currentindex]->qsUrl); } } m_bMousePress = false; return QWidget::mouseReleaseEvent(event); } void ScrollImageWidget::resizeEvent(QResizeEvent *event) { //底層圖片自適應窗口 m_bottomLabel->setGeometry(0, 0, this->width(), this->height()); //頂層圖片自適應底層圖片 m_topLabel->setGeometry(0, 0, this->width(), this->height()); //主布局適應窗口 m_vMainLayout->setGeometry(QRect(0, 0, this->width(), this->height())); //設置主布局 m_vMainLayout->setContentsMargins((this->width() - m_imageArray.size()*(20 + m_buttonsize)*m_dpi) / 2, this->height() - (BUTTON_SPACING * 2 + m_buttonsize)*m_dpi, (this->width() - m_imageArray.size()*(BUTTON_SPACING * 2 + m_buttonsize)*m_dpi) / 2, BUTTON_SPACING*m_dpi); return QWidget::resizeEvent(event); }