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