【Qt】通过QtCreator源码学习Qt(四):插件管理PluginManager

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010168781/article/details/84667127
1、简介

QtCreator使用插件架构,方便扩展。它的核心是插件管理,主类是PluginManager。
下面是翻译src\libs\extensionsystem\pluginmanager.cpp中关于插件的一些说明,后续会详细分析插件管理的代码。

2、名字空间、主要类介绍

插件使用的名字空间是namespace:ExtensionSystem:它提供了属于核心插件系统的类。ExtensionSystem包含插件管理器及其支持类,以及必须由插件提供者实现的IPlugin接口。

class ExtensionSystem::PluginManager:主类
PluginManager类实现了核心插件系统,包括对插件本身以及它们的状态、生命周期、注册的对象的管理。

3、插件

插件由XML描述符文件和包含Qt插件的库组成它必须派生自IPlugin类,并且IID为"org.qt-project.Qt.QtCreatorPlugin"。
插件管理器通过路径列表,以搜索插件、检索关于这些插件状态的信息并加载它们。通常,插件管理器只需要一个,因此应用程序中创建一个PluginManager实例并启动加载。
加载插件的步骤:设置插件路径列表、尝试加载所有插件:
PluginManager::setPluginPaths(QStringList(“plugins”));
PluginManager::loadPlugins(); // try to load all the plugins

此外,还可以直接访问插件规范(描述文件中的信息)、插件实例(通过PluginSpec)及其状态。

4、对象池

插件可以将对象添加到位于插件管理器中的公共“池”中。
池中的对象必须派生自QObject,没有其他先决条件。对象可以通过getObject()和getObjectByName()函数从对象池中检索。
当对象池的状态发生变化时,插件管理器就会发出相应的信号。

对象池的一个常见用途是插件(或应用程序)为其他插件提供了一个“扩展点”,这是一个可以实现并添加到对象池中的类/接口。
提供扩展点的插件在对象池中寻找类/接口的实现。
代码实现:
{
// 插件A提供了一个“MimeTypeHandler”扩展点
// 插件B中:
MyMimeTypeHandler *handler = new MyMimeTypeHandler();
PluginManager::instance()->addObject(handler);
// 插件A中:
MimeTypeHandler *mimeHandler = PluginManager::getObject();
}

ExtensionSystem::Invoker类模板为使用“软”扩展点提供了“语法糖”,这些扩展点可能由池中的对象提供,也可能不是。
这种方法既不需要将“用户”插件链接到“提供者”插件,也不需要公共共享头文件。公开的接口是由对象池中“提供者”对象的可调用函数隐式给出的。
代码示例:

{
 // 在“提供”插件A中:
 namespace PluginA {
 class SomeProvider : public QObject
 {
    Q_OBJECT

 public:
    Q_INVOKABLE QString doit(const QString &msg, int n)
    {
        qDebug() << "I AM DOING IT " << msg;
        return QString::number(n);
    }
 };
 } // namespace PluginA


 // 在“使用”插件B中:
 int someFuntionUsingPluginA()
 {
    using namespace ExtensionSystem;

    QObject *target = PluginManager::getObjectByClassName("PluginA::SomeProvider");

    if (target) {
        // 一些随机参数。
        QString msg = "REALLY.";

        // 普通函数调用,没有返回值。
        invoke<void>(target, "doit", msg, 2);
        // 无返回值的普通函数。
        qDebug() << "Result: " << invoke<QString>(target, "doit", msg, 21);

        // 用返回值记录函数调用成功。
        Invoker<QString> in1(target, "doit", msg, 21);
        qDebug() << "Success: (expected)" << in1.wasSuccessful();
        // T尝试调用不存在的函数。
        Invoker<QString> in2(target, "doitWrong", msg, 22);
        qDebug() << "Success (not expected):" << in2.wasSuccessful();

    } else {
        // 必须处理插件A的缺失。
    }
 };
}

注意事项:
传递给invoke()调用的参数的类型是从参数本身推导出来的,并且必须与被调用函数的参数类型匹配。
对象池操作函数是线程安全的。

5、插件函数说明

void PluginManager::objectAdded(QObject *obj):将对象添加到插件池中

void PluginManager::aboutToRemoveObject(QObject *obj):从插件池中删除对象

void PluginManager::pluginsChanged():可用插件列表已更改。

T *PluginManager::getObject():从对象池中检索给定类型的对象。函数使用qobject_cast来确定对象的类型。如果对象池中有多个给定类型的对象,则该函数将任意选择其中一个。

T *PluginManager::getObject(Predicate predicate):从对象池中检索给定类型predicate的对象。这个函数使用qobject_cast来确定对象的类型。predicate必须是接受T *并返回bool的函数。如果有多个对象匹配类型,则该函数将任意选择其中一个。

猜你喜欢

转载自blog.csdn.net/u010168781/article/details/84667127
今日推荐