一、前言
广告轮播这个控件做的比较早,是很早以前定制一个电信客户端时候用到的,该客户端需要在首页展示轮播预先设定好的图片,图片的路径可以自由设定,然后轮播的间隔速度可以自由控制,同时该控件还需要提供两种指示器的风格,一种是迷你型的样式,一种是数字型的样式。
本控件很早就做好了,由于当时的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>#endifclass QDESIGNER_WIDGET_EXPORT AdsWidget : public QWidget#elseclass AdsWidget : public QWidget#endif{ Q_ 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(Q *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(Q *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->set Name(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->set Name(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(); }}六、控件介绍
- 超过146个精美控件,涵盖了各种仪表盘、进度条、进度球、指南针、曲线图、标尺、温度计、导航条、导航栏,flatui、高亮按钮、滑动选择器、农历等。远超qwt集成的控件数量。
- 每个类都可以独立成一个单独的控件,零耦合,每个控件一个头文件和一个实现文件,不依赖其他文件,方便单个控件以源码形式集成到项目中,较少代码量。qwt的控件类环环相扣,高度耦合,想要使用其中一个控件,必须包含所有的代码。
- 全部纯Qt编写,QWidget+QPainter绘制,支持Qt4.6到Qt5.12的任何Qt版本,支持mingw、msvc、gcc等编译器,不乱码,可直接集成到Qt Creator中,和自带的控件一样使用,大部分效果只要设置几个属性即可,极为方便。
- 每个控件都有一个对应的单独的包含该控件源码的DEMO,方便参考使用。同时还提供一个所有控件使用的集成的DEMO。
- 每个控件的源代码都有详细中文注释,都按照统一设计规范编写,方便学习自定义控件的编写。
- 每个控件默认配色和demo对应的配色都非常精美。
- 超过130个可见控件,6个不可见控件。
- 部分控件提供多种样式风格选择,多种指示器样式选择。
- 所有控件自适应窗体拉伸变化。
- 集成自定义控件属性设计器,支持拖曳设计,所见即所得,支持导入导出 格式。
- 自带activex控件demo,所有控件可以直接运行在ie浏览器中。
- 集成fontawesome图形字体+阿里巴巴iconfont收藏的几百个图形字体,享受图形字体带来的乐趣。
- 所有控件最后生成一个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、学习方法、写作技巧、热门技术、职场发展等内容,干货多多,福利多多!
继续阅读与本文标签相同的文章
上一篇 :
Qt编写自定义控件24-图片轮播控件
下一篇 :
Qt编写自定义控件22-蚂蚁线
-
.net持续集成测试篇之Nunit文件断言、字符串断言及集合断言
2026-05-21栏目: 教程
-
java并发之CopyOnWriteArrayList
2026-05-21栏目: 教程
-
异步编程CompletableFuture实现高并发系统优化之请求合并
2026-05-21栏目: 教程
-
Qt编写自定义控件22-蚂蚁线
2026-05-21栏目: 教程
-
Qt编写自定义控件23-广告轮播控件
2026-05-21栏目: 教程
