为萌梦动作编辑器写插件(C++/QML混合插件篇)
-
上次给大家介绍了萌梦动作编辑器是可以支持插件的,同时也简单介绍了制作一个简单的QML插件以便和萌梦动作编辑器结合起来。那么这次我们介绍一下萌梦动作编辑器支持的另外一种插件格式,那就是C++/QML混合插件,以下我们简称混合插件。C++/QML混合插件的介绍
混合插件是萌梦动作编辑器的一种新型的插件格式,它利用C++强大的功能来处理复杂的业务,以便支持QML层,让插件变得更加强大。事实上,萌梦动作编辑器就是由若干个插件组合而成,插件的组合赋予了动作编辑器强大的能力,使其工作起来更有效。
此外,萌梦动作编辑器支持插件之间的相互交互,让数据传递在插件之间变得简单有效。其中的秘诀就是萌梦独家研制的插件模块(名称为:QtDream.Plugin)。下面就让我们来看一个例子吧。
如何使用混合插件
首先请转到这里查看一个混合插件工程。或者在浏览器访问:
https://gitee.com/jiangcaiyang/QtDreamTestNotepadPlugin-master
一个混合插件通常包含以下几个文件
- .qmake.conf # 规定了Qt版本等信息
- 插件名称.pro # 规定了插件名称等信息
- 插件名称Plugin.h
- 插件名称Plugin.cpp # 规定了插件的类型继承自QQmlExtensionPlugin而写的类
- 插件名称plugin.json # json描述插件的一些信息
- 插件名称plugin.qrc # 用来包裹qmldir的qrc文件
- qmldir # 描述了插件的一些信息
此外还有若干qml文件,目的是和萌梦动作编辑器整合起来。
文件看起来很多的样子……但是别慌,我们一点一点来分析,慢慢就会知道其中的用处的。
-
首先是qmldir文件。Qt的定义式语言引擎会读取它然后获取到qml路径的信息。我们的Notepad插件的qmldir内容是这样的:
module QtDream.Notepad Main 0.3 qrc:///QtDream/Notepad/qml/Main.qml NotepadPage 0.3 qrc:///QtDream/Notepad/qml/NotepadPage.qml typeinfo NotepadPlugin.qmltypes depends QtQuick 2.5 depends QtQuick.Controls 1.4 depends QtQuick.Dialog 1.2 depends QtDream.Core 3.3 depends QtDream.Plugin 1.0 depends QtDream.Project 1.0 designersupported plugin qtdreamnotepad classname NotepadPlugin
首先
module
后面跟随的是模块的uri,这里我们写成了QtDream.Notepad
。然后我们需要将主要的QML文件暴露出来啦,所以我们将Main.qml
文件以及版本和路径在此写了出来。同样的我们也需要暴露NotepadPage
这个类。然后呢,为了让qmlplugindump生成类型信息,我还写了typeinfo,并且将此类型信息的名称写在了后面。然后就是一系列依赖的声明了,QtDream.Notepad
依赖QtQuick 2.5、QtQuick.Controls 1.4
等等。最后让其得到Qt Quick设计器的支持,这样就可以在设计器中设计这样的界面了。最后两行则是声明插件的名称以及具体包含插件的名称。一个插件可能包含0个或者更多的plugin
,但是classname这一栏只可能有一个,表示的是包含定义QQmlExtensionPlugin
子类的类的名称。QML引擎就会根据这个名称来读取插件的实现。
-
随后就是
插件名称.pro
文件了,在我们的QtDream.Notepad这个插件中,pro文件可以说是起到了组织的作用。为了以后的插件都兼容Qt和萌梦动作编辑器,我们建议插件的pro文件都按照标准的方式写。比如说QtDream.Notepad文件的内容如下:# notepad.pro QT += qml quick DEFINES += NOTEPAD_LIB OTHER_FILES += notepadplugin.json QMAKE_TARGET_PRODUCT = "QtDream Notepad Module (Qt $$QT_VERSION)" QMAKE_TARGET_DESCRIPTION = "QtDream notepad module, tekes a notepad easily." lupdate_only { SOURCES = qml/*.qml \ qml/*.js } qtHaveModule( qml ) { HEADERS += notepadplugin.h SOURCES += notepadplugin.cpp DISTFILES += qmldir !greaterThan( QT_MINOR_VERSION, 6 ) { RESOURCES += notepadplugin.qrc } CXX_MODULE = dreamnotepad TARGET = qtdreamnotepad TARGETPATH = QtDream/Notepad IMPORT_VERSION = 0.3 load( qml_plugin ) } RESOURCES += notepadassets.qrc # 这些是文档的部分 #QMAKE_DOCS = $$PWD/doc/notepad.qdocconf #OTHER_FILES += $$QMAKE_DOCS doc/src/*.qdoc HEADERS += notepadglobal.h \ notepadio.h SOURCES += notepadglobal.cpp \ notepadio.cpp
书写萌梦动作编辑器的插件pro文件和其它pro文件差别不大,但是要注意的几点是:
QMAKE_TARGET_PRODUCT
和QMAKE_TARGET_DESCRIPTION
是设定插件的名称和插件的描述的属性。以此可以告诉用户插件的作用如何;qtHaveModule( qml ) { }
表示Qt只有包含了qml插件的情况下,才会生成qml插件。!greaterThan( QT_MINOR_VERSION, 6 ) { }
这是兼容Qt 5.6以及之前的Qt版本而设计的方法,通过这个方法,Qt 5.6以及以前的版本无论是否能够静态编译,都能够运行起插件。load( qml_plugin )
表示使用Qt内部spec的函数来载入qml的插件。qml_plugin则代表着要载入qml插件的方法来处理项目。
最后您如果想要为插件生成文档,那么可以取消其中的注释,这样文档也能够顺利的生成了。
-
紧接着介绍的是
notepadplugin.h
和nodepadplugin.cpp
了。这些也是生成一个混合插件必要的文件了。下面是notepadplugin.h
的文件内容:// notepadplugin.h #ifndef NOTEPADPLUGIN_H #define NOTEPADPLUGIN_H #include <QQmlExtensionPlugin> class NotepadPlugin: public QQmlExtensionPlugin { Q_OBJECT Q_PLUGIN_METADATA( IID QQmlExtensionInterface_iid FILE "notepadplugin.json" ) public: NotepadPlugin( QObject* parent = Q_NULLPTR ); void registerTypes( const char* uri ); }; #endif // NOTEPADPLUGIN_H
这个类是继承了
QQmlExtensionPlugin
类,然后覆盖了registerTypes
方法。其中notepadplugin.json
的内容就是文件系统的notepadplugin.json文件。接下来介绍的是notepadplugin.cpp
文件的内容:// notepadplugin.cpp #include <qqml.h> #include <QQmlEngine> #include "notepadplugin.h" #include "notepadio.h" // 注册单例函数 static QObject* NotepadIOCreateCallback( QQmlEngine* qmlEngine, QJSEngine* jsEngine ) { Q_UNUSED( qmlEngine ); Q_UNUSED( jsEngine ); NotepadIO* io = NotepadIO::instance( ); qmlEngine->setObjectOwnership( io, QQmlEngine::CppOwnership ); return io; } NotepadPlugin::NotepadPlugin( QObject* parent ): QQmlExtensionPlugin( parent ) { #if defined( QT_STATIC ) #if QT_VERSION >= QT_VERSION_CHECK( 5, 7, 0 ) Q_INIT_RESOURCE( qmake_QtDream_Notepad ); #else Q_INIT_RESOURCE( notepadplugin ); #endif #endif Q_INIT_RESOURCE( notepadassets );// 所有资源一定要打在一个包中,要不然程序会发现还是找不到相应的资源 } void NotepadPlugin::registerTypes( const char* uri ) { Q_UNUSED( uri ); qmlRegisterSingletonType<NotepadIO>( uri, 0, 2, "NotepadIO", NotepadIOCreateCallback ); }
以上是
NotepadPlugin
类的实现。其中#ifdef #endif的内容表示兼容静态编译以及Qt5.6以及以前的初始化。最后就是注册一个名为NotepadIO
的单例,其中是创建Notepad
类需要的回调。回调的实现不是本文探讨的内容,所以暂且不介绍。
-
最后介绍的是
notepad.json
和.qmake.conf
。其中json文件是可选的,{ "Keys": [ "NotepadPlugin" ], "uri": [ "QtDream.Notepad" ] }
notepad.json包含的是一个简单的字符串,其中包含的是Keys和uri。Keys就是我们的
QQmlExtensionPlugin
子类,而uri则是我们使用qml进行import
时候的的uri。而.qmake.conf则是使用Qt的方式构建必要的文件。它的内容也极其简单。
load(qt_build_config) MODULE_VERSION = 5.10.1
除了第一行载入Qt构建的配置外,还需要设置的就是模块编译时候的版本。这里我们用Qt当前的版本5.10.1。
-
好了,一个包含C++和QML混合插件就介绍完了。不过等下,你们还没有看过效果嘛?很简单,从gitee上下载或者复制项目到本地,进行编译,然后呢,放在和萌梦动作编辑器文件夹中的
qml/QtDream
子文件夹,再在萌梦动作编辑器中设定合适的路径,就可以顺利地载入插件的内容了!
-
@jiangcaiyang 正确使用插件,补充一步,需要将工程下【qmldir】文件拷贝到插件目录
-
@青山白云 谢谢,我做得疏漏了。这方面没有介绍清楚~