注意:这儿暂时不考虑静态插件(潜意识中总觉得它根本就不算插件)。 插件是一个动态库(共享库)。动态库是一个独立的文件中的独立模块,可被多个程序访问。 1. 程序链接时指明动态库 这时程序中包含相应的头文件,编译时指定头文件路径,对于qmake来说: 这样一来,程序启动时会自动加载需要的链接库。 2. 程序中动态加载动态库 运行过程中找到来查找某个动态库,加载并解析出其中的某个函数。 Qt提供了QLibrary这个类来封装各个平台下的差异。 动态加载,那么程序怎么知道去哪儿加载插件呢? 很多人抱怨,装有Qt的机器上一切正常,发布后,jpeg等格式图片看不成,数据库无法连接,汉字乱码... 其实答案很简单: QCoreApplication 的 libraryPaths() 中有一些路径,比如: 然后程序启动后,会去这些路径下的下列子目录 imagesformats 中 找图片插件 sqldrivers 中 找数据库驱动插件 codecs 中 找字符的编解码插件 ... 这就是为什么:将 jpeg4.dll 放到可执行程序所在文件夹的 imagesformats 中即可解决问题的原因。 除此之外,要设置插件路径,我们还可以修改: QCoreApplication::libraryPaths() 通过 addLibraryPath() QLibraryInfo::location(QLibraryInfo::PluginsPath) 通过 qt.conf 文件 QT_PLUGIN_PATH 环境变量 Manual 中对此有详细介绍。 Qt 提供了两个层次的Api Higher-level 用于扩展Qt自身的工程,比如前述的图片插件、编解码插件等等 Lower-level 用于扩展 应用程序的功能,比如 QtCreator 本身用了非常多的专有插件 这部分,插件本身的api很简单,困难在功能实现上。比如实现一个 style 插件: 这两个都没什么好说的,只是一个宏特别关键: 看它的源代码,也是一堆宏,贴出来也不好看 展开看一下: 这样一来舒服多了,导出了两个函数: 这一部分和本文其他部分关系不是太紧密,而且内容可能比较多,还是单独出来准备"插件学习二"吧。 这时它是一个静态库。静态库如何使用?不用多说了,肯定直接链接到程序中。于是我们需要: 对与Qt提供的 higher-level 插件,比如图片插件 jpeg,这意味着: 代码中,(使用宏,也就是使动态编译时它不起作用) #include<QtPlugin> Q_IMPORT_PLUGIN(qjpeg) pro文件内,(指定要链接的库) 当静态编译时,插件中的宏 展开为 同时,工程中的宏 展开为: 这也很容易理解,Q_EXPORT_PLUGIN2(PLUGINNAME, ClassName) 中的第一个参数做什么用了。插件是什么
先看动态库的两种用法
LIBS += -L/path1/path2/.../ -labcd
INCLUDEPATH += /p1/p2/.../插件是提供特定接口的动态库
Qt插件位置
插件API
前面的插件位置提到的主要是这个
higher-level
Q_EXPORT_PLUGIN2(PluginName, ClassName)
# define Q_EXPORT_PLUGIN2(PLUGIN, PLUGINCLASS) /
Q_PLUGIN_VERIFICATION_DATA /
Q_EXTERN_C Q_DECL_EXPORT /
const char * Q_STANDARD_CALL qt_plugin_query_verification_data() /
{ return qt_plugin_verification_data; } /
Q_EXTERN_C Q_DECL_EXPORT QT_PREPEND_NAMESPACE(QObject) * Q_STANDARD_CALL qt_plugin_instance() /
Q_PLUGIN_INSTANCE(PLUGINCLASS)static const char qt_plugin_verification_data[] = /
"pattern=QT_PLUGIN_VERIFICATION_DATA/n" /
"version=4.7.0/ndebug=false/nbuildkey=xxx";
extern "C" Q_DECL_EXPORT const char * qt_plugin_query_verification_data()
{
return qt_plugin_verification_data;
}
extern "C" Q_DECL_EXPORT qt_plugin_instance()
{
static QPointer<QObject> _instance;
if (!_instance)
_instance = new ClassName;
return _instance;
}lower-level
静态插件
静态插件使用
静态插件用到的宏
Q_EXPORT_PLUGIN2(PLUGINNAME, ClassName)
qt_plugin_instance_PLUGINNAME()
{
static QPointer<QObject> _instance;
if (!_instance)
_instance = new ClassName;
return _instance;
}Q_IMPORT_PLUGIN(PluginName)
QObject *qt_plugin_instance_PLUGINNAME();
class StaticPLUGINNAMEPluginInstance
{
public:
StaticPLUGINNAMEPluginInstance()
{
qRegisterStaticPluginInstanceFunction(qt_plugin_instance_PLUGINNAME);
}
};
static StaticPLUGINNAMEPluginInstance staticPLUGINNAMEInstance;