插件内容(Plugin Content)

插件是一个已定义接口的库,它只在需要时才被加载。这与一个库在程序启动时被链接和加载不同。在QML场景下,这个接口叫做QQmlExtensionPlugin。我们关心其中的两个方法initializeEngine()registerTypes()。当插件被加载时,首先会调用initializeEngine(),它允许我们访问引擎将插件对象暴露给根上下文。大多数时候你只会使用到registerTypes()方法。它允许你注册你自定义的QML类型到引擎提供的地址上。

我们稍微退一步考虑一个潜在的文件IO类型,它允许我们在QML中读取/写入一个小型文本文件。第一次的迭代可能看起来像在嘲笑QML的实现。

// FileIO.qml (good)
QtObject {
    function write(path, text) {};
    function read(path) { return "TEXT"}
}

这是一个纯粹的qml可能的实现,C++基于QML编程接口来探索一些编程接口。我们看到我们有一个读取和写入函数。写入函数需要一个路径和一个文本,读取函数需要一个路径,返回一个文本。路径和文本看起来是公共参数,或许我们可以将它们提取作为属性。

// FileIO.qml (better)
QtObject {
    property url source
    property string text
    function write() { // open file and write text };
    function read() { // read file and assign to text };
}

当然这看起来更像一个QML编程接口。我们使用属性让我们的环境能够绑定我们的属性并且响应变化。

在C++中创建这个编程接口我们需要创建类似的一个接口。

class FileIO : public QObject {
    ...
    Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
    Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)
    ...
public:
    Q_INVOKABLE void read();
    Q_INVOKABLE void write();
    ...
}

QML引擎需要注册FileIO类型。我们想要在org.example.io模块中使用它。

import org.example.io 1.0

FileIO {
}

一个插件可以在相同的模块中暴露若干个类型。但是不能从一个插件中暴露若干个模块。所以模块与插件之间的关系是一对一的。这个关系由模块标识符表示。