QML 的 Import语句及自定义类
首先应了解C++类的知识, 环境变量的概念和一点CMake和Javascript语法, 否则下面的解释可能有些难懂
Import语句, 共3种
1.import <ModuleIdentifier> [<Version.Number>] [as <Qualifier>]
例:import QtQuick 2.10 as Quick
这里QtQuick 2.10是一个模块(是一个类与头文件的组合, 后面会讨论),Quick叫做namespace qualifier,用来引用QtQuick 2.10
还可以(这里“textwidgets"看起来应该是一个文件):
import "../textwidgets" as MyModule
2.Directory Imports(也可以导目录)
import "<DirectoryPath>" [as <Qualifier>]
3.JavaScript Resource Imports(javascript文件)
import "<JavaScriptFile>" as <Identifier>
上面例子中直接导入文件,那么这些文件在哪个目录呢?
根据帮助文档: QML Import Path
When an identified module is imported, the QML engine searches the import path for a matching module.
This import path, as returned by QQmlEngine::importPathList(), defines the default locations to be searched by the engine. By default, this list contains:
包括4种情况:
- The directory of the current file
- The location specified by QLibraryInfo::QmlImportsPath
- Paths specified by the QML_IMPORT_PATH environment variable
- The qrc:/qt-project.org/imports path inside the resources.
当标识模块被导入(读取import语句)时,QML引擎会查找匹配的 import路径。
这些import路径可通过QQmlEngine::importPathList()方法返回,默认情况下包括:
- 当前路径;
- QLibraryInfo::QmlImportsPath指定的路径;
- QML_IMPORT_PATH环境变量指定的路径;
- 资源文件中指定的路径:qrc:/qt-project.org/imports
Additional import paths can be added through QQmlEngine::addImportPath() or the QML_IMPORT_PATH environment variable. When running the qml tool, you can also use the -I option to add an import path.
可通过QQmlEngine::addImportPath()方法或QML_IMPORT_PATH环境变量添加路径。当使用qml工具时也可通过 -I 参数添加一个import路径。
查询Qt Assistant得到,QQmlEngine::importPathList()的解释,与上面4点是一致的:
QStringList QQmlEngine::importPathList() const
Returns the list of directories where the engine searches for installed modules in a URL-based directory structure.
For example, if /opt/MyApp/lib/imports is in the path, then QML that imports com.mycompany.Feature will cause the QQmlEngine to look in /opt/MyApp/lib/imports/com/mycompany/Feature/ for the components provided by that module. A qmldir file is required for defining the type version mapping and possibly QML extensions plugins.
By default, the list contains the directory of the application executable, paths specified in the QML_IMPORT_PATH environment variable, and the builtin QmlImportsPath from QLibraryInfo.
You can specify multiple import paths in the QML_IMPORT_PATH environment variable by joining them using the path separator. On Windows the path separator is a semicolon (;), on other platforms it is a colon (:). This means that you cannot specify resource paths or URLs in QML_IMPORT_PATH, as they contain colons themselves. However, you can add resource paths and URLs by calling QQmlEngine::addImportPath() programatically.
路径的问题解决了,那么如何将C++类定义为一个QML对象呢?
参考官方例子:QML 引用C++类实例:https://code.qt.io/cgit/qt/qtdeclarative.git/tree/examples/qml/referenceexamples/adding?h=6.2
首先你应了解C++类的知识,这里定义了一个person类:
#include "person.h"
// ![0]
QString Person::name() const { return m_name; }
void Person::setName(const QString &n) { m_name = n; } ……
然后是头文件,这里的"Q_OBJECT, Q_PROPERTY..."需要一些Qt知识:
#ifndef PERSON_H #define PERSON_H #include <QObject> #include <QtQml/qqml.h> //![0] class Person : public QObject { Q_OBJECT Q_PROPERTY(QString name READ name WRITE setName) Q_PROPERTY(int shoeSize READ shoeSize WRITE setShoeSize) QML_ELEMENT // 定义为QML元素 public: using QObject::QObject; QString name() const; void setName(const QString &); int shoeSize() const; void setShoeSize(int); private: QString m_name; int m_shoeSize = 0; }; //![0] #endif // PERSON_H
根据官方文档:
C++ types are declared using the QML_ELEMENT and QML_NAMED_ELEMENT() macros and registered via the build system using QML_IMPORT_NAME and QML_IMPORT_MAJOR_VERSION. The import name and version given this way form a module that can be imported to access the types.
This is most common in client applications which define their own QML object types in C++.
这里注意QML_ELEMENT, 它指明这个头文件对应的类是一个QML元素。根据帮助文档:原文如下:
QML_ELEMENT:Declares the enclosing type or namespace to be available in QML, using its class or namespace name as the QML element name.
这里说明类名就是QML元素的名称。
NOTE: When classes have the same name but are located in different namespaces using QML_ELEMENT on both of them will cause a conflict. Make sure to use QML_NAMED_ELEMENT() for one of them instead.
如果有多个相同名称的类(处于不同命名空间),则使用QML_NAMED_ELEMENT() 宏来区分不同命名空间的类。
接下来在qml文件中引用它。
准备好了类,说明元素名已经确定了,import后面的模块如何确定呢?比如:
import People 1.0
Person { name: "Bob Jones" shoeSize: 12 }
import这里会报错,说明找不到People这个模块:
这就需要使用构建工具
在CMake中加入:
qt_add_qml_module(adding // 添加目标--工程名 URI People // 类名 VERSION 1.0 QML_FILES example.qml NO_RESOURCE_TARGET_PATH )
编译一次就没有问题了。
原理:
https://doc.qt.io/qt-6/qtqml-syntax-imports.html
QML 引用C++类实例:https://code.qt.io/cgit/qt/qtdeclarative.git/tree/examples/qml/referenceexamples/adding?h=6.2