插件是什么

  • 注意:这儿暂时不考虑静态插件(潜意识中总觉得它根本就不算插件)。

插件是一个动态库(共享库)。动态库是一个独立的文件中的独立模块,可被多个程序访问。

先看动态库的两种用法

1. 程序链接时指明动态库

这时程序中包含相应的头文件,编译时指定头文件路径,对于qmake来说:

LIBS += -L/path1/path2/.../ -labcd
INCLUDEPATH += /p1/p2/.../

这样一来,程序启动时会自动加载需要的链接库。

2. 程序中动态加载动态库

运行过程中找到来查找某个动态库,加载并解析出其中的某个函数。 Qt提供了QLibrary这个类来封装各个平台下的差异。

插件是提供特定接口的动态库

  • 它是动态库
  • 它需要一个或几个特定的接口(这样程序才能感知它)
  • 它采用第二种加载方式
  • Qt 为插件提供了 QPluginLoader,比通用 QLibrary 好用

Qt插件位置

动态加载,那么程序怎么知道去哪儿加载插件呢?

很多人抱怨,装有Qt的机器上一切正常,发布后,jpeg等格式图片看不成,数据库无法连接,汉字乱码...

其实答案很简单:

QCoreApplication 的 libraryPaths() 中有一些路径,比如:

  • $QTDIR/plugins
  • 可执行程序所在文件夹

然后程序启动后,会去这些路径下的下列子目录

  • imagesformats

    中 找图片插件

    sqldrivers

    中 找数据库驱动插件

    codecs

    中 找字符的编解码插件

    ...

这就是为什么:将 jpeg4.dll 放到可执行程序所在文件夹的 imagesformats 中即可解决问题的原因。

除此之外,要设置插件路径,我们还可以修改:

QCoreApplication::libraryPaths()

通过 addLibraryPath()

QLibraryInfo::location(QLibraryInfo::PluginsPath)

通过 qt.conf 文件

QT_PLUGIN_PATH

环境变量

Manual 中对此有详细介绍。有关插件路径问题,请考虑 http://blog.csdn.net/dbzhang800/archive/2011/06/14/6543489.aspx

插件API

Qt 提供了两个层次的Api

Higher-level

用于扩展Qt自身的工程,比如前述的图片插件、编解码插件等等
前面的插件位置提到的主要是这个

Lower-level

用于扩展 应用程序的功能,比如 QtCreator 本身用了非常多的专有插件

higher-level

这部分,插件本身的api很简单,困难在功能实现上。比如实现一个 style 插件:

  • 派生 QStyle 或它的子类,实现自己的 Style 类(难点)
  • 派生 QStylePlugin,实现插件,在它内部创建 Style 的对象

这两个都没什么好说的,只是一个宏特别关键:

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;
}

这样一来舒服多了,导出了两个函数:

  • 一个返回值是一个长长的字符串,用来校验差价和程序所用Qt版本什么的是否匹配
  • 另一个返回的是插件类的对象,这样通过该函数就可以使用插件了。

lower-level

这一部分和本文其他部分关系不是太紧密,而且内容可能比较多,还是单独出来准备"插件学习二"吧。

  • 不像图片插件、数据库插件等,Qt为他们提供了现成的接口。这儿我们必须实现自己的接口(别人也不清楚我们的需求,对吧)

静态插件

  • 这个东西怎么说呢,尽管静态编译过Qt,但基本没用过。所以在这静态插件上面应该更没有什么发言权。
  • 熟悉Qt静态编译的,应该对此更熟一些,因为这是插件都是静态的。

静态插件使用

这时它是一个静态库。静态库如何使用?不用多说了,肯定直接链接到程序中。于是我们需要:

  • 包含头文件
  • 指定链接库

对与Qt提供的 higher-level 插件,比如图片插件 jpeg,这意味着:

代码中,(使用宏,也就是使动态编译时它不起作用)

  • #include<QtPlugin>

  • Q_IMPORT_PLUGIN(qjpeg)

pro文件内,(指定要链接的库)

  • QTPLUGIN += qjpeg

静态插件用到的宏

当静态编译时,插件中的宏

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;

这也很容易理解,Q_EXPORT_PLUGIN2(PLUGINNAME, ClassName) 中的第一个参数做什么用了。

参考

Qt 插件学习(一)的更多相关文章

  1. 收藏的博客 -- Qt/C++学习

    Qt Creator环境: 使用Qt Creator作为Linux IDE,代替Vim:实现两台Linux电脑远程部署和调试(一台电脑有桌面系统,一台电脑无桌面系统) 使用Qt Creator作为Li ...

  2. Qt WebKit 学习的说明

    (转自:http://it.100xuexi.com/view/otdetail/20120827/4021c662-b917-44d9-8284-910cac713c23.html) QT Webk ...

  3. uexQQ插件学习心得

    uexQQ插件学习心得 uexQQ插件的作用:通过qq可以分享图文,音乐,应用到相应的qq空间.支持手机客户端分享和手机webQQ分享.下面我们就来看一看他的一些方法. 我们先说一下分享的步骤,这个步 ...

  4. VS2010,Qt插件安装使用

    用了几次的QtCreateor,不习惯. 果断换回VS 基本步骤: 1.安装VS2010 2.安装Qt Creator5 3.安装Qt插件 qt-vs-addin-1.2.2-opensource 就 ...

  5. emmet插件学习,练习中遇到一些问题

    emmet插件学习:帮助提高敲代码效率的插件 参考文献:Emmet(Zen coding)HTML代码使用技巧七则http://www.wzsky.net/html/Website/htmlcss/1 ...

  6. bootstrap插件学习

    转自http://v3.bootcss.com/javascript/ bootstrap javascript插件学习 模态框 打开模态框 <button type="button& ...

  7. Qt的学习资料比起其它C/C++的GUI组件来说已经算很全的了

    Qt的学习资料比起其它C/C++的GUI组件来说已经算很全的了.Google的话能解决很多问题,如果没搜到资料的话,如果不是问题太过具体或者奇葩,那就是搜索方法的问题.中文教程中,Qt学习之路系列很不 ...

  8. [转] Qt 多线程学习

    Qt 多线程学习 转自:http://www.cnblogs.com/IT-BOY/p/3544220.html 最近的项目上用到了关于多线程的知识,自己也比较感兴趣,所以就拿了那本<C++ G ...

  9. Jquery插件学习

    前端开发也工作了一段时间,Jquery代码页写了很多,但是都是些的很零散的,不是很好用,网上看了很多人写的Jquery 很好用,而且到每个项目中都可以使用, 本人就感觉很好奇他们是怎么做到的呢,于是自 ...

随机推荐

  1. extension(类扩展)和 category(类别)

    extension(类扩展) 简单来说,extension在.m文件中添加,所以其权限为private,所以只能拿到源码的类添加extension.另外extension是编译时决议,和interfa ...

  2. Golang之初探

    什么是Go语言 Go语言介绍 产生背景: 超级复杂的C++11特性的吹捧报告的鄙视以及最终的目标是具备动态语言的开发速度的同时并要有C/C++编译语言的性能与安全性以及设计网络和多核时代的C语言 Go ...

  3. Celery 初步使用心得

    一. 基本介绍 Celery是一个专注于实时处理和任务调度的分布式任务队列.所谓任务就是消息,消息中的有效载荷中包含要执行任务需要的全部数据. 使用Celery常见场景: Web应用.当用户触发的一个 ...

  4. 关于pycharm database查看db.sqlites文件提示:Driver class 'org.sqlite.JDBC' not found

    系统重新安装后,启动pycharm存在各种问题,其中一个问题就是在Pycharm中的database里面不能查看sqlite数据库了: 经过一番查找终于找到了问题: 首先问题 是提示这样一个报错: 解 ...

  5. Linux--查询文件的第几行到第几行命令

    cat catalina.out | tail -n +14000 | head -n 10000 | sort | uniq -c linux 如何显示一个文件的某几行(中间几行)[一]从第3000 ...

  6. socket 多线程安全、粘包问题

    脚本如下: # -*- coding:utf-8 -*- ''' @Author: Stefan @File: server_listener.py @Date: 2016-11-09 If you ...

  7. Windows&Appium&Python自动化测试-环境搭建之安卓SDK

    一.摘要 本博文将详细讲述在Windows环境下的jdk安装.配置以及环境校验:安卓sdk安装.配置以及环境校验 二.安装包工具准备: jdk1.8.0(64 位) installer_r24.4.1 ...

  8. linux基础_用户管理

    1.创建用户 基本语法 创建用户:useradd [选项] 用户名 (1)当传教用户成功后,会自动的创建和用户名同名的家目录. (2)也可以通过useradd -d 指定目录 新用户名,给新创建的用户 ...

  9. python_列表方法

    1.在列表后面追加元素 user = [] while True: name = input("输入名字:") # 在列表后面追加元素 user.append(name) prin ...

  10. 一段有关线搜索的从python到matlab的代码

    在Udacity上很多关于机器学习的课程几乎都是基于python语言的,博主“ttang”的博文“重新发现梯度下降法——backtracking line search”里对回溯线搜索的算法实现也是用 ...