Qt で書かれたコントロール プロパティ デザイナー ユーザー プロパティ

I.はじめに

ユーザープロパティは後から新たに追加される機能です。カスタムコントロールがQ_PROPERTY修正プロパティを採用している場合、プロパティバーに自動的に認識されます。これを一般にコントロールプロパティと呼びます。構成設計ソフトウェアには、コントロール自体。それでも十分ではありません。結局のところ、これらのプロパティは外観のみに基づいており、特定のデバイスのプロパティを表すことはできません。したがって、このコントロールのプロパティに加えて、デバイスを保存するためにユーザー プロパティを追加する必要がありますデバイス番号、デバイス名、地理的位置、その他の情報など、コントロールに関連付けられたプロパティ。この情報はコントロール属性と同じである必要があり、XML ファイルにインポートおよびエクスポートできます。複数のユーザー属性をサポートできます。ユーザーが自分で名前と値を入力します 名前と値の両方が中国語の記述をサポートします xml ファイルでは、ユーザー プロパティとコントロール プロパティを区別するために、user- プロパティを追加することでユーザー プロパティを具体的に表しますこのようにして、コントロールをロードするために XML ファイルが読み取られると、user- で始まるすべてのプロパティが認識され、コントロールのユーザー プロパティ リストに保存されます。

ユーザー属性メカニズムの導入により、コントロールの既存の機能が大幅に拡張されました。これは、N 個のカスタマイズされたデータをバインドすることに相当します。これらのユーザー属性は、setProperty を使用して直接設定し、プロパティを通じて読み込むことができます。順番に中国語属性をサポートします。属性を設定する必要がある場合は変換します: widget->setProperty(name.toStdString().c_str(), value);

体験アドレス:https://gitee.com/feiyangqingyun/QUCSDK
https://github.com/feiyangqingyun/qucsdk

2. 実装された機能

  1. プラグイン ファイル内のすべてのコントロールを自動的にロードしてリストを生成します。デフォルトの組み込みコントロールは 120 を超えています。
  2. キャンバスにドラッグすると、対応するコントロールが自動的に生成されます。表示されているものがそのまま得られます。
  3. 右側の中国語プロパティ バーでは、対応するプロパティを変更すると、対応する選択したコントロールにすぐに適用され、直感的かつ簡潔で、初心者が使用するのに非常に適しています。
  4. オリジナルの属性バーのテキスト翻訳マッピング メカニズムは非常に効率的であり、他の言語で属性バーを簡単に拡張できます。
  5. すべてのコントロールのプロパティが自動的に抽出され、列挙値ドロップダウン ボックスなどを含む右側のプロパティ バーに表示されます。
  6. プラグイン ファイルの手動選択とプラグイン ファイルの外部インポートをサポートします。
  7. 現在のキャンバスのすべてのコントロール構成情報を XML ファイルにエクスポートできます。
  8. XML ファイルを手動で選択してコントロール レイアウトを開き、XML ファイルに基づいてコントロールを自動的にロードできます。
  9. スライド バーを引くか、シミュレートされたデータのチェック ボックスをオンにするか、テキスト ボックスに入力してデータを生成し、すべてのコントロールを適用できます。
  10. このコントロールは 8 方向のプルとサイズ変更をサポートし、あらゆる解像度に適応し、キーボード上の上下左右の位置を微調整できます。
  11. これにより、シリアル ポート収集、ネットワーク収集、データベース収集という 3 つの方法でデータを設定できるようになります。
  12. コードは非常に簡潔で、コメントも非常に詳細なので、設定のプロトタイプとして利用して、自分でさらに機能を拡張することができます。
  13. 純粋な Qt で書かれており、任意の Qt バージョン + 任意のコンパイラ + 任意のシステムをサポートします。

3.エフェクト描画

4. コアコード

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();
}

この記事の特典として、Qt 開発学習パッケージと技術ビデオ (C++ 言語の基礎、Qt プログラミングの概要、QT シグナルとスロットのメカニズム、QT インターフェイス開発イメージの描画、QT ネットワーク、QT データベース) を無料で受け取ることができます。プログラミング、QT プロジェクトの実践、QT 組み込み開発、Quick モジュールなど) ↓↓↓↓下記参照↓↓料金受け取り記事下部をクリック↓↓

5. コントロールの導入

  1. さまざまなダッシュボード、プログレスバー、プログレスボール、コンパス、カーブ、ルーラー、温度計、ナビゲーションバー、ナビゲーションバー、フラットイ、ハイライトボタン、スライドセレクター、旧暦などをカバーする160以上の絶妙なコントロール。qwt によって統合されるコントロールの数をはるかに上回ります。
  2. 各クラスは結合なしで個別のコントロールに独立して形成できます。各コントロールにはヘッダー ファイルと実装ファイルがあり、他のファイルに依存しません。単一のコントロールを次の形式でプロジェクトに統合するのが便利です。ソースコードの量が減り、コードが減ります。qwt のコントロール クラスは連動しており、高度に結合されているため、いずれかのコントロールを使用する場合は、すべてのコードを含める必要があります。
  3. すべて純粋な Qt で書かれ、QWidget+QPainter によって描画され、Qt4.6 から Qt5.12 までの任意の Qt バージョンをサポートし、mingw、msvc、gcc などのコンパイラをサポートし、Windows+Linux+Mac+ などのオペレーティング システムをサポートします。埋め込み Linux など、文字化けしないコード、Qt Creator に直接統合でき、組み込みコントロールのように使用でき、ほとんどのエフェクトはいくつかのプロパティを設定するだけで済み、非常に便利です。
  4. 各コントロールには、簡単に参照して使用できるように、コントロールのソース コードを含む対応する個別のデモがあります。また、すべてのコントロールで使用される統合デモも提供します。
  5. 各コントロールのソース コードには詳細な中国語のコメントがあり、統一された設計仕様に従って記述されているため、カスタム コントロールの作成方法を簡単に学ぶことができます。
  6. 各コントロールのデフォルトのカラーマッチングとデモに対応したカラーマッチングが非常に絶妙です。
  7. 130 を超える表示コントロールと 6 つの非表示コントロール。
  8. 一部のコントロールでは、複数のスタイルの選択肢と複数のインジケーター スタイルの選択肢が提供されます。
  9. すべてのコントロールはフォームストレッチの変化に適応します。
  10. 統合されたカスタム コントロール属性デザイナー、ドラッグ アンド ドロップ デザイン、WYSIWYG をサポートし、XML 形式のインポートとエクスポートをサポートします。
  11. ActiveX コントロールのデモが付属しており、すべてのコントロールを IE ブラウザで直接実行できます。
  12. fontawesome グラフィック フォントと Alibaba iconfont が収集した何百ものグラフィック フォントを統合し、グラフィック フォントがもたらす楽しさをお楽しみください。
  13. すべてのコントロールは最終的にダイナミック ライブラリ ファイル (dll など) を生成します。これは、ドラッグ アンド ドロップ設計のために qtcreator に直接統合できます。
  14. qml バージョンはすでにありますが、ユーザーからの要望が多ければ pyqt バージョンも検討される予定です。
  15. カスタム コントロール プラグインは、バックドアや制限なしでダイナミック ライブラリを自由に使用できます (永久無料)。お気軽にご利用ください。
  16. 現在、qt5.12.3 msvc2017 32+64 mingw 32+64 を含む 26 バージョンの dll が提供されています。
  17. コントロールは随時追加および改善され、SDK も随時更新されます。ご提案は大歓迎です。ありがとうございます。
  18. Qt の入門書としては、Huo Yafei 著の『Qt Creator によるクイック スタート』および『Qt5 プログラミング入門』を、Qt の上級書籍については、公式の『C++ GUI Qt4 Programming』をお勧めします。
  19. プログラマー向けの自己啓発本と計画本シリーズ『偉そうなプログラマー』、『プログラマーの成長講座』、『悩み解消プログラマー』シリーズはとてもためになり、一生役に立つのでとてもおすすめです。
  20. SDKダウンロードリンク: https://pan.baidu.com/s/1A5Gd77kExm8Co5ckT51vvQ 抽出コード: 877p

元のリンク: cnblogs.com/feiyangqingyun/p/11922938.html

この記事の特典として、Qt 開発学習パッケージと技術ビデオ (C++ 言語の基礎、Qt プログラミングの概要、QT シグナルとスロットのメカニズム、QT インターフェイス開発イメージの描画、QT ネットワーク、QT データベース) を無料で受け取ることができます。プログラミング、QT プロジェクトの実践、QT 組み込み開発、Quick モジュールなど) ↓↓↓↓下記参照↓↓料金受け取り記事下部をクリック↓↓

おすすめ

転載: blog.csdn.net/hw5230/article/details/132813264