1. 程式人生 > 實用技巧 >QT實現滾動輪播顯示圖片(支援兩種滾動模式切換,間隔時間設定,按鈕尺寸設定,縮放比自適應)

QT實現滾動輪播顯示圖片(支援兩種滾動模式切換,間隔時間設定,按鈕尺寸設定,縮放比自適應)

廢話不多說,直接上程式碼和效果圖

兩種切換效果

#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()
{
}

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();
    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();
    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_waitingtime / 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);
}