一、前言控件能加载拖曳拉伸了,这些都是基本的前提工作,接下来的重点就是要动态加载选中控件的属性了,Qt的属性机制那是异常的强大,只能用强大到爆来形容,Qt中编写自定义控件,如果属性都用Q_PROPERTY来描述过,那都支持整个Qt生态环境中的各种应用场景的加载,比如
widget的属性设计,qml中的属性识别等,都是非常的方便。
仔细观察QtDesigner设计器的属性控件,看起来和表格控件很类似,如果自己重新造轮子整一个,需要花费巨大的代价,其实Qt已经有这个开源组件在qt-solutions-master中,名字叫qtpropertybrowser,搜索下有很多该组件的使用方法,demo也是非常的详细,本人改过其中的部分代码以便过滤父类属性和中文属性映射等。
体验地址:
https://pan.baidu.com/s/1A5Gd77kExm8Co5ckT51vvQ 提取码:877p 文件:可执行
文件.zip
二、实现的功能1. 自动加载插件文件中的所有控件生成列表,默认自带的控件超过120个。
2. 拖曳到画布自动生成对应的控件,所见即所得。
3. 右侧中文属性栏,改变对应的属性立即应用到对应选中控件,直观简洁,非常适合小白使用。
4. 独创属性栏文字翻译映射机制,效率极高,可以非常方便拓展其他语言的属性栏。
5. 所有控件的属性自动提取并
显示在右侧属性栏,包括枚举值下拉框等。
6. 支持手动选择插件文件,外部导入插件文件。
7. 可以将当前画布的所有控件配置信息导出到xml文件。
8. 可以手动选择xml文件打开控件布局,自动根据xml文件加载控件。
9. 可拉动滑动条、勾选模拟
数据复选框、文本框输入,三种方式来生成数据应用所有控件。
10. 控件支持八个方位拉动调整大小,自适应任意分辨率,可键盘上下左右微调位置。
11. 打通了串口采集、网络采集、
数据库采集三种方式设置数据。
12. 代码极其精简,注释非常详细,可以作为组态的雏形,自行拓展更多的功能。
13. 纯Qt编写,支持任意Qt版本+任意
编译器+任意系统。
三、效果图四、核心代码- 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. 强烈推荐程序员自我修养和规划系列书《大话程序员》《程序员的成长课》《解忧程序员》,受益匪浅,受益终生!
20. SDK下载链接:[
https://pan.baidu.com/s/1A5Gd77kExm8Co5ckT51vvQ](https://pan.baidu.com/s/1A5Gd77kExm8Co5ckT51vvQ) 提取码:877p