Qt的源码中通过 Q<pluginType>Factory、Q<pluginType>Plugin 和 Q<pluginType> 这三个类实现了Qt的插件加载机制,
这个机制可用于加载特定种类的插件。比如通过 QPlatformIntegrationFactory\QPlatformIntegrationPlugin\QPlatformIntegration
class Q<pluginType>Plugin { ... Q<pluginType> * creat(...) ; // 返回一个Q<pluginType>类型的指针,这个函数的功能一般都非常简单, // 其内部只需要 new 一个 Q<pluginName> 类的对象,并返回其指针 }
QFactoryLoader::QObject *instance(int index)
template <class PluginInterface, class FactoryInterface> PluginInterface *qLoadPlugin(const QFactoryLoader *loader, const QString &key) { const int index = loader->indexOf(key); // 根据插件的关键字查找该插件所属的库在库列表中的索引 if (index != -1) { QObject *factoryObject = loader->instance(index); // 加载插件所属的库 if (FactoryInterface *factory = qobject_cast<FactoryInterface *>(factoryObject)) if (PluginInterface *result = factory->create(key)) return result; // 返回插件的实体类 } return 0; } template <class PluginInterface, class FactoryInterface, class Parameter1> PluginInterface *qLoadPlugin1(const QFactoryLoader *loader, const QString &key, const Parameter1 ¶meter1) { const int index = loader->indexOf(key); if (index != -1) { QObject *factoryObject = loader->instance(index); if (FactoryInterface *factory = qobject_cast<FactoryInterface *>(factoryObject)) if (PluginInterface *result = factory->create(key, parameter1)) return result; } return 0; }
class Q<pluginType>Factory { public: static QStringList keys(...) ; // 获得与 Q<pluginType> 类型的插件相关的关键字列表, // 关键字一般用于描述插件的名称等属性,这个关键字列表中的每个 // 元素都对应一个实际的插件。如 QPlatformInputContextFactory::keys(...) // 返回的就是输入法插件的名称列表。 static Q<pluginType> * creat(...) ; // 返回一个Q<pluginType>类型的指针(应用程序所需的插件) }
需要一个输入法插件了,就会直接调用 QPlatformInputContextFactory::creat(...) 来生产一个输入法类插件,而不用再管这个插件加载过程中的细节。
返回的这个输入法类插件到底是什么,是ibus? 还是fcitx? 这些完全由用户通过环境变量QT_IM_MODULE指定,
QPlatformInputContextFactory::create()方法中会去检测这个环境变量。
static QPlatformIntegration *platform_integration; static QPlatformIntegration *platformIntegration() { return platform_integration; }
GuiApplicationPrivate::platform_integration = QPlatformIntegrationFactory::create(name, arguments, argc, argv, platformPluginPath); ....
QPlatformIntegration *ret = loadIntegration(directLoader(), platform, paramList, argc, argv))
static inline QPlatformIntegration *loadIntegration(QFactoryLoader *loader, const QString &key, const QStringList ¶meters, int &argc, char ** argv) { const int index = loader->indexOf(key); if (index != -1) { // factory 指向对应的平台插件类的实例,如QLinuxFbIntegrationPlugin类; // 接着调用其creat方法生成并返回一个 QPlatformIntegration 类的实例的指针, // 这个指针将最终赋值给 QGuiApplicationPrivate::platform_integration, // 应用程序就得到了自己的运行平台. // 同时由此可知,如果想自己写一个QPA平台插件,只需派生一个QPlatformIntegrationPlugin类和一个QPlatformIntegration类即可。 if (QPlatformIntegrationPlugin *factory = qobject_cast<QPlatformIntegrationPlugin *>(loader->instance(index))) if (QPlatformIntegration *result = factory->create(key, parameters, argc, argv)) return result; } return 0; }
QPlatformInputContext *QPlatformInputContextFactory::create() { QPlatformInputContext *ic = 0; QString icString = QString::fromLatin1(qgetenv("QT_IM_MODULE")); // 检测环境变量QT_IM_MODULE,根据它选择要加载的输入法插件 if (icString == QLatin1String("none")) return 0; ic = create(icString); // 调用另一个create函数加载输入法插件 if (ic && ic->isValid()) return ic; // 下面的代码暂不理会 delete ic; ic = 0; QStringList k = keys(); for (int i = 0; i < k.size(); ++i) { if (k.at(i) == icString) continue; ic = create(k.at(i)); if (ic && ic->isValid()) return ic; delete ic; ic = 0; } return 0; } QPlatformInputContext *QPlatformInputContextFactory::create(const QString& key) { QStringList paramList = key.split(QLatin1Char(':')); const QString platform = paramList.takeFirst().toLower(); #if !defined(QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) if (QPlatformInputContext *ret = qLoadPlugin1<QPlatformInputContext, QPlatformInputContextPlugin>(loader(), platform, paramList)) // 根据key(插件名称)来加载对应的库并实例化(产生一个QPlatformInputContext类型的指针)。 return ret; #endif return 0; }
Qt中能加载库或插件的几个类:
QLibrary ,
QPluginLoader ,
QFactoryLoader ,
QStaticPlugin (暂时不研究这个)
QLibrary 和 QPluginLoader 依赖的‘私有数据类‘都是 QLibraryPrivate, 一个QLibrary或QPluginLoader的对象都有一个QLibraryPrivate对象,对应一个库或插件;
QFactoryLoader 依赖的‘私有数据类‘是 QFactoryLoaderPrivate , 但 QFactoryLoaderPrivate 类中又包含了一个QLibraryPrivate列表,这个列表中有多个
QLibraryPrivate类型的元素,对应一系列的库或插件;
所以可见,QLibraryPrivate是Qt中与库或插件相关的核心数据类,每个库都对应一个QLibraryPrivate对象。
<2>
1. Qt Assistant 中搜索 How to Create Qt Plugins ,这一段详细说明了创建插件的方法。
主要有高级和低级两种API可以用来写插件。
高级API的使用方法可以在Qt源码中看到很多实例。低级API的使用示例在本系列文章的最后给出。
2. 如果不会写插件的 .pro 文件,可以在Qt Assistant 中搜索 qmake Manual , 这一页里有很多链接是与编写工程文件相关的,如
qmake Language 链接讲 .pro 文件的语法,Variables 链接讲.pro 文件中的变量(如QT、CONFIG、TEMPLATE等变量),
Replace Functions 和 Replace Functions 链接讲一些内建的函数(可以在.pro文件中使用)
原文地址:http://blog.csdn.net/newthinker_wei/article/details/41291811