什么对象可以暴露出来?
插件可以暴露任何对象。一般地,我们会把有可能被其它插件使用到的一些提供某些功能的对象暴露出来。在 Qt Creator 中,这种功能的定义通常使用接口。下面是其中一些接口:
Core::INavigationWidgetFactory
Core::IEditor
Core::IOptionsPage
Core::IOutputPane
Core::IWizard
C++ 开发者通常会将只包含 public 纯虚函数的类当做接口。在 Qt Creator 中,接口则是拥有一个或多个纯虚函数的 QObject 子类。
如果一个插件有实现了这样的接口的对象,那么这个对象就应该被暴露出来。例如,一个插件中的某个类实现了INavigationWidgetFactory
接口,并且暴露出来,那么 Core 就会自动把这个类提供的组件当做导航组件显示出来。来看一下下面的代码:我们通过实现 Core::INavigationWidgetFactory
将一个简单的QTableWidget
当做导航组件。
NavWidgetFactory.h
#ifndef NAVWIDGETFACTORY_H #define NAVWIDGETFACTORY_H #include <coreplugin/inavigationwidgetfactory.h> class NavWidgetFactory : public Core::INavigationWidgetFactory { public: NavWidgetFactory(); ~NavWidgetFactory(); Core::NavigationView createWidget(); QString displayName() const; int priority() const; QString id() const; }; #endif // NAVWIDGETFACTORY_H
NavWidgetFactory.cpp
#include "NavWidgetFactory.h" #include <QtGui> NavWidgetFactory::NavWidgetFactory() { } NavWidgetFactory::~NavWidgetFactory() { } Core::NavigationView NavWidgetFactory::createWidget() { Core::NavigationView view; view.widget = new QTableWidget(50, 3); return view; } QString NavWidgetFactory::displayName() const { return "Spreadsheet"; } int NavWidgetFactory::priority() const { return 0; } QString NavWidgetFactory::id() const { return "Spreedsheet"; }
TableNav.h
#ifndef TABLENAVPLUGIN_H #define TABLENAVPLUGIN_H #include <extensionsystem/iplugin.h> class TableNavPlugin : public ExtensionSystem::IPlugin { public: TableNavPlugin(); ~TableNavPlugin(); void extensionsInitialized(); bool initialize(const QStringList & arguments, QString * errorString); void shutdown(); }; #endif // TABLENAVPLUGIN_H
TableNav.cpp
#include "TableNav.h" #include "NavWidgetFactory.h" #include <QtPlugin> #include <QtGui> TableNavPlugin::TableNavPlugin() { // Do nothing } TableNavPlugin::~TableNavPlugin() { // Do notning } bool TableNavPlugin::initialize(const QStringList& args, QString *errMsg) { Q_UNUSED(args); Q_UNUSED(errMsg); // Provide a navigation widget factory. // Qt Creator’s navigation widget will automatically // hook to our INavigationWidgetFactory implementation, which // is the NavWidgetFactory class, and show the QTableWidget // created by it in the navigation panel. addAutoReleasedObject(new NavWidgetFactory); return true; } void TableNavPlugin::extensionsInitialized() { // Do nothing } void TableNavPlugin::shutdown() { // Do nothing } Q_EXPORT_PLUGIN(TableNavPlugin)
我们修改下 .pro 和 .pluginspec 文件,编译之后运行一下 Qt Creator。注意,在左侧的编译面板中,我们可以在下拉框中找到 Spreadsheet 一项,点击这一项,就可以看到我们创建的新的 table 导航:
监控暴露对象
当使用PluginManager::addObject()
添加对象的时候,PluginManager
就会发出objectAdded(QObject*)
信号。我们的应用程序可以使用这个信号来处理被添加的对象。
显然,只有当插件建立了连接之后,它才能接收信号。这需要在插件初始化之后,也就是说,只有插件初始化之后被添加的对象发出的objectAdded()
信号,才能够被插件接收到。
通常,连接到objectAdded()
信号的 slot 会寻找一个或多个已知接口。假设你的插件要找的是INavigationWidgetFactory
接口,那么就应该使用类似下面的代码:
void Plugin::slotObjectAdded(QObject * obj) { INavigationWidgetFactory *factory = Aggregation::query(obj); if(factory) { // use it here... } }
查找对象
有时候,插件需要查找提供其他功能的对象。现在我们已经知道:
PluginManager::allObjects()
以QList<QObject*>
的形式返回一个对象池;- 通过连接
PluginManager::objectAdded()
信号,可以让我们知道有对象被暴露出来。
使用上面提到的函数,我们就可以查找对象。现在,我们再来介绍另外一种查找对象的方式。
假设我们需要查找一个实现了INavigationWidgetFactory
接口的对象,然后把它添加到一个QListWidget
中显示出来。那么,我们可以使用PluginManager::getObjects<T>()
函数。下面是代码片段:
ExtensionSystem::PluginManager* pm = ExtensionSystem::PluginManager::instance(); QList<Core::INavigationWidgetFactory*> objects = pm->getObjects<Core::INavigationWidgetFactory>(); QListWidget* listWidget = new QListWidget(); Q_FOREACH(Core::INavigationWidgetFactory* obj, objects) { QString objInfo = QString("%1 (%2)") .arg(obj->displayName()) .arg(obj->metaObject()->className()); listWidget->addItem(objInfo); }
我们可以发现,在我们的 list 中显示出来的顺序,和导航下拉框中的显示顺序不一定一致:
附件下载:TableNav 插件文件