Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Qt编写控件属性设计器4-加载属性

Qt编写控件属性设计器4-加载属性

原创
作者头像
feiyangqingyun
修改于 2019-09-16 02:52:32
修改于 2019-09-16 02:52:32
1.1K0
举报
文章被收录于专栏:Qt项目实战Qt项目实战

一、前言

控件能加载拖曳拉伸了,这些都是基本的前提工作,接下来的重点就是要动态加载选中控件的属性了,Qt的属性机制那是异常的强大,只能用强大到爆来形容,Qt中编写自定义控件,如果属性都用Q_PROPERTY来描述过,那都支持整个Qt生态环境中的各种应用场景的加载,比如widget的属性设计,qml中的属性识别等,都是非常的方便。

仔细观察QtDesigner设计器的属性控件,看起来和表格控件很类似,如果自己重新造轮子整一个,需要花费巨大的代价,其实Qt已经有这个开源组件在qt-solutions-master中,名字叫qtpropertybrowser,搜索下有很多该组件的使用方法,demo也是非常的详细,本人改过其中的部分代码以便过滤父类属性和中文属性映射等。

二、实现的功能

  1. 自动加载插件文件中的所有控件生成列表,默认自带的控件超过120个。
  2. 拖曳到画布自动生成对应的控件,所见即所得。
  3. 右侧中文属性栏,改变对应的属性立即应用到对应选中控件,直观简洁,非常适合小白使用。
  4. 独创属性栏文字翻译映射机制,效率极高,可以非常方便拓展其他语言的属性栏。
  5. 所有控件的属性自动提取并显示在右侧属性栏,包括枚举值下拉框等。
  6. 支持手动选择插件文件,外部导入插件文件。
  7. 可以将当前画布的所有控件配置信息导出到xml文件。
  8. 可以手动选择xml文件打开控件布局,自动根据xml文件加载控件。
  9. 可拉动滑动条、勾选模拟数据复选框、文本框输入,三种方式来生成数据应用所有控件。
  10. 控件支持八个方位拉动调整大小,自适应任意分辨率,可键盘上下左右微调位置。
  11. 打通了串口采集、网络采集、数据库采集三种方式设置数据。
  12. 代码极其精简,注释非常详细,可以作为组态的雏形,自行拓展更多的功能。
  13. 纯Qt编写,支持任意Qt版本+任意编译器+任意系统。

三、效果图

在这里插入图片描述
在这里插入图片描述

四、核心代码

代码语言:txt
AI代码解释
复制
void QtObjectController::setObject(QObject *object)
{
    //如果设置的控件已经是当前控件则不处理
    if (d_ptr->m_object == object) {
        return;
    }

    if (d_ptr->m_object) {
        d_ptr->saveExpandedState();
        QListIterator<QtProperty *> it(d_ptr->m_topLevelProperties);
        while (it.hasNext()) {
            d_ptr->m_browser->removeProperty(it.next());
        }
        d_ptr->m_topLevelProperties.clear();
    }

    d_ptr->m_object = object;

    if (!d_ptr->m_object) {
        return;
    }

    //加载父类的属性
    d_ptr->addClassPropertiesParent(d_ptr->m_object->metaObject()->superClass());
    //加载当前控件的属性
    d_ptr->addClassProperties(d_ptr->m_object->metaObject());
    //存储节点状态
    d_ptr->restoreExpandedState();

    //折叠所有节点
    d_ptr->collapseAll();
}

