将C++类注册到QML

Q_GLOBLE_STATIC

由Qt负责线程安全懒加载的创建单例对象

Q_GLOBAL_STATIC(Type, instanceName);  // 声明全局静态对象
Q_GLOBAL_STATIC_WITH_ARGS(Type, instanceName, Args...);  // 带参数的构造
  • Type​:单例类的类型。
  • instanceName​:静态实例的变量名。
  • Args...​:构造函数参数(可选)。
Q_GLOBAL_STATIC(A, aInstance); // 由qt负责构造和提供一个静态单例实例

class A{
	static A* getInstance(){
		return &aInstance;
	}
	/*
	相当于
	static A* getInstance(){ // 
		static aInstance; // 构造可能多线程不安全,将其交给qt负责
		return &aInstance;
	}
	*/
}

手动注册

非单例

实现方法:**qmlRegisterType<MyComponent>

1. 注册类型

// 注册到 QML
qmlRegisterType<MyComponent>("com.mylib", 1, 0, "MyComponent");
// C++ 类定义
class MyComponent : public QObject {
    Q_OBJECT
    Q_PROPERTY(QString name READ name WRITE setName)
public:
    explicit MyComponent(QObject *parent = nullptr) : QObject(parent) {}
    QString name() const { return m_name; }
    void setName(const QString &name) { m_name = name; }
private:
    QString m_name;
};

// 注册到 QML
qmlRegisterType<MyComponent>("com.mylib", 1, 0, "MyComponent");

2. 使用

非单例对象需要在QML作组件实例化,然后才能访问

// QML 中使用(每次创建新实例)
import com.mylib 1.0 // 导入

MyComponent {
    id: component1
    name: "Instance 1"
}

MyComponent {
    id: component2  // 独立的新实例
    name: "Instance 2"
}

单例

实现方法:qmlRegisterSingletonType<ClassName> + 工厂方法

所有 QML 组件访问的是同一个实例,需通过工厂函数控制实例化。

1. 工厂函数签名必须是

static QObject* create(QQmlEngine*, QJSEngine*) {
        static ConfigManager instance;  // 全局唯一实例
        return &instance;
}

2. 注册到引擎中

// main.cpp :: main()

// 注册到 QML
qmlRegisterSingletonType<ConfigManager>(
    "com.mylib",// 包名
    1,  // 版本
    0, // 版本 
    "ConfigManager", // QML中访问使用的类型名
    [](QQmlEngine*, QJSEngine*) -> QObject* { return ConfigManager::create(nullptr, nullptr);  // 类工厂方法
}
);

3. QML中访问

单例组件直接通过类名访问

// QML 中使用(全局共享实例)
import com.mylib 1.0

Text {
	// 单例对象不实例化为组件,直接通过类名访问
    text: ConfigManager.theme  // 所有组件访问同一实例
}

是否多QML引擎间共享单例:qmlRegisterSingletonType控制每个实例只在QML引擎使用工厂类获取一次。如果通过工厂方法每次都返回相同实例,则就是多QML引擎共享的,如果每次返回新实例,就是多引擎不共享的。

QML_ELEMENT 宏(自动化注册)​

在cmake中配置统一版本,无需配置类型名等,简化开发代码。

非单例对象

1. 包含宏

// MyClass.h
#include <QObject>

class MyClass : public QObject {
    Q_OBJECT
    QML_ELEMENT
    // QML_NAMED_ELEMENT(MyClass)  // 指定QML中使用的类型名,可省略,省略则自动使用C++类名作为QML类型名
    // ...
};

2. CMake中包含文件,配置模块信息

qt_add_qml_module(MyModule
    URI "MyModule" // QML中使用的包名
    VERSION 1.0 // 版本
    SOURCES myclass.h myclass.cpp // 文件
)

3. 使用

非单例要实例化组件然后通过组件访问

// QML 中直接使用类名
import MyModule 1.0

MyClass {  // 类型名与 C++ 类名一致
    //...
}

单例对象

1. 包含宏

// MyClass.h
#include <QObject>

class MyClass : public QObject {
    Q_OBJECT
    QML_ELEMENT // 注册QML对象
    QML_SINGLETON // 自动注册为QML单例
    // ...
};

2. CMake中包含文件,配置模块信息

qt_add_qml_module(MyModule
    URI "MyModule" // QML中使用的包名
    VERSION 1.0 // 版本
    SOURCES myclass.h myclass.cpp // 文件
)

3. 使用

直接通过类名访问单例对象

// QML 中直接使用类名
import MyModule 1.0

Rectangle {  
    name: MyClass.value
}

暴露属性

属性绑定

使用Q_PROPERTY要提供读写方法和信号,写用来在事件中设置属性,读和信号用来将数据绑定到组件,并通过信号触发读方法更新视图,同时信号也可以捕获处理。

先来看数据流向

image

整体是一个单向绑定 事件->Model->View

QML将一个属性绑定 cpp对象方法

Text{
	text: cppobj.value // 从 js = cppobj.value 调用的是cppobj.Getter方法
	onChange:{
		cppobj.value = value // 这里赋值操作时setter方法
	}
}

cppobj.value 其底层会调用cppobj.Getter方法获取数据,并且绑定valueChange信号。
cpp值改变时,会发送信号触发Getter去更新数据(set方法emit信号,如果不发送信号则不会去触发视图更新)

// MyClass.h
#include <QObject>

class MyClass : public QObject {
    Q_OBJECT
    QML_ELEMENT  // 自动注册为QML类型
    
    // 暴露属性:类型、名称、读方法、写方法、通知信号
    Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)

public:
    explicit MyClass(QObject* parent = nullptr) : QObject(parent) {}

    // Getter方法
    QString name() const { return m_name; }

    // Setter方法
    void setName(const QString& name) {
        if (m_name == name) return;
        m_name = name;
        emit nameChanged();  // 触发通知信号到QML
    }

signals:
    void nameChanged();

private:
    QString m_name = "Default";
};

信号捕捉

可以在QML的C++组件中捕捉信号并处理

MyClass{
	onNameChanged:{ // on+信号名 捕捉信号
		// ... 
	}
}

方法绑定

使用 Q_INVOKABLE

// MyClass.h
#include <QObject>
#include <QString>

class MyClass : public QObject {
    Q_OBJECT
    QML_ELEMENT
    
public:
    explicit MyClass(QObject* parent = nullptr) : QObject(parent) {}

    // 暴露普通方法
    Q_INVOKABLE QString formatMessage(const QString& text, int count) {
        return QString("%1: %2 items").arg(text).arg(count);
    }

    // 暴露槽函数(无需Q_INVOKABLE,自动可见)
public slots:
    void reset() {
        m_value = 0;
        emit valueChanged();
    }
    
    // 暴露信号处理函数
    void onButtonClicked() {
        qDebug() << "Button clicked!";
    }

signals:
    void operationCompleted(bool success);
};
posted @ 2025-07-20 00:33  丘狸尾  阅读(132)  评论(0)    收藏  举报