基础知识部分
主体框架,qml必须通过源对象来进行交互,即交互的双方都是QObject的子类,能有一个基础的沟通系统,在qml与cpp交互过程中,鉴于cpp多种设计模式,和对于数据的不同使用和需求,设计了多个接口
在此列举:
qmlRegisterAnonymousType
qmlRegisterExtendedType
qmlRegisterExtendedUncreatableType
qmlRegisterlnterface
qmlRegisterModule
qmlRegisterRevision
qmlRegisterSingletonlnstance
qmlRegisterSingletonType
qmlRegisterType
qmlRegisterTypeNotAvailable
qmlRegisterUncreatableMetaObject
amlRegisterUncreatableType
以下这张图分析了如上这些接口在何种情况下使用:
其中我们最常用的是:qmlRegisterType、qmlRegisterModule,
有些不走上面的方式
比如在model/view中,qt5在qml中的TabView没有对应的model,QT6对其支持也很弱,满足不了需求,因此,qml使用view,cpp作为model成了一种很普遍的方式,根据需求,使用
engine.rootContext()->setContextProperty()这种接口来将cpp文件与qml交互效果比较理想,
附上优快云大佬写的网址:
C++ 与 QML 之间进行数据交互的几种方法_qml和c++交互-优快云博客
对于cpp跳过js控制qml控件这种,则提供了另外一些方式:直接从引擎拿到根元素,对根元素进行操作,可以是显示的控件,也可以是数据类型的元素,灵活性非常大,但是在信号与槽函数连接中,由于connect()连接方式必须确定是何种类型发出何种信号,这种方式限制了信号的传递。
auto root = engine.rootObjects();
// findChild 是qml中的objectName名
auto base = root.first()->findChild<QObject *>("label1");
详解每一种类型的具体使用
qmlRegisterAnonymousType
qmlRegisterAnonymousType()
是一个在 Qt Quick 中用于注册匿名 QML 类型的函数。这个函数允许你在运行时动态地注册自定义的 QML 类型,而无需在 C++ 代码中提前声明这些类型。
代码:cpp部分:
class Bar : public QObject
{
Q_OBJECT
Q_PROPERTY(QString baz READ baz WRITE setBaz NOTIFY bazChanged)
public:
Bar() {}
QString baz() const { return mBaz; }
void setBaz(const QString &baz)
{
if (baz == mBaz)
return;
mBaz = baz;
emit bazChanged();
}
signals:
void bazChanged();
private:
QString mBaz;
};
class Foo : public QObject
{
Q_OBJECT
Q_PROPERTY(Bar *bar READ bar CONSTANT FINAL)
public:
Foo() {}
Bar *bar() { return &mBar; }
private:
Bar mBar;
};
注册方式,和qmlRegisterType类型注册一致
qmlRegisterAnonymousType<Bar>("App", 1);
qmlRegisterExtendedType
qmlRegisterExtendedType()
是一个用于在 Qt Quick 中注册扩展 QML 类型的函数。它可以让你将自定义的 C++ 类型注册到 QML 中,以便在 QML 代码中使用这些类型。
T
是要注册的 C++ 类型。uri
是类型的命名空间 URI。majorVersion
和minorVersion
是版本号。qmlName
是在 QML 中使用的类型名称。templateArgs
是可选的模板参数(仅适用于模板类型)
代码演示:
cpp:
// customtype.h
#ifndef CUSTOMTYPE_H
#define CUSTOMTYPE_H
#include <QObject>
class CustomType : public QObject
{
Q_OBJECT
Q_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged)
public:
explicit CustomType(QObject *parent = nullptr);
int value() const;
void setValue(int value);
signals:
void valueChanged();
private:
int m_value;
};
#endif // CUSTOMTYPE_H
//-------------------------------------------------------------------
// customtype.cpp
#include "customtype.h"
CustomType::CustomType(QObject *parent) : QObject(parent), m_value(0)
{}
int CustomType::value() const
{
return m_value;
}
void CustomType::setValue(int value)
{
if (m_value != value) {
m_value = value;
emit valueChanged();
}
}
main函数中注册:
qmlRegisterExtendedType<CustomType>("CustomTypes", 1, 0, "CustomType", "int");
qml
// main.qml
import QtQuick 2.15
import CustomTypes 1.0
Rectangle {
width: 200
height: 200
CustomType {
id: customTypeObject
value: 42
}
Text {
anchors.centerIn: parent
text: "Value: " + customTypeObject.value
}
}
qmlRegisterExtendedUncreatableType
qmlRegisterExtendedUncreatableType()
是 Qt Quick 中用于注册扩展不可创建类型的函数。这种类型通常是一种特殊类型,它不能在 QML 中直接创建,但可以在 C++ 代码中创建并传递给 QML。
这个函数用于注册那些在 QML 中不能被实例化的类型,但可以在 C++ 中创建实例并通过指针传递给 QML。通常,这种类型用于在 QML 中表示一些特定的数据结构或对象,这些对象只能通过 C++ 代码创建,而不是在 QML 中实例化。
uri
是类型所在的命名空间。versionMajor
和versionMinor
是类型的版本号。qmlName
是在 QML 中使用的类型名称。reason
是一个描述,用于说明为什么该类型不可创建。
代码:cpp文件:
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QObject>
class MyExtendedType : public QObject
{
Q_OBJECT
Q_PROPERTY(int value READ value CONSTANT)
public:
MyExtendedType(QObject *parent = nullptr) : QObject(parent), m_value(42) {}
int value() const { return m_value; }
private:
int m_value;
};
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
qmlRegisterExtendedUncreatableType<MyExtendedType>("MyNamespace", 1, 0, "MyExtendedType", "You cannot create MyExtendedType objects from QML.");
QQmlApplicationEngine engine;
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();
}
#include "main.moc"
在这个示例中,我们定义了一个名为 MyExtendedType
的类,它继承自 QObject
。我们使用 qmlRegisterExtendedUncreatableType()
函数将其注册到 QML 中。
在 QML 代码中,我们无法直接实例化 MyExtendedType
,但是我们可以在 C++ 中创建它,并通过指针传递给 QML。这种类型在 QML 中通常用于表示一些数据模型或状态,这些对象只能在 C++ 代码中创建。
qml文件
import QtQuick 2.15
import MyNamespace 1.0
Item {
Component.onCompleted: {
var myObj = Qt.createQmlObject('import MyNamespace 1.0; MyExtendedType {}', parentItem, 'myObj');
console.log(myObj.value);
}
}
qmlRegisterInterface
qmlRegisterInterface()
是一个用于注册 QML 接口类型的函数。接口类型是一种特殊的类型,它定义了一组属性、方法或信号,但没有具体的实现。这些接口类型通常用于描述 QML 中的行为或功能,并且可以被其他 QML 类型实现。
uri
是接口类型所在的命名空间。versionMajor
和versionMinor
是接口类型的版本号。qmlName
是在 QML 中使用的接口类型的名称
cpp代码:
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QObject>
class MyInterface : public QObject
{
Q_OBJECT
public:
virtual ~MyInterface() {}
virtual void doSomething() = 0;
};
class MyImplementation : public MyInterface
{
Q_OBJECT
public:
void doSomething() override {
qDebug() << "MyImplementation is doing something.";
}
};
mian中:
qmlRegisterInterface<MyInterface>("MyNamespace", 1, 0, "MyInterface");
我们定义了一个名为 MyInterface
的接口类,并且使用 qmlRegisterInterface()
函数将其注册到 QML 中。然后,我们定义了一个实现了 MyInterface
接口的类 MyImplementation
。
在 QML 代码中,你可以将 MyInterface
用作其他 QML 类型的基类,并在具体的类型中实现 MyInterface
定义的方法。
qmlRegisterModule
qmlRegisterModule()
函数用于注册一个 QML 模块,使得该模块中的 QML 类型能够在 QML 中被访问和使用。
qml代码
import MyModule 1.0
Rectangle {
width: 100
height: 100
color: "red"
Text {
anchors.centerIn: parent
text: "Hello from MyModule!"
}
}
qmlRegisterType
qmlRegisterType()
是一个用于在 Qt Quick 中注册自定义 QML 类型的函数。通过这个函数,你可以将自定义的 C++ 类型注册到 QML 中,使得你可以在 QML 代码中实例化和使用这些类型
代码cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QObject>
class MyCustomType : public QObject
{
Q_OBJECT
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
public:
MyCustomType(QObject *parent = nullptr) : QObject(parent), m_name("John Doe") {}
QString name() const { return m_name; }
void setName(const QString &name)
{
if (m_name != name) {
m_name = name;
emit nameChanged();
}
}
signals:
void nameChanged();
private:
QString m_name;
};
main中:
qmlRegisterType<MyCustomType>("com.example.customtype", 1, 0, "MyCustomType");
qml中
import QtQuick 2.15
import com.example.customtype 1.0
Item {
MyCustomType {
id: myCustomTypeObject
name: "Alice"
}
Text {
text: myCustomTypeObject.name
}
}
qmlRegisterSingletonType
qmlRegisterSingletonType()
是用于注册单例类型到 QML 的函数。单例类型是指在 QML 中只能创建一个实例的类型。这些类型在整个 QML 应用程序中都是全局可访问的,可以用于共享全局状态、提供全局服务等
url
是单例类型的 QML 文件的 URL。uri
是单例类型所在的命名空间。versionMajor
和versionMinor
是单例类型的版本号。qmlName
是在 QML 中使用的类型名称
cpp代码:
#include <QQmlContext>
#include <QObject>
class MySingletonType : public QObject
{
Q_OBJECT
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
public:
MySingletonType(QObject *parent = nullptr) : QObject(parent), m_name("Singleton Object") {}
QString name() const { return m_name; }
void setName(const QString &name) {
if (m_name != name) {
m_name = name;
emit nameChanged();
}
}
signals:
void nameChanged();
private:
QString m_name;
};
main中:
qmlRegisterSingletonType<MySingletonType>("com.example.singleton", 1, 0, "MySingletonType", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * {
Q_UNUSED(engine)
Q_UNUSED(scriptEngine)
return new MySingletonType();
});
qml中:
import QtQuick 2.15
import com.example.singleton 1.0
Text {
text: MySingletonType.name
}
qmlRegisterUncreatableType
qmlRegisterUncreatableType()
函数用于在 Qt Quick 中注册一个不可创建的类型,也就是说,这种类型在 QML 中不能通过 createComponent()
或者 createObject()
函数来创建实例。通常,这样的类型用于表示一些静态数据或者只能在 C++ 端创建的对象
uri
是类型所在的命名空间。versionMajor
和versionMinor
是类型的版本号。qmlName
是在 QML 中使用的类型名称。reason
是一个描述,用于说明为什么该类型不可创建。
cpp函数
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QObject>
class MyUncreatableType : public QObject
{
Q_OBJECT
Q_PROPERTY(QString reason READ reason CONSTANT)
public:
MyUncreatableType(QObject *parent = nullptr) : QObject(parent) {}
QString reason() const { return m_reason; }
private:
QString m_reason = "This type cannot be created from QML.";
};
main中:
qmlRegisterUncreatableType<MyUncreatableType>("com.example.uncreatable", 1, 0, "MyUncreatableType", "This type cannot be created from QML.");
qml中
在 QML 代码中,你不能像普通类型一样使用 MyUncreatableType
,因为它不能被创建。但是你可以访问它的属性或方法。
附上一个画框中随机点小星星的qml代码
直接当成文件,导入即可
import QtQuick
Item {
anchors.fill: parent
Rectangle {
anchors.fill: parent
color: "lightgray"
MouseArea {
anchors.fill: parent
onClicked: {
// 创建一个 rectangleComponent 定义的组件实例,并将其添加为 parent 元素的子组件
var rectangle = rectangleComponent.createObject(parent)
rectangle.x = mouseX
rectangle.y = mouseY
// [] qt5
// rectangle.x = mouse.x
// rectangle.y = mouse.y
// []
}
}
}
Component {
id: rectangleComponent
Rectangle {
width: 20; height: 20
color: "lightgray"
Canvas {
anchors.fill: parent
onPaint: {
// getContext 获取绘画环境,类似于HTML
var ctx = getContext("2d");
ctx.strokeStyle = "blue";
ctx.lineWidth = 2;
// 中心点
var centerX = width / 2;
var centerY = height / 2;
// 外接圆半径
var radius = Math.min(width, height) / 3;
ctx.beginPath();
for (var i = 0; i < 5; i++) {
// 计算顶点坐标
var theta = i * (Math.PI * 2) / 5 - Math.PI / 10;
var x = centerX + Math.cos(theta) * radius;
var y = centerY + Math.sin(theta) * radius;
if (i === 0) {
ctx.moveTo(x, y);
} else {
ctx.lineTo(x, y);
}
}
ctx.closePath();
ctx.stroke();
}
}
}
}
}
一个GridView的绘制图
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
GridView {
id: gridView
anchors.fill: parent
cellWidth: 100
cellHeight: 100
model: 20
delegate: Item {
width: gridView.cellWidth - 5
height: gridView.cellHeight - 5
Rectangle {
anchors.fill: parent
// color: "lightblue"
border.color: "red"
// Text {
// anchors.centerIn: parent
// text: index
// }
}
// 在第三个项中插入按钮
Button {
visible: index === 2
width: parent.width - 10
height: deviceSize(parent.height)
anchors.centerIn: parent.Center
text: "Button"
onClicked: console.log("Button clicked")
}
function deviceSize(size) {
if (size > 30) {
return 50
} else {
return parent.height
}
}
// 在第六个项中插入下拉框
ComboBox {
visible: index === 5
width: parent.width
height: deviceComboxSize(parent.height)
model: ["Option 1", "Option 2", "Option 3"]
}
function deviceComboxSize(size) {
if (size > 30) {
return 30
} else {
return parent.height
}
}
}
}