插件是什么

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

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

先看动态库的两种用法

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. easyui的combobox默认选中第一个选项

    pmProjectSelect.combobox({ editable:false, width:165, url : ctx + '/PmProject/findByProjectMgr', //c ...

  2. 今日js心得

    <input type="hidden" id="history_chart_json" data-json="#{smartDeviceMon ...

  3. Java秒杀实战 (四)JMeter压测

    转自:https://blog.csdn.net/qq_41305266/article/details/81071278. 一.JMeter入门 下载链接 http://jmeter.apache. ...

  4. instanceof解析

    https://www.zhihu.com/question/21574535/answer/18998914 Java instanceof 关键字是如何实现的? 基本理解 只是在同一个类加载器加载 ...

  5. Windows Phone惨遭微软放弃

    微软在电脑操作系统上的用户保有量一直处于遥遥领先的地位,特别是最新的Windows 10系统,一经推出,市场表现就比较好,但相比起来,微软的手机操作系统Windows Phone就被贴上“差等生”的标 ...

  6. linux基础1_文件类型、拓展名、目录配置

    命令ls -l,显示的第一个属性代表了这个档案的档案类型 [d]:目录 [-]:普通文件 [l]:连接文件 [b]:存储数据以供系统访问的接口设备 [c]:串行接口的端口设备,例如键盘.鼠标 [s]: ...

  7. vi和vim的使用

    本章内容: vi编辑器简介 vim基本使用 vim使用技巧 一.vim简介 vim是一个全屏幕纯文本编辑器,是vi编辑器的增强版. 二.vim的基本使用 1.vim的工作模式 命令模式:是主要使用快键 ...

  8. 使用canvas 代码画小猪佩奇

    最近不是小猪佩奇很火嘛!!! 前几天 在知乎 看见了别人大佬用python写的 小猪佩奇,  顿时想学 ,可是 自己 没学过python(自己就好爬爬图片,,,,几个月没用 又丢了) 然后 就想画一个 ...

  9. String、StringBuffer和StringBuilder区别

    String.StringBuffer和StringBuilder区别 1.长度是否可变 String 是被 final 修饰的,他的长度是不可变的,就算调用 String 的concat 方法,那也 ...

  10. zencart单独屏蔽左右边栏代码

    1.屏蔽左栏:打开模板目录下的tpl_main_page.php文件,找到以下代码 if (!isset($flag_disable_left) || !$flag_disable_left) { 在 ...