本系列所有文章可以在这里查看[http://blog.csdn.net/cloud_castle/article/category/2123873](http://blog.csdn.net/cloud_castle/article/category/2123873) 接上文[Qt5官方demo解析集19——Chapter 5: Using List Property Types](http://blog.csdn.net/cloud_castle/article/details/36898495) 在前文中我们定义的PieChart和PieSlice这两个自定义QML类型只用来供app.qml文件使用,如果希望我们所定义的类型可以被多个qml使用,那么可以将其创建为可扩展的插件。由于是将C++定义的类创建为供QML使用的插件,所以这与我们原先创建C++的插件略有不同。 1、首先我们需要继承QQmlExtensionPlugin类,这是一个抽象基类,提供了可供QML装载的插件。 2、接着我们需要在其子类中使用Q_PLUGIN_METADATA宏将其这个插件注册到Qt的元对象系统中。 3、重写纯虚函数registerTypes(),并在其中使用qmlRegisterType()注册插件中的QML类型,这与我们之前在main函数中做的一样。 4、然后我们需要编写一个插件的工程文件,包括TEMPLATE、CONFIG、DESTDIR、TARGET等等。 5、最后,我们还需要创建一个qmldir文件来描述这个插件。 先看下工程目录,其中piechart与pieslice并没有任何变化: ![](https://box.kancloud.cn/2016-01-18_569cbd07e93e5.jpg) 这实际上是两个工程,我们完全可以单独编译import来生成dll插件,然后放在合适的地方供app工程使用。我们先来看import工程中的文件 chartsplugin.h: ~~~ #ifndef CHARTSPLUGIN_H #define CHARTSPLUGIN_H //![0] #include <QQmlExtensionPlugin> class ChartsPlugin : public QQmlExtensionPlugin // 继承QQmlExtensionPlugin { Q_OBJECT Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") // 为这个插件定义了一个唯一的接口,并注册至元对象系统 public: void registerTypes(const char *uri); // 注册类型函数重载 }; //![0] #endif ~~~ chartsplugin.cpp: ~~~ #include "chartsplugin.h" //![0] #include "piechart.h" #include "pieslice.h" #include <qqml.h> void ChartsPlugin::registerTypes(const char *uri) // 实现插件中类型的注册 { qmlRegisterType<PieChart>(uri, 1, 0, "PieChart"); qmlRegisterType<PieSlice>(uri, 1, 0, "PieSlice"); } //![0] ~~~ 可以看到QML插件注册的代码也很间断,但真正的实现还在于下面两个文件: qmldir这个文件只有两句话: ~~~ module Charts // 定义了组件名称空间为Charts,这个名称也是我们最后import时使用的 plugin chartsplugin // 定义插件,与上面的chartsplugin一致 ~~~ 然后是我们的import.pro文件: ~~~ TEMPLATE = lib // 生成库文件 CONFIG += plugin // 该库是一个插件 QT += qml quick DESTDIR = ../Charts // 从Debug目录跳出到Build目录,并建立Charts目录,以存放dll与qmldir文件 TARGET = $$qtLibraryTarget(chartsplugin) HEADERS += piechart.h \ pieslice.h \ chartsplugin.h SOURCES += piechart.cpp \ pieslice.cpp \ chartsplugin.cpp DESTPATH=$$[QT_INSTALL_EXAMPLES]/qml/tutorials/extending/chapter6-plugins/Charts // 设置了一个变量指向这个Charts目录 target.path=$$DESTPATH qmldir.files=$$PWD/qmldir qmldir.path=$$DESTPATH INSTALLS += target qmldir OTHER_FILES += qmldir # Copy the qmldir file to the same folder as the plugin binary QMAKE_POST_LINK += $$QMAKE_COPY $$replace($$list($$quote($$PWD/qmldir) $$DESTDIR), /, $$QMAKE_DIR_SEP) ~~~ 这样,在这个工程编译后,我们将在build目录中的Charts文件夹中找到我们的chartsplugind.dll与qmldir文件。d表示由debug编译产生。 接下来的app项目调用了这个插件并绘制了这个饼状图: app.qml: ~~~ import QtQuick 2.0 import Charts 1.0 // 这里会有一条红色波浪线,QtCreator会抱怨可能找不到这个模块 // 你可以不管它,也可以设置qmlplugindump让QtQuick获知到这个模块的信息 Item { width: 300; height: 200 PieChart { // 我们可以像前面的例子一样使用我们自定义的类型 anchors.centerIn: parent width: 100; height: 100 slices: [ PieSlice { anchors.fill: parent color: "red" fromAngle: 0; angleSpan: 110 }, PieSlice { anchors.fill: parent color: "black" fromAngle: 110; angleSpan: 50 }, PieSlice { anchors.fill: parent color: "blue" fromAngle: 160; angleSpan: 100 } ] } } ~~~ main.cpp中不需要做额外的工作: ~~~ #include <QtQuick/QQuickView> #include <QGuiApplication> int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); QQuickView view; view.setResizeMode(QQuickView::SizeRootObjectToView); view.setSource(QUrl("qrc:///app.qml")); view.show(); return app.exec(); } ~~~ app.pro: ~~~ TARGET = chapter6-plugins // 设置项目名 QT += qml quick # Avoid going to debug/release subdirectory # so that our application will see the # import path for the Charts module. win32: DESTDIR = ./ // 这一句将程序从debug移到上级build目录,也就是Charts的同级目录,这样使得程序可以到上面生成的插件 SOURCES += main.cpp RESOURCES += app.qrc ~~~ 最后还有一个根工程文件chapter6-plugins.pro: ~~~ TEMPLATE = subdirs // 编译下面SUBDIRS定义的子目录 CONFIG += ordered // 顺序编译,可能是基于效率不太被推荐,不过在这个小例子中就无所谓了 SUBDIRS = \ import \ // 先编译import目录里的工程 app.pro // 然后编译app工程 ~~~ 最后还是看下效果呗~ ![](https://box.kancloud.cn/2016-01-18_569cbd0802ab6.jpg)