void QtObjectControllerPrivate::addClassProperties(const QMetaObject *metaObject)
{
    if (!metaObject) {
        return;
    }

    QtProperty *classProperty = m_classToProperty.value(metaObject);
    if (!classProperty) {
        QString className = QLatin1String(metaObject->className());
        classProperty = m_manager->addProperty(QtVariantPropertyManager::groupTypeId(), className);
        m_classToProperty[metaObject] = classProperty;
        m_propertyToClass[classProperty] = metaObject;

        for (int idx = metaObject->propertyOffset(); idx < metaObject->propertyCount(); idx++) {
            QMetaProperty metaProperty = metaObject->property(idx);
            int type = metaProperty.userType();
            QtVariantProperty *subProperty = 0;

            //将英文属性换成中文属性
            QString propertyName = metaProperty.name();
            propertyName = QtPropertyName::maps.value(propertyName, propertyName);

            if (!metaProperty.isReadable()) {
                subProperty = m_readOnlyManager->addProperty(QVariant::String, propertyName);
                subProperty->setValue(QLatin1String("< Non Readable >"));
            } else if (metaProperty.isEnumType()) {
                if (metaProperty.isFlagType()) {
                    subProperty = m_manager->addProperty(QtVariantPropertyManager::flagTypeId(), propertyName);
                    QMetaEnum metaEnum = metaProperty.enumerator();
                    QMap<int, bool> valueMap;
                    QStringList flagNames;
                    for (int i = 0; i < metaEnum.keyCount(); i++) {
                        int value = metaEnum.value(i);
                        if (!valueMap.contains(value) && isPowerOf2(value)) {
                            valueMap[value] = true;
                            flagNames.append(QLatin1String(metaEnum.key(i)));
                        }
                        subProperty->setAttribute(QLatin1String("flagNames"), flagNames);
                        subProperty->setValue(flagToInt(metaEnum, metaProperty.read(m_object).toInt()));
                    }
                } else {
                    subProperty = m_manager->addProperty(QtVariantPropertyManager::enumTypeId(), propertyName);
                    QMetaEnum metaEnum = metaProperty.enumerator();
                    QMap<int, bool> valueMap; // dont show multiple enum values which have the same values
                    QStringList enumNames;
                    for (int i = 0; i < metaEnum.keyCount(); i++) {
                        int value = metaEnum.value(i);
                        if (!valueMap.contains(value)) {
                            valueMap[value] = true;

                            //将枚举类型强制转为中文
                            QString enumName = metaEnum.key(i);
                            enumName = QtPropertyName::maps.value(enumName, enumName);
                            enumNames.append(enumName);
                        }
                    }
                    subProperty->setAttribute(QLatin1String("enumNames"), enumNames);
                    subProperty->setValue(enumToInt(metaEnum, metaProperty.read(m_object).toInt()));
                }
            } else if (m_manager->isPropertyTypeSupported(type)) {
                if (!metaProperty.isWritable()) {
                    subProperty = m_readOnlyManager->addProperty(type, propertyName + QLatin1String(" (Non Writable)"));
                }
                if (!metaProperty.isDesignable()) {
                    subProperty = m_readOnlyManager->addProperty(type, propertyName + QLatin1String(" (Non Designable)"));
                } else {
                    subProperty = m_manager->addProperty(type, propertyName);
                }
                subProperty->setValue(metaProperty.read(m_object));
            } else {
                subProperty = m_readOnlyManager->addProperty(QVariant::String, propertyName);
                subProperty->setValue(QLatin1String("< Unknown Type >"));
                subProperty->setEnabled(false);
            }
            classProperty->addSubProperty(subProperty);
            m_propertyToIndex[subProperty] = idx;
            m_classToIndexToProperty[metaObject][idx] = subProperty;
        }
    } else {
        updateClassProperties(metaObject, false);
    }

    m_topLevelProperties.append(classProperty);
    m_browser->addProperty(classProperty);
}

