Qt編寫自定義控件23-廣告輪播控件

1、前言

廣告輪播這個控件作的比較早,是很早之前定製一個電信客戶端時候用到的,該客戶端須要在首頁展現輪播預先設定好的圖片,圖片的路徑能夠自由設定,而後輪播的間隔速度能夠自由控制,同時該控件還須要提供兩種指示器的風格,一種是迷你型的樣式,一種是數字型的樣式。
本控件很早就作好了,因爲當時的QPainter功力不足,還不是很熟悉QPainter,採用的是效率比較低的直接用現有控件堆積而成,好比指示器採用的QLabel,用樣式表來控制對應的形狀,指示器所在的底部放一個widget,採用左右佈局,而後右側放一個彈簧把指示器label所有頂在左邊,至於圖片的顯示,採用的是樣式表中的border-image來設置,開個定時器,到了時間則設置成不一樣的border-image便可。這種方法雖然效率低了點,可是初學者很容易理解接收,甚至能夠作出更多的效果,只要項目對CPU要求不高,也不失爲一種還行的辦法。程序員

2、實現的功能

  • 1:可設置顯示的圖像
  • 2:可添加多個廣告
  • 3:可設置指示器樣式 迷你型樣式 數字型樣式
  • 4:可設置指示器大小
  • 5:可設置切換間隔

3、效果圖



4、頭文件代碼

#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

5、完整代碼

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

6、控件介紹

  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中拖曳設計使用。

7、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、學習方法、寫做技巧、熱門技術、職場發展等內容,乾貨多多,福利多多!
相關文章
相關標籤/搜索