zoukankan      html  css  js  c++  java
  • Qt编写自定义控件23-广告轮播控件

    一、前言

    广告轮播这个控件做的比较早,是很早以前定制一个电信客户端时候用到的,该客户端需要在首页展示轮播预先设定好的图片,图片的路径可以自由设定,然后轮播的间隔速度可以自由控制,同时该控件还需要提供两种指示器的风格,一种是迷你型的样式,一种是数字型的样式。
    本控件很早就做好了,由于当时的QPainter功力不足,还不是很熟悉QPainter,采用的是效率比较低的直接用现有控件堆积而成,比如指示器采用的QLabel,用样式表来控制对应的形状,指示器所在的底部放一个widget,采用左右布局,然后右侧放一个弹簧把指示器label全部顶在左边,至于图片的显示,采用的是样式表中的border-image来设置,开个定时器,到了时间则设置成不同的border-image即可。这种方法虽然效率低了点,但是初学者很容易理解接收,甚至可以做出更多的效果,只要项目对CPU要求不高,也不失为一种还行的办法。

    二、实现的功能

    • 1:可设置显示的图像
    • 2:可添加多个广告
    • 3:可设置指示器样式 迷你型样式 数字型样式
    • 4:可设置指示器大小
    • 5:可设置切换间隔

    三、效果图



    四、头文件代码

    #ifndef ADSWIDGET_H
    #define ADSWIDGET_H
    
    /**
     * 广告轮播控件 作者:feiyangqingyun(QQ:517216493) 2016-12-22
     * 1:可设置显示的图像
     * 2:可添加多个广告
     * 3:可设置指示器样式 迷你型样式 数字型样式
     * 4:可设置指示器大小
     * 5:可设置切换间隔
     */
    
    #include <QWidget>
    
    class QLabel;
    
    #ifdef quc
    #if (QT_VERSION < QT_VERSION_CHECK(5,7,0))
    #include <QtDesigner/QDesignerExportWidget>
    #else
    #include <QtUiPlugin/QDesignerExportWidget>
    #endif
    
    class QDESIGNER_WIDGET_EXPORT AdsWidget : public QWidget
    #else
    class AdsWidget : public QWidget
    #endif
    
    {
        Q_OBJECT
        Q_ENUMS(BannerStyle)
    
        Q_PROPERTY(int interval READ getInterval WRITE setInterval)
        Q_PROPERTY(QSize bannerFixedSize READ getBannerFixedSize WRITE setBannerFixedSize)    
        Q_PROPERTY(QString imageNames READ getImageNames WRITE setImageNames)
        Q_PROPERTY(BannerStyle bannerStyle READ getBannerStyle WRITE setBannerStyle)
    
    public:
        enum BannerStyle {
            BannerStyle_Min = 0,    //迷你型样式
            BannerStyle_Num = 1     //数字型样式
        };
    
        explicit AdsWidget(QWidget *parent = 0);
        ~AdsWidget();
    
    protected:
        bool eventFilter(QObject *obj, QEvent *event);
    
    private:
        int interval;               //自动切换间隔
        QSize bannerFixedSize;      //导航指示器固定尺寸
        BannerStyle bannerStyle;    //导航指示器样式
        QString imageNames;         //导航图片集合字符串
    
        int currentIndex;           //当前显示的广告对应索引
        QTimer *timer;              //定时器轮播广告
        QList<QLabel *> labs;       //导航标签链表
        QList<QString> names;       //导航图片链表
    
        QWidget *widgetBg;          //存放广告图片的容器
        QWidget *widgetBanner;      //存放导航指示器的容器
    
    private slots:
        void initWidget();
        void initForm();
        void changedAds();
        void changedAds(QLabel *lab);
    
    public:
        int getInterval()               const;
        QSize getBannerFixedSize()      const;
        BannerStyle getBannerStyle()    const;
        QString getImageNames()         const;
    
        QSize sizeHint()                const;
        QSize minimumSizeHint()         const;
    
    public Q_SLOTS:
        void setInterval(int interval);
        void setBannerFixedSize(const QSize &bannerFixedSize);
        void setBannerStyle(const BannerStyle &bannerStyle);
        void setImageNames(const QString &imageNames);
    };
    
    #endif // ADSWIDGET_H
    
    
    

    五、完整代码

    #pragma execution_character_set("utf-8")
    
    #include "adswidget.h"
    #include "qevent.h"
    #include "qlabel.h"
    #include "qlayout.h"
    #include "qtimer.h"
    #include "qdebug.h"
    
    AdsWidget::AdsWidget(QWidget *parent) : QWidget(parent)
    {
        this->initWidget();
        this->initForm();
    }
    
    AdsWidget::~AdsWidget()
    {
        if (timer->isActive()) {
            timer->stop();
        }
    }
    
    bool AdsWidget::eventFilter(QObject *obj, QEvent *event)
    {
        if (event->type() == QEvent::MouseButtonPress) {
            if (obj->inherits("QLabel")) {
                //先停止定时器,防止按下切换的时候短时间内再度切换
                timer->stop();
                changedAds((QLabel *)obj);
                timer->start(interval);
            }
        }
    
        return QWidget::eventFilter(obj, event);
    }
    
    void AdsWidget::initWidget()
    {
        QVBoxLayout *verticalLayout = new QVBoxLayout(this);
        verticalLayout->setSpacing(0);
        verticalLayout->setContentsMargins(0, 0, 0, 0);
    
        widgetBg = new QWidget(this);
        widgetBg->setObjectName(QString::fromUtf8("widgetBg"));
    
        QGridLayout *gridLayout = new QGridLayout(widgetBg);
        gridLayout->setSpacing(0);
        gridLayout->setContentsMargins(0, 0, 0, 0);
    
        QSpacerItem *verticalSpacer = new QSpacerItem(10, 10, QSizePolicy::Minimum, QSizePolicy::Expanding);
        gridLayout->addItem(verticalSpacer, 0, 0, 1, 1);
    
        widgetBanner = new QWidget(widgetBg);
        widgetBanner->setObjectName(QString::fromUtf8("widgetBanner"));
    
        QHBoxLayout *horizontalLayout = new QHBoxLayout(widgetBanner);
        horizontalLayout->setSpacing(3);
        gridLayout->addWidget(widgetBanner, 1, 0, 1, 1);
    
        QSpacerItem *horizontalSpacer = new QSpacerItem(10, 10, QSizePolicy::Expanding, QSizePolicy::Minimum);
        gridLayout->addItem(horizontalSpacer, 1, 1, 1, 1);
        verticalLayout->addWidget(widgetBg);
    }
    
    void AdsWidget::initForm()
    {
        interval = 3000;
        bannerFixedSize = QSize(20, 20);
        bannerStyle = BannerStyle_Num;
        imageNames.clear();
    
        currentIndex = 0;
        timer = new QTimer(this);
        timer->setInterval(interval);
        connect(timer, SIGNAL(timeout()), this, SLOT(changedAds()));
        timer->start();
    }
    
    void AdsWidget::changedAds()
    {
        if (names.count() == 0) {
            return;
        }
    
        if (currentIndex < names.count() - 1) {
            currentIndex++;
        } else {
            currentIndex = 0;
        }
    
        changedAds(labs.at(currentIndex));
    }
    
    void AdsWidget::changedAds(QLabel *lab)
    {
        //这里采用样式改变背景颜色的方式,也可以改成贴背景图的方式
        QString qss;
        QString qssCurrent;
    
        if (bannerStyle == BannerStyle_Min) {
            qss = "QLabel{background:#4380A8;}";
            qssCurrent = "QLabel{background:#084279;}";
        } else if (bannerStyle == BannerStyle_Num) {
            qss = "QLabel{color:#FFFFFF;background:rgba(0,0,0,40);}";
            qssCurrent = "QLabel{color:#FFFFFF;background:#0C7FC8;}";
        }
    
        //将当前广告指示器突出显示
        foreach (QLabel *currentLab, labs) {
            if (currentLab == lab) {
                currentLab->setStyleSheet(qssCurrent);
            } else {
                currentLab->setStyleSheet(qss);
            }
        }
    
        //更新索引和图片
        currentIndex = labs.indexOf(lab);
        widgetBg->setStyleSheet(QString("QWidget#widgetBg{border-image:url(%1);}").arg(names.at(currentIndex)));
    }
    
    int AdsWidget::getInterval() const
    {
        return this->interval;
    }
    
    QSize AdsWidget::getBannerFixedSize() const
    {
        return this->bannerFixedSize;
    }
    
    AdsWidget::BannerStyle AdsWidget::getBannerStyle() const
    {
        return this->bannerStyle;
    }
    
    QString AdsWidget::getImageNames() const
    {
        return this->imageNames;
    }
    
    QSize AdsWidget::sizeHint() const
    {
        return QSize(200, 150);
    }
    
    QSize AdsWidget::minimumSizeHint() const
    {
        return QSize(20, 15);
    }
    
    void AdsWidget::setInterval(int interval)
    {
        if (this->interval != interval) {
            this->interval = interval;
            timer->setInterval(interval);
        }
    }
    
    void AdsWidget::setBannerFixedSize(const QSize &bannerFixedSize)
    {
        if (this->bannerFixedSize != bannerFixedSize) {
            this->bannerFixedSize = bannerFixedSize;
            foreach (QLabel *lab, labs) {
                lab->setFixedSize(bannerFixedSize);
            }
        }
    }
    
    void AdsWidget::setBannerStyle(const AdsWidget::BannerStyle &bannerStyle)
    {
        if (this->bannerStyle != bannerStyle) {
            this->bannerStyle = bannerStyle;
    
            foreach (QLabel *lab, labs) {
                if (bannerStyle == BannerStyle_Min) {
                    lab->setText("");
                } else if (bannerStyle == BannerStyle_Num) {
                    lab->setText(lab->text());
                }
            }
        }
    }
    
    void AdsWidget::setImageNames(const QString &imageNames)
    {
        if (this->imageNames != imageNames) {
            this->imageNames = imageNames;
    
            //先清空原有所有指示器
            qDeleteAll(labs);
            labs.clear();
    
            //根据图片链表自动生成导航指示器和图片链表
            names = this->imageNames.split(";");
            for (int i = 0; i < names.count(); i++) {
                QLabel *lab = new QLabel;
                widgetBanner->layout()->addWidget(lab);
                lab->setFixedSize(bannerFixedSize);
                lab->setAlignment(Qt::AlignCenter);
                lab->installEventFilter(this);
                if (bannerStyle == BannerStyle_Num) {
                    lab->setText(QString::number(i + 1));
                }
    
                labs.append(lab);
            }
    
            //立即显示第一张
            changedAds();
        }
    }
    
    
    
    

    六、控件介绍

    1. 超过146个精美控件,涵盖了各种仪表盘、进度条、进度球、指南针、曲线图、标尺、温度计、导航条、导航栏,flatui、高亮按钮、滑动选择器、农历等。远超qwt集成的控件数量。
    2. 每个类都可以独立成一个单独的控件,零耦合,每个控件一个头文件和一个实现文件,不依赖其他文件,方便单个控件以源码形式集成到项目中,较少代码量。qwt的控件类环环相扣,高度耦合,想要使用其中一个控件,必须包含所有的代码。
    3. 全部纯Qt编写,QWidget+QPainter绘制,支持Qt4.6到Qt5.12的任何Qt版本,支持mingw、msvc、gcc等编译器,不乱码,可直接集成到Qt Creator中,和自带的控件一样使用,大部分效果只要设置几个属性即可,极为方便。
    4. 每个控件都有一个对应的单独的包含该控件源码的DEMO,方便参考使用。同时还提供一个所有控件使用的集成的DEMO。
    5. 每个控件的源代码都有详细中文注释,都按照统一设计规范编写,方便学习自定义控件的编写。
    6. 每个控件默认配色和demo对应的配色都非常精美。
    7. 超过130个可见控件,6个不可见控件。
    8. 部分控件提供多种样式风格选择,多种指示器样式选择。
    9. 所有控件自适应窗体拉伸变化。
    10. 集成自定义控件属性设计器,支持拖曳设计,所见即所得,支持导入导出xml格式。
    11. 自带activex控件demo,所有控件可以直接运行在ie浏览器中。
    12. 集成fontawesome图形字体+阿里巴巴iconfont收藏的几百个图形字体,享受图形字体带来的乐趣。
    13. 所有控件最后生成一个dll动态库文件,可以直接集成到qtcreator中拖曳设计使用。

    七、SDK下载

    • SDK下载链接:https://pan.baidu.com/s/1tD9v1YPfE2fgYoK6lqUr1Q 提取码:lyhk
    • 自定义控件+属性设计器欣赏:https://pan.baidu.com/s/1l6L3rKSiLu_uYi7lnL3ibQ 提取码:tmvl
    • 下载链接中包含了各个版本的动态库文件,所有控件的头文件,使用demo。
    • 自定义控件插件开放动态库dll使用(永久免费),无任何后门和限制,请放心使用。
    • 目前已提供26个版本的dll,其中包括了qt5.12.3 msvc2017 32+64 mingw 32+64 的。
    • 不定期增加控件和完善控件,不定期更新SDK,欢迎各位提出建议,谢谢!
    • widget版本(QQ:517216493)qml版本(QQ:373955953)三峰驼(QQ:278969898)。
    • 涛哥的知乎专栏 Qt进阶之路 https://zhuanlan.zhihu.com/TaoQt
    • 欢迎关注微信公众号【高效程序员】,C++/Python、学习方法、写作技巧、热门技术、职场发展等内容,干货多多,福利多多!
  • 相关阅读:
    10-18 noip提高组模拟赛(codecomb)T2贪心
    vj1011:记忆化搜索
    vj1010:高精乘+细心模拟
    10-18 noip提高组模拟赛(codecomb)T1倍增[未填]
    CODEFORCES ROUND #273 DIV2
    Unkown2
    2014.first[未填]
    Unknown
    历年noip复赛试题整合
    快速幂(模板)
  • 原文地址:https://www.cnblogs.com/feiyangqingyun/p/10987726.html
Copyright © 2011-2022 走看看