void QtObjectControllerPrivate::addClassPropertiesParent(const QMetaObject *metaObject)
{
    if (!metaObject) {
        return;
    }

    //存储需要过滤的属性,有时候大部分属性都用不上
    QStringList keyName;
    keyName << "geometry";

    QtProperty *classProperty = m_classToProperty.value(metaObject);
    if (!classProperty) {
        QString className = QLatin1String(metaObject->className());
        classProperty = m_manager->addProperty(QtVariantPropertyManager::groupTypeId(), className);
        m_classToProperty[metaObject] = classProperty;
        m_propertyToClass[classProperty] = metaObject;

        for (int idx = metaObject->propertyOffset(); idx < metaObject->propertyCount(); idx++) {
            QMetaProperty metaProperty = metaObject->property(idx);
            int type = metaProperty.userType();
            QtVariantProperty *subProperty = 0;

            //如果当前属性不在需要过滤的属性中则继续下一个属性判断
            QString propertyName = metaProperty.name();
            if (!keyName.contains(propertyName)) {
                continue;
            }

            propertyName = QtPropertyName::maps.value(propertyName, propertyName);

            if (!metaProperty.isReadable()) {
                subProperty = m_readOnlyManager->addProperty(QVariant::String, propertyName);
                subProperty->setValue(QLatin1String("< Non Readable >"));
            } else if (metaProperty.isEnumType()) {
                if (metaProperty.isFlagType()) {
                    subProperty = m_manager->addProperty(QtVariantPropertyManager::flagTypeId(), propertyName);
                    QMetaEnum metaEnum = metaProperty.enumerator();
                    QMap<int, bool> valueMap;
                    QStringList flagNames;
                    for (int i = 0; i < metaEnum.keyCount(); i++) {
                        int value = metaEnum.value(i);
                        if (!valueMap.contains(value) && isPowerOf2(value)) {
                            valueMap[value] = true;
                            flagNames.append(QLatin1String(metaEnum.key(i)));
                        }
                        subProperty->setAttribute(QLatin1String("flagNames"), flagNames);
                        subProperty->setValue(flagToInt(metaEnum, metaProperty.read(m_object).toInt()));
                    }
                } else {
                    subProperty = m_manager->addProperty(QtVariantPropertyManager::enumTypeId(), propertyName);
                    QMetaEnum metaEnum = metaProperty.enumerator();
                    QMap<int, bool> valueMap; // dont show multiple enum values which have the same values
                    QStringList enumNames;
                    for (int i = 0; i < metaEnum.keyCount(); i++) {
                        int value = metaEnum.value(i);
                        if (!valueMap.contains(value)) {
                            valueMap[value] = true;
                            enumNames.append(QLatin1String(metaEnum.key(i)));
                        }
                    }
                    subProperty->setAttribute(QLatin1String("enumNames"), enumNames);
                    subProperty->setValue(enumToInt(metaEnum, metaProperty.read(m_object).toInt()));
                }
            } else if (m_manager->isPropertyTypeSupported(type)) {
                if (!metaProperty.isWritable()) {
                    subProperty = m_readOnlyManager->addProperty(type, propertyName + QLatin1String(" (Non Writable)"));
                }
                if (!metaProperty.isDesignable()) {
                    subProperty = m_readOnlyManager->addProperty(type, propertyName + QLatin1String(" (Non Designable)"));
                } else {
                    subProperty = m_manager->addProperty(type, propertyName);
                }
                subProperty->setValue(metaProperty.read(m_object));
            } else {
                subProperty = m_readOnlyManager->addProperty(QVariant::String, propertyName);
                subProperty->setValue(QLatin1String("< Unknown Type >"));
                subProperty->setEnabled(false);
            }
            classProperty->addSubProperty(subProperty);
            m_propertyToIndex[subProperty] = idx;
            m_classToIndexToProperty[metaObject][idx] = subProperty;
        }
    } else {
        updateClassProperties(metaObject, false);
    }

    m_topLevelProperties.append(classProperty);
    m_browser->addProperty(classProperty);
}

五、控件介绍

  1. 超过150个精美控件,涵盖了各种仪表盘、进度条、进度球、指南针、曲线图、标尺、温度计、导航条、导航栏,flatui、高亮按钮、滑动选择器、农历等。远超qwt集成的控件数量。
  2. 每个类都可以独立成一个单独的控件,零耦合,每个控件一个头文件和一个实现文件,不依赖其他文件,方便单个控件以源码形式集成到项目中,较少代码量。qwt的控件类环环相扣,高度耦合,想要使用其中一个控件,必须包含所有的代码。
  3. 全部纯Qt编写,QWidget+QPainter绘制,支持Qt4.6到Qt5.12的任何Qt版本,支持mingw、msvc、gcc等编译器,支持任意操作系统比如windows+linux+mac+嵌入式linux等,不乱码,可直接集成到Qt Creator中,和自带的控件一样使用,大部分效果只要设置几个属性即可,极为方便。
  4. 每个控件都有一个对应的单独的包含该控件源码的DEMO,方便参考使用。同时还提供一个所有控件使用的集成的DEMO。
  5. 每个控件的源代码都有详细中文注释,都按照统一设计规范编写,方便学习自定义控件的编写。
  6. 每个控件默认配色和demo对应的配色都非常精美。
  7. 超过130个可见控件,6个不可见控件。
  8. 部分控件提供多种样式风格选择,多种指示器样式选择。
  9. 所有控件自适应窗体拉伸变化。
  10. 集成自定义控件属性设计器,支持拖曳设计,所见即所得,支持导入导出xml格式。
  11. 自带activex控件demo,所有控件可以直接运行在ie浏览器中。
  12. 集成fontawesome图形字体+阿里巴巴iconfont收藏的几百个图形字体,享受图形字体带来的乐趣。
  13. 所有控件最后生成一个动态库文件(dll或者so等),可以直接集成到qtcreator中拖曳设计使用。
  14. 目前已经有qml版本,后期会考虑出pyqt版本,如果用户需求量很大的话。
  15. 自定义控件插件开放动态库使用(永久免费),无任何后门和限制,请放心使用。
  16. 目前已提供26个版本的dll,其中包括了qt5.12.3 msvc2017 32+64 mingw 32+64 的。
  17. 不定期增加控件和完善控件,不定期更新SDK,欢迎各位提出建议,谢谢!
  18. Qt入门书籍推荐霍亚飞的《Qt Creator快速入门》《Qt5编程入门》,Qt进阶书籍推荐官方的《C++ GUI Qt4编程》。
  19. 强烈推荐程序员自我修养和规划系列书《大话程序员》《程序员的成长课》《解忧程序员》,受益匪浅,受益终生!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Qt编写控件属性设计器5-属性中文
在上一篇文章中就提到过,使用qtpropertybrowser来加载属性,对应加载到的属性是英文的,也就是控件类中Q_PROPERTY描述的变量名称,如何变成中文或者其他语言显示呢?这个就需要研究qtpropertybrowser的源码了,通过研究发现,在QtObjectControllerPrivate类中负责对控件的属性名称进行遍历,然后发送到QtVariantPropertyManager进行统一的管理,那只要将这里的属性名称进行映射就行了,对应的英文到中文或者其他语言都可以,甚至枚举值的下拉框也可以在这里换成中文的。曾经想过用翻译的机制,后面发现路很漫长,而且最终还是需要映射转换,看过QtDesigner的源码,里边最终也是将翻译文件中的对应项转换成中文的。
feiyangqingyun
2019/09/14
1.8K0
Qt编写控件属性设计器5-属性中文
Qt编写控件属性设计器1-加载插件
加载插件是整个属性设计器的第一步要打通的功能,插件中的控件都加载不了,后面就别搞别玩下去了没法玩的,要从一个动态库中加载出来控件,肯定需要用到反射机制,以前做.NET开发的时候就觉得反射这个东西相当强大,居然可以读取DLL加载出来控件,现在用Qt,发现Qt也有反射机制,也许这东东可能各大开发语言平台都具备吧,Qt反射对应的类叫QMetaObject,着实强大,其实整个Qt开发框架也是超级强大的,本人自从转为Qt开发为主后,就深深的爱上了她,在其他跨平台的GUI开发框架平台面前,都会被Qt秒成渣,Qt的跨平台性是毋庸置疑的,几十兆的内存存储空间即可运行,尤其是嵌入式linux这种资源相当紧张的情况下,Qt的性能发挥到极致。
feiyangqingyun
2019/09/14
1.3K0
Qt编写控件属性设计器1-加载插件
Qt 教程二
因为Qt是一个C++框架, 因此C++中所有的语法和数据类型在Qt中都是被支持的, 但是Qt中也定义了一些属于自己的数据类型, 下边给大家介绍一下这些基础的数类型。
用户11332765
2024/10/28
3060
Qt编写自定义控件34-磁盘容量统计
磁盘容量统计控件,说白了,就是用来统计本地盘符占用的容量,包括但不限于已用空间、剩余空间、总大小、已用百分比等,其中对应的百分比采用进度条显示,该进度条的前景色和背景色及文字颜色可以设置,在整体换肤的时候就需要用到。
feiyangqingyun
2019/08/27
1.5K0
Qt编写自定义控件34-磁盘容量统计
4. Qt的容器类
QList类、QLinkedList类和QVector类常常使用到的Qt容器类有QList、QLinkedList和QVector等。在开发一个较高性能需求的应用程序时。程序猿会比較关注这些容器类的执行效率。下表列出了QList、QLinkedList和QVector容器的时间复杂度。
全栈程序员站长
2022/07/07
1.1K0
4. Qt的容器类
使用vc(vs2008)编译Qt5.4
官方的Qt 只有vc10以上的版本 若是想vc9 只能自己编译 so 开始干 搜索资料 1)vc9不能支持webkit的编译 直接删除掉 2)有部分地方 vc9默认支持LONG转ULONG 需要自己改代码 3)需要OPENSSL 4)需要python3.4.3 5)需要activePerl开工 1。下载安装activeperl 2。下载安装python3.4.3 3。编译openssl 0.9.8k perl Configure VC-WIN32 –prefix=C:\Build-OpenSSL-VC9-32 ms\do_ms nmake -f ms\nt.mak   nmake -f ms\nt.mak install 4。开始config Qt5 一个bat搞定
用户3519280
2023/07/06
2800
Qt属性系统(Qt Property System)
  Qt提供了巧妙的属性系统,它与某些编译器支持的属性系统相似。然而,作为平台和编译器无关的库,Qt不能够依赖于那些非标准的编译器特性,比如__property 或者 [property]。Qt的解决方案能够被任何Qt支持的平台下的标准C++编译器支持。它依赖于元对象系统(Meta_Object Sytstem),元对象系统通过信号和槽提供了对象间通讯的机制。
全栈程序员站长
2021/12/29
2K0
Qt属性系统(Qt Property System)
Qt 音乐播放器「建议收藏」
一、实现功能: 1、读取歌曲文件,实现歌曲的播放; 2、采用Qt Designer实现歌曲的暂停和播放,歌曲名列表和当前播放歌曲名的显示,上一曲和下一曲歌曲的更换,播放模式的设置,音量的改变,歌曲播放进度的改变; 3、读取歌词文件,实现歌词的显示; 4、利用QSetting增加歌曲文件和歌词文件的设置功能; 5、界面汉化; 6、使用CSS进行界面美化。
全栈程序员站长
2022/08/12
1.8K0
Qt 音乐播放器「建议收藏」
Qt音视频开发16-mpv通用接口
前面几篇文章,依次讲了解码播放、录像存储、读取和控制、事件订阅等,其实这些功能的实现都离不开封装的通用的接口,最开始本人去调用一些设置的时候,发现多参数的不好实现,原来需要用mpv_node处理,而Qt中如何转成mpv_node需要特殊的处理才行,后来在开源主页看到了官方提供的demo例子,直接用qt封装好了多个接口(https://github.com/mpv-player/mpv-examples/tree/master/libmpv),看里面的注释是英文的,估计应该是官方提供的,传入的参数都是支持QVariant的,这样兼容性就超级强大了,多种不同类型的数据参数都可以传入进去,再次感谢官方的demo,官方的demo除了有QWidget的外还有qml的版本,同时还提供了opengl版本,各位有兴趣都可以down下来看看,不过demo比较简单就是,并没有演示所有的功能,只演示了最基础的功能比如播放视频进度控制等,离一个完整的视频播放器差十万八千里不止。
feiyangqingyun
2020/08/24
1.2K0
Qt音视频开发16-mpv通用接口
Qt开源网络库[4]-原理篇下
上一篇分析到原理上,主要讲述的是builder模式设计与HttpService,HttpRequest的原理和实现。本篇将会讲到HttpResponse的响应机制与自动推导接收者(槽函数)的实现。
Qt君
2019/07/15
9340
Qt TreeWidget 控件(一)
Qt 的List Widget、Tree Widget和Table Widget属于Qt Model/View中的简便类,之前文章介绍过Qt Model/View的三种级别分别是简便类、预定义模型以及自定义模型,其中自定义模型还没有介绍。对于这个简便类,还是有很多地方要介绍的。
用户5908113
2019/12/19
1.3K0
【QT】QT容器
隐式数据共享类当作为函数参数传递的时候,不仅安全而且效率很高,因为传递的时候只是传递了数据的指针,数据本身只当自己被修改的时候才会去复制。简称写时复制。
半生瓜的blog
2023/05/13
3.5K0
【QT】QT容器
Qt开源作品12-硬盘容量控件
磁盘容量统计控件,说白了,就是用来统计本地盘符占用的容量,包括但不限于已用空间、剩余空间、总大小、已用百分比等,其中对应的百分比采用进度条显示,该进度条的前景色和背景色及文字颜色可以设置,在整体换肤的时候就需要用到。
feiyangqingyun
2020/05/17
5520
Qt开源作品12-硬盘容量控件
06 json数据解析和列表控件
功能:将QJsonDocment转换 成QByteArray,以便将数据写入到json文件中
天天Lotay
2023/10/15
3120
06 json数据解析和列表控件
Qt编写控件属性设计器6-动态属性
之前就提过,Qt的属性机制强大到爆,这次的动态属性功能就是要让他爆,很难想象只要一行代码即可widget->setProperty("value", value);没错就这么简单,调用弱属性机制,可以直接控制控件中的所有属性,设计这个机制的人绝对是天才,直接跪了。至于具体底层是怎么实现的,这个可以先不管,也没有太多精力再去研究Qt的源码了,那个源码非常庞大,研究源码的时候最快的办法是搜索直接定位对应文件。本设计器除了提供文本框输入值进行动态改变控件属性以外,还提供了了滑动条、随机模拟数据、串口采集数据、网络采集数据、数据库采集数据等多种方式获取数据源。
feiyangqingyun
2019/09/14
1.9K0
Qt编写控件属性设计器6-动态属性
Qt编写自定义控件25-自定义QCustomPlot
上次在写大屏数据可视化电子看板系统时候,提到过改造QCustomPlot来实现柱状分组图、横向柱状图、横向分组图、鼠标悬停提示等。这次单独列出来描述,有很多人疑问为啥不用QChart,或者echart等形式,其实这两种方式我都尝试过,比如Qt5.7以后新增的QChart模块,曲线这块,支持数据量很小,而且用法极其不适应,非常别扭,尤其是10W以上数据量的支持,简直是渣渣,优点也是有很多的,比如动画效果,我看过他的完整源码,动画这块处理的非常好,连坐标轴都可以有动画效果,而且支持很多种效果,而且内置了很多套theme皮肤,省去了很多渣渣审美的程序员自己来配色,这个倒是挺方便的。而对于echart,必须依赖浏览器控件,资源占用比较高,后面决定采用改造QCustomPlot来实现用户需要的各种图表效果。
feiyangqingyun
2019/08/27
3.4K0
Qt编写自定义控件25-自定义QCustomPlot
qml 结合 QSqlTableModel 动态加载数据 MVC「建议收藏」
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/127739.html原文链接:https://javaforall.cn
全栈程序员站长
2022/07/25
1.1K0
qml 结合 QSqlTableModel 动态加载数据 MVC「建议收藏」
QT应用编程: 基于Qt设计的跨平台录音机功能
QT通过QAudioInput类读取声卡PCM数据,在封装WAV头,转为WAV格式的文件保存到本地。
DS小龙哥
2022/01/07
1.4K0
QT应用编程: 基于Qt设计的跨平台录音机功能
Qt编写自定义控件55-手机通讯录
前面几篇文章中的控件基本上难度系数接近0,甚至有凑控件数量的嫌疑,这次必须来一个强悍的控件,本控件难度系数在所有控件中排前五,代码量也不少,头文件都550行,实现文件1600行,为什么这么多呢,其实本控件是由好多个子控件组成的,字母高亮背景类、中间字母分隔类、右侧字母导航类、通讯录按钮类、自定义滚动条类,我在写比较复杂的控件的时候,一般都会逐个功能拆分,然后思考是否该功能可以做成独立的类,这样管理起来比较方便,也方便查看代码。
feiyangqingyun
2019/09/25
1.2K0
Qt编写自定义控件55-手机通讯录
Qt编写自定义控件24-图片轮播控件
上一篇文章写的广告轮播控件,采用的传统widget堆积设置样式表做的,这次必须要用到更高级的QPainter来绘制了,这个才是最高效的办法,本控件参考雨田哥的轮播控件,经过大规模的改造而成,相比于原来的广告轮播控件,本控件可以说完爆他,按在地上使劲摩擦。除了可以设置图片路径集合以外,还可以设置对应的提示信息,这个在众多的web轮播图片效果中最常见,比如新闻的标题等,可以更直观的显示当前图片,而且单击图片还可以支持跳转,指示器的位置也能设置左边+中间+右边,指示器的样式更加增加到椭圆条状+圆形+矩形+小圆点+长条状多种可选择,可以说涵盖了各种web轮播图片的效果,还可以设置鼠标悬停暂停轮播,以便看清说明后鼠标移开继续轮播。指示器的宽高颜色等,都是可以自由设定的,这个对于采用QPainter绘制来说,是最好自定义的,无非就是设置对应的画笔QPen和对应的画布QBrush的颜色啦。
feiyangqingyun
2019/08/27
2K0
Qt编写自定义控件24-图片轮播控件
相关推荐
Qt编写控件属性设计器5-属性中文
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档