• 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()
    {
        //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);
    }
  • 相关阅读:
    我的第一颗二叉链树的笔记
    我的kmp笔记
    链表操作笔记
    POJ 2559 Largest Rectangle in a Histogram (单调栈)
    牛客网 wyh的数列(循环节+快速幂)
    数论知识点
    牛客网 n的约数 (唯一分解定理)
    POJ 3783 Balls (DP)
    关于unordered_map和map
    2018年四校联合周赛-第二场 B.异或和问题(二维树状数组)
  • 原文地址:https://www.cnblogs.com/suxia/p/14261677.html
Copyright © 2020-2023  润新知