Qt written control property designer-user properties

I. Introduction

User properties are a newly added function later. If the custom control adopts the Q_PROPERTY modified property, it will be automatically recognized in the property bar. This is generally called the control property. In the configuration design software, there are only the control properties of the control itself. It's still not enough. After all, these properties are only based on appearance and cannot represent the properties of a certain device. Therefore, in addition to the properties of this control, user properties need to be added to store the device properties associated with the control, such as device number, device name, geography Position and other information, and this information must be the same as the control attributes, and can be imported and exported to xml files. It can support multiple user attributes at the same time. The user fills in the name and value by himself. Both the name and value support Chinese description. In the xml file, in order To distinguish between user properties and control properties, the user properties are specifically represented by adding the user- prefix in front of them. In this way, when the xml file is read to load the control, all properties beginning with user- are recognized and stored in the user property list of the control.

Since the introduction of the user attribute mechanism, the existing functions of the control have been greatly expanded. It is equivalent to binding N customized data. These user attributes can be set directly using setProperty, and then read through property. In order Supports Chinese attribute names. Convert when you need to set attributes: widget->setProperty(name.toStdString().c_str(), value);

Experience address: https://gitee.com/feiyangqingyun/QUCSDK
https://github.com/feiyangqingyun/qucsdk

2. Functions implemented

  1. Automatically loads all controls in the plug-in file to generate a list. The default built-in controls are more than 120.
  2. Drag to the canvas to automatically generate the corresponding control, what you see is what you get.
  3. In the Chinese property bar on the right, changing the corresponding properties is immediately applied to the corresponding selected control. It is intuitive and concise, and is very suitable for novices to use.
  4. The original attribute bar text translation mapping mechanism is extremely efficient and can easily expand the attribute bar in other languages.
  5. The properties of all controls are automatically extracted and displayed in the property bar on the right, including enumeration value drop-down boxes, etc.
  6. Supports manual selection of plug-in files and external import of plug-in files.
  7. All control configuration information of the current canvas can be exported to an xml file.
  8. You can manually select the xml file to open the control layout, and automatically load the control based on the xml file.
  9. You can pull the slide bar, check the simulated data check box, or enter the text box to generate data and apply all controls.
  10. The control supports pulling and resizing in eight directions, adapts to any resolution, and can fine-tune the position up, down, left, and right on the keyboard.
  11. It opens up three ways to set data: serial port collection, network collection, and database collection.
  12. The code is extremely concise and the comments are very detailed. It can be used as a prototype of the configuration to expand more functions by yourself.
  13. Written in pure Qt, it supports any Qt version + any compiler + any system.

3. Effect drawing

4. Core code

void frmMain::openFile(const QString &fileName)
{
    //如果控件列表没有则不用继续
    if (ui->listWidget->count() == 0) {
        return;
    }

    //打开文件
    QFile file(fileName);
    if (!file.open(QFile::ReadOnly | QFile::Text)) {
        return;
    }

    //将文件填充到dom容器
    QDomDocument doc;
    if (!doc.setContent(&file)) {
        file.close();
        return;
    }

    file.close();

    listSelect.clear();
    listUserProperty.clear();
    xmlName = fileName;

    //先清空原有控件
    QList<QWidget *> widgets = ui->centralwidget->findChildren<QWidget *>();
    qDeleteAll(widgets);
    widgets.clear();

    //先判断根元素是否正确
    QDomElement docElem = doc.documentElement();
    if (docElem.tagName() == "canvas") {
        QDomNode node = docElem.firstChild();
        QDomElement element = node.toElement();
        while(!node.isNull()) {
            //控件名称
            QString name = element.tagName();
            //取出当前控件在控件列表中的索引,如果不存在则意味着配置文件中的该控件不存在了
            int index = listNames.indexOf(name);
            if (index < 0) {
                continue;
            }

            //存储控件的坐标位置和宽度高度
            int x, y, width, height;
            //存储自定义控件属性
            QList<QPair<QString, QVariant> > propertys;
            //存储控件自定义属性
            QStringList userProperty;

            //节点名称不为空才继续
            if (!name.isEmpty()) {
                //遍历节点的属性名称和属性值
                QDomNamedNodeMap attrs = element.attributes();
                for (int i = 0; i < attrs.count(); i++) {
                    QDomNode node = attrs.item(i);
                    QString nodeName = node.nodeName();
                    QString nodeValue = node.nodeValue();
                    //qDebug() << name << nodeName << nodeValue;

                    //优先取出坐标+宽高属性,这几个属性不能通过设置弱属性实现
                    if (nodeName == "x") {
                        x = nodeValue.toInt();
                    } else if (nodeName == "y") {
                        y = nodeValue.toInt();
                    } else if (nodeName == "width") {
                        width = nodeValue.toInt();
                    } else if (nodeName == "height") {
                        height = nodeValue.toInt();
                    } else if (nodeName.startsWith("user-")) {
                        //取出user-开头的自定义属性
                        nodeName = nodeName.split("-").last();
                        userProperty << QString("%1|%2").arg(nodeName).arg(nodeValue);
                    } else {
                        QVariant value = QVariant(nodeValue);
                        //为了兼容Qt4,需要将颜色值的rgba分别取出来,因为Qt4不支持16进制字符串带透明度
                        //#6422a3a9 这种格式依次为 argb 带了透明度的才需要特殊处理
                        if (nodeValue.startsWith("#") && nodeValue.length() == 9) {
                            bool ok;
                            int alpha = nodeValue.mid(1, 2).toInt(&ok, 16);
                            int red = nodeValue.mid(3, 2).toInt(&ok, 16);
                            int green = nodeValue.mid(5, 2).toInt(&ok, 16);
                            int blue = nodeValue.mid(7, 2).toInt(&ok, 16);
                            value = QColor(red, green, blue, alpha);
                        }

                        propertys.append(qMakePair(nodeName, value));
                    }
                }
            }

            //qDebug() << name << x << y << width << height;

            //根据不同的控件类型实例化控件
            int countWidget = listWidgets.count();
            int countProperty = propertys.count();
            for (int i = 0; i < countWidget; i++) {
                QString className = listWidgets.at(i)->name();
                if (name == className) {
                    //生成对应的控件
                    QWidget *widget = createWidget(i);
                    //逐个设置自定义控件的属性
                    for (int j = 0; j < countProperty; j++) {
                        QPair<QString, QVariant> property = propertys.at(j);
                        QString name = property.first;
                        QVariant value = property.second;
                        widget->setProperty(name.toStdString().c_str(), value);
                    }

                    //设置控件坐标及宽高
                    widget->setGeometry(x, y, width, height);
                    //实例化选中窗体跟随控件一起
                    newSelect(widget, userProperty);
                    break;
                }
            }

            //移动到下一个节点
            node = node.nextSibling();
            element = node.toElement();
        }
    }
}

void frmMain::saveFile(const QString &fileName)
{
    //如果控件列表没有则不用继续
    if (ui->listWidget->count() == 0) {
        return;
    }

    QFile file(fileName);
    if (!file.open(QFile::WriteOnly | QFile::Text | QFile::Truncate)) {
        return;
    }

    //以流的形式输出文件
    QTextStream stream(&file);

    //构建xml数据
    QStringList list;

    //添加固定头部数据
    list << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
    //添加canvas主标签,保存宽高和背景图片,还可以自行添加其他属性
    list << QString("<canvas width=\"%1\" height=\"%2\" image=\"%3\">")
         .arg(ui->centralwidget->width()).arg(ui->centralwidget->height()).arg("bg.jpg");

    //从容器中找到所有控件,根据控件的类名保存该类的所有属性
    QList<QWidget *> widgets = ui->centralwidget->findChildren<QWidget *>();
    foreach (QWidget *widget, widgets) {
        const QMetaObject *metaObject = widget->metaObject();
        QString className = metaObject->className();

        //如果当前控件的父类不是主窗体则无需导出,有些控件有子控件无需导出
        if (widget->parent() != ui->centralwidget || className == "SelectWidget") {
            continue;
        }

        //逐个存储自定义控件属性
        //metaObject->propertyOffset()表示当前控件的属性开始索引,0开始的是父类的属性
        QStringList values;
        int index = metaObject->propertyOffset();
        int count = metaObject->propertyCount();
        for (int i = index; i < count; i++) {
            QMetaProperty property = metaObject->property(i);
            QString nodeName = property.name();
            QVariant variant = property.read(widget);
            QString typeName = variant.typeName();
            QString nodeValue = variant.toString();

            //如果是颜色值则取出透明度一起,颜色值toString在Qt4中默认不转透明度
            if (typeName == "QColor") {
                QColor color = variant.value<QColor>();
                if (color.alpha() < 255) {
                    //Qt4不支持HexArgb格式的字符串,需要挨个取出来拼接
                    //nodeValue = color.name(QColor::HexArgb);
                    QString alpha = QString("%1").arg(color.alpha(), 2, 16, QChar('0'));
                    QString red = QString("%1").arg(color.red(), 2, 16, QChar('0'));
                    QString green = QString("%1").arg(color.green(), 2, 16, QChar('0'));
                    QString blue = QString("%1").arg(color.blue(), 2, 16, QChar('0'));
                    nodeValue = QString("#%1%2%3%4").arg(alpha).arg(red).arg(green).arg(blue);
                }
            }

            //枚举值要特殊处理,需要以字符串形式写入,不然存储到配置文件数据为int
            if (property.isEnumType()) {
                QMetaEnum enumValue = property.enumerator();
                nodeValue = enumValue.valueToKey(nodeValue.toInt());
            }

            values << QString("%1=\"%2\"").arg(nodeName).arg(nodeValue);
            //qDebug() << nodeName << nodeValue << variant;
        }

        //找到当前控件对应的索引
        index = -1;
        count = listSelect.count();
        for (int i = 0; i < count; i++) {
            if (listSelect.at(i)->getWidget() == widget) {
                index = i;
                break;
            }
        }

        //可以用下面方法列出所有的用户属性,然后取值,本程序已经用 listUserProperty 存储了
        //qDebug() << widget->dynamicPropertyNames();

        //逐个存储控件的用户属性
        QStringList userProperty = listUserProperty.at(index);
        count = userProperty.count();
        for (int i = 0; i < count; i++) {
            QStringList list = userProperty.at(i).split("|");
            values << QString("user-%1=\"%2\"").arg(list.at(0)).arg(list.at(1));
        }

        //逐个添加界面上的控件的属性
        QString geometry = QString("x=\"%1\" y=\"%2\" width=\"%3\" height=\"%4\"").arg(widget->x()).arg(widget->y()).arg(widget->width()).arg(widget->height());
        QString str = QString("\t<%1 %2 %3/>").arg(className).arg(geometry).arg(values.join(" "));
        list << str;
    }

    //添加固定尾部数据
    list << "</canvas>";

    //写入文件
    QString data = list.join("\n");
    stream << data;
    file.close();
}

As a benefit for this article, you can receive a Qt development learning package and technical videos for free, including (C++ language basics, introduction to Qt programming, QT signal and slot mechanism, QT interface development-image drawing, QT network, QT database programming, QT project practice , QT embedded development, Quick module, etc.) ↓↓↓↓↓↓See below↓↓Click at the bottom of the article to receive the fee↓↓

5. Control introduction

  1. More than 160 exquisite controls, covering various dashboards, progress bars, progress balls, compasses, curves, rulers, thermometers, navigation bars, navigation bars, flatui, highlight buttons, sliding selectors, lunar calendar, etc. Far exceeds the number of controls integrated by qwt.
  2. Each class can be independently formed into a separate control, with zero coupling. Each control has a header file and an implementation file, and does not rely on other files. It is convenient for a single control to be integrated into the project in the form of source code, with less code. The control classes of qwt are interlocking and highly coupled. If you want to use one of the controls, you must include all the code.
  3. All written in pure Qt, drawn by QWidget+QPainter, support any Qt version from Qt4.6 to Qt5.12, support compilers such as mingw, msvc, gcc, etc., support any operating system such as windows+linux+mac+embedded linux, etc., no garbled code , can be directly integrated into Qt Creator and used like the built-in controls. Most effects only need to set a few properties, which is extremely convenient.
  4. Each control has a corresponding separate DEMO containing the source code of the control for easy reference and use. It also provides an integrated DEMO used by all controls.
  5. The source code of each control has detailed Chinese comments and is written in accordance with unified design specifications, making it easy to learn how to write custom controls.
  6. The default color matching of each control and the color matching corresponding to the demo are very exquisite.
  7. More than 130 visible controls and 6 invisible controls.
  8. Some controls provide multiple style choices and multiple indicator style choices.
  9. All controls adapt to form stretch changes.
  10. Integrated custom control attribute designer, supports drag and drop design, WYSIWYG, supports import and export of xml format.
  11. Comes with activex control demo, all controls can be run directly in the IE browser.
  12. Integrate fontawesome graphic fonts + hundreds of graphic fonts collected by Alibaba iconfont, and enjoy the fun brought by graphic fonts.
  13. All controls finally generate a dynamic library file (dll or so, etc.), which can be directly integrated into qtcreator for drag and drop design.
  14. There is already a qml version, and a pyqt version will be considered later if there is great demand from users.
  15. The custom control plug-in is open to dynamic library use (free forever), without any backdoors or restrictions, so please feel free to use it.
  16. Currently, 26 versions of dll have been provided, including qt5.12.3 msvc2017 32+64 mingw 32+64.
  17. Controls are added and improved from time to time, and the SDK is updated from time to time. Suggestions are welcome, thank you!
  18. For introductory Qt books, we recommend Huo Yafei's "Quick Start with Qt Creator" and "Introduction to Qt5 Programming". For advanced Qt books, we recommend the official "C++ GUI Qt4 Programming".
  19. I highly recommend the series of self-cultivation and planning books for programmers, "The Big Talk Programmer", "Programmer's Growth Course", and "The Worry-Relieving Programmer", which will benefit you a lot and will last a lifetime!
  20. SDK download link: https://pan.baidu.com/s/1A5Gd77kExm8Co5ckT51vvQ Extraction code: 877p

Original link: cnblogs.com/feiyangqingyun/p/11922938.html

As a benefit for this article, you can receive a Qt development learning package and technical videos for free, including (C++ language basics, introduction to Qt programming, QT signal and slot mechanism, QT interface development-image drawing, QT network, QT database programming, QT project practice , QT embedded development, Quick module, etc.) ↓↓↓↓↓↓See below↓↓Click at the bottom of the article to receive the fee↓↓

Guess you like

Origin blog.csdn.net/hw5230/article/details/132813264