QML(2) - Qt 中如何注册一个 C++ 类到 QML

发布于:2025-08-29 ⋅ 阅读:(12) ⋅ 点赞:(0)

QT5.15 之前的传统用法

前言
在进行 Qt Quick 开发时, 有些需求是无法在 QML 中实现的,我们必须要使用C++中的方法来完成它,这个时候我们就需要实现 QML 与 C++ 的混合编程。

通常我们会先把需要的功能在 C++ 中全部完成,然后在 QML 中直接调用 C++ 中的方法。博主查看了Qt的帮助文档发现一共有两种方法可以实现。

方法一:在QML系统中注册C++类型
官方文档说明:

具体步骤如下:

1. 实现C++类的功能;

myconfiguration.h

#ifndef MYCONFIGURATION_H
#define MYCONFIGURATION_H

#include <QObject>
#include <QSettings>

class MyConfiguration : public QObject
{
    Q_OBJECT
public:
    explicit MyConfiguration(QObject *parent = nullptr);

    // 使用 Q_INVOKABLE 宏修饰的方法才可以在 QML 中被调用	
    Q_INVOKABLE void setProperty(QString name, QString section, QString key, QString value);

    Q_INVOKABLE QString getProperty(QString name, QString section, QString key);

signals:

public slots:
};

#endif // MYCONFIGURATION_H
myconfiguration.cpp

#include "myconfiguration.h"

MyConfiguration::MyConfiguration(QObject *parent) : QObject(parent)
{

}

void MyConfiguration::setProperty(QString name, QString section, QString key, QString value)
{
    QString fileName = name;
    QString path = section + "/" + key;

    QSettings *settings = new QSettings(fileName, QSettings::IniFormat);
    settings->setValue(path, value);
}

QString MyConfiguration::getProperty(QString name, QString section, QString key)
{
    QString fileName = name;
    QString path = section + "/" + key;

    QSettings *settings = new QSettings(fileName, QSettings::IniFormat);
    return settings->value(path, "").toString();
}

      2. 使用 qmlRegisterType 函数将类注册到 QML 中;

    包含必要的头文件

    确保你的C++代码中包含了必要的Qt QML头文件。

    // 注册你的C++类

    qmlRegisterType<YourClass>("com.yourcompany.yourapp", 1, 0, "YourClass");

    • "com.yourcompany.yourapp":这是你为你的类型指定的URI。这个URI用于在QML文件中引用你的类型。它应该是一个反向域名,以确保唯一性。

    • 1, 0:这是主版本号和次版本号,用于版本控制。当你的类型发生变化时,你可以更新这些值来通知QML环境。

    • "YourClass":这是你在QML文件中将要使用的类型名称。它应该与C++类名相对应或者你可以自定义一个更易于使用的名称。

    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    #include "myconfiguration.h"
    #include <QQmlContext>
    #include <QtQml>
    
    int main(int argc, char *argv[])
    {
        QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    
        QGuiApplication app(argc, argv);
    
        QQmlApplicationEngine engine;
        //参数:qmlRegisterType<C++类型名> (命名空间 主版本 次版本 QML中的类型名)
        qmlRegisterType<MyConfiguration, 1>("com.yourcompany.yourapp", 1, 0, "MyConfiguration");
    
        const QUrl url(QStringLiteral("qrc:/main.qml"));
        QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                         &app, [url](QObject *obj, const QUrl &objUrl) {
            if (!obj && url == objUrl)
                QCoreApplication::exit(-1);
        }, Qt::QueuedConnection);
        engine.load(url);
    
        return app.exec();
    }
    

      3. 使用 import 语句导入注册时填写的类所在的命名空间;

      4. 在 QML 文件中实例化对象;

      5. 通过该对象的 id 来访问对象的属性和方法;

      import QtQuick 2.12
      import QtQuick.Window 2.12
      // 导入命名空间
      import com.yourcompany.yourapp 1.0
      
      Window {
          visible: true
          width: 640
          height: 480
      
          // 实例化对象
          MyConfiguration { id: myConfiguration }
      
          Rectangle {
              width: 200
              height: 160
              anchors.centerIn: parent
              color: "yellow"
      
              Text {
                  id: myText
                  anchors.centerIn: parent
                  font.pixelSize: 24
                  font.family: "微软雅黑"
                  color: "black"
                  text: "测试"
              }
      
              MouseArea {
                  anchors.fill: parent
                  onClicked: {
                      // 通过 id 调用 getProperty 和 setProperty
                      // 运行结果如下图所示,获取到配置文件中的 name 为 billy 并赋值给 text
                      // 修改配置文件中 age 的值为 30
                      myText.text  = myConfiguration.getProperty("config.ini", "base", "name")
                      myConfiguration.setProperty("config.ini", "base", "age", "30")
                  }
              }
          }
      }
      

      注意事项:

      • 确保你的C++类是可被QML访问的,通常意味着它应该有合适的Q_OBJECT宏(如果使用了信号和槽),并且它的构造函数是可访问的。

      • 如果你的类包含自定义的信号和槽,确保它们使用了Q_INVOKABLE宏,这样它们才能在QML中被调用。

      • 如果你的类有属性或者需要暴露给QML,确保它们使用了Q_PROPERTY宏。

      通过以上步骤,你可以将C++类成功地注册到QML环境中,从而在QML界面中使用这些C++类的功能。

      方法二:将对象设置为上下文属性

      具体步骤如下:

      1. 实现C++类的功能(同法一的第一步);

      2. 在 main.cpp 中完成属性设置;

      #include <QGuiApplication>
      #include <QQmlApplicationEngine>
      #include "myconfiguration.h"
      #include <QQmlContext>
      
      int main(int argc, char *argv[])
      {
          QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
      
          QGuiApplication app(argc, argv);
      
          QQmlApplicationEngine engine;
      
          // 把类的实例化对象 myConfiguration 设置为上下文属性
          // 可以在所有qml文件中通过 applicationConfiguration 来调用该类的属性和方法
          MyConfiguration myConfiguration;
          engine.rootContext()->setContextProperty("applicationConfiguration", &myConfiguration);
      
          const QUrl url(QStringLiteral("qrc:/main.qml"));
          QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                           &app, [url](QObject *obj, const QUrl &objUrl) {
              if (!obj && url == objUrl)
                  QCoreApplication::exit(-1);
          }, Qt::QueuedConnection);
          engine.load(url);
      
          return app.exec();
      }
      

        3. 在所有qml文件中都可以通过设置好的名字来调用该类中的属性和方法;

        import QtQuick 2.12
        import QtQuick.Window 2.12
        
        Window {
            visible: true
            width: 640
            height: 480
        
            Rectangle {
                width: 200
                height: 160
                anchors.centerIn: parent
                color: "yellow"
        
                Text {
                    id: myText
                    anchors.centerIn: parent
                    font.pixelSize: 24
                    font.family: "微软雅黑"
                    color: "black"
                    text: "测试"
                }
        
                MouseArea {
                    anchors.fill: parent
                    onClicked: {
                        // 通过 applicationConfiguration 调用属性和方法
                        myText.text  = applicationConfiguration.getProperty("config.ini", "base", "name")
                        applicationConfiguration.setProperty("config.ini", "base", "age", "30")
                    }
                }
            }
        }
        

        网站公告

        今日签到

        点亮在社区的每一天
        去签到