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、学习方法、写作技巧、热门技术、职场发展等内容,干货多多,福利多多!

原文地址:https://www.cnblogs.com/feiyangqingyun/p/10987726.html

时间: 2024-10-11 07:52:48

Qt编写自定义控件23-广告轮播控件的相关文章

Qt编写自定义控件24-图片轮播控件

一.前言 上一篇文章写的广告轮播控件,采用的传统widget堆积设置样式表做的,这次必须要用到更高级的QPainter来绘制了,这个才是最高效的办法,本控件参考雨田哥的轮播控件,经过大规模的改造而成,相比于原来的广告轮播控件,本控件可以说完爆他,按在地上使劲摩擦.除了可以设置图片路径集合以外,还可以设置对应的提示信息,这个在众多的web轮播图片效果中最常见,比如新闻的标题等,可以更直观的显示当前图片,而且单击图片还可以支持跳转,指示器的位置也能设置左边+中间+右边,指示器的样式更加增加到椭圆条状

Android之仿京东淘宝的自动无限轮播控件

在App的开发中,很多的时候都需要实现类似京东淘宝一样的自动无限轮播的广告栏,所以就自己写了一个,下面是我自定义控件的思路和过程. 一.自定义控件属性 新建自定义控件SliderLayout继承于RelativeLayout,首先要考虑的就是自定义的控件需要扩展那些属性,把这些属性列出来.在这里是要实现类似于京东淘宝的无限轮播广告栏,那马首先想到的就是轮播的时长.轮播指示器的样式等等.我在这里列举了一些并且结合到了代码中. 1.扩展属性 (1)是否开启自动轮播的功能. (2)指示器的图形样式,一

Android--带位置提示的轮播控件

github地址:https://github.com/zerohuan/SlideLayout/tree/master 实际效果图: 该自定义控件继承FrameLayout, 包含一个ViewPager和横向排列的LinearLayout.后者用于包含显示表示轮播位置的点集,使用ViewPager的好处在于可以灵活的定义item的内容,而不仅仅是图片.</p><p></p><p>为了便于使用,通过自定义属性的方式定义了所须的运行参数:</p>&

走马灯图片轮播控件----------WinForm控件开发系列

/// <summary> /// 走马灯图片轮播控件 /// </summary> [ToolboxItem(true)] [DefaultProperty("Images")] [Description("走马灯图片轮播控件")] public partial class ImageCarouselExt : Control { #region private bool barShow = true; /// <summary>

adminLTE 教程 -4 轮播控件

轮播可以放在首页用来展示需要显示的内容,其实内容没有什么可以讲解的,就是在box下面放了carousel控件. 在adminLTE演示页面搜索Carousel <div class="box box-solid"> <div class="box-header with-border"> <h3 class="box-title">Carousel</h3> </div> <!--

WPF自定义轮播控件

 闲得蛋疼做了一个WPF制作轮播动画,勉强可以看,写个随笔留个脚印.  源码:有需要的可留言.  效果图:

图片轮播控件----------WinForm控件开发系列

   public partial class ImageCarouselDevelopExt : Control { #region /// <summary> /// 动画播放定时器 /// </summary> private Timer carouselTimer = new Timer(); /// <summary> /// 轮播的五个PictureBox /// </summary> private List<PictureBox>

swiper轮播控件配置项

var mySwiper = new Swiper ('.swiper-container', { direction: 'horizontal', loop: true, autoplay: 5000, autoplayDisableOnInteraction : false,  //控制使用分页器后,还可以自动轮播 // 如果需要分页器 pagination: '.swiper-pagination', paginationClickable :true,                 /

android-自定义广告轮播Banner(无限循环实现)

关于广告轮播,大家肯定不会陌生,它在现手机市场各大APP出现的频率极高,它的优点在于"不占屏",可以仅用小小的固定空位来展示几个甚至几十个广告条,而且动态效果很好,具有很好的用户"友好性",下面来看几个示例图:    再来看下我仿写的效果: 关于广告轮播Banner这个东西,GitHub上面应该有现成的开源组件,不过我没去找过,觉得实现起来不会太难,就自己去仿写了,下面我说下实现的思路: 1.首先看到这个可以滑动切换图片的界面,我们很自然就会想到ViewPager控