使用低级的api:扩展Qt的应用程序
不仅仅是Qt 本身,Qt的应用程序也可以通过plugins来扩展。这个就要求应用程序来探测和加载插件通过QPluginLoader.在这个前提下, 插件可以提供任意的函数,就不会局限于database drivers, image formats, text codecs, styles, 和一些其他可以扩展Qt功能类型的插件。
制作应用程序插件的扩展可以通过如下的步骤:
- 定义接口的集合(类的纯虚函数)跟随这个插件plugins.
- 使用这个Q_DECLARE_INTERFACE()宏来告诉Qt的元对象系统关于这个接口。
- 使用QPluginLoader在应用程序中来加载这些插件.
- 使用qobject_cast()来告诉插件实现给定的接口。
- 声明一个插件类继承自QObject,或者从这个插件想提供的接口;
- 使用Q_INTERFACE()宏来告诉Qt的元对象系统关于这个这个插件;
- 导出这个插件通过使用Q_PLUGIN_METADATA()宏;
- 编译插件通过使用合适的.pro 文件。
class FilterInterface { public: virtual ~FilterInterface() {} virtual QStringList filters() const = 0; virtual QImage filterImage(const QString &filter, const QImage &image, QWidget *parent) = 0; };
#include <QObject>
#include <QtPlugin>
#include <QStringList>
#include <QImage>
#include <plugandpaint/interfaces.h>
class ExtraFiltersPlugin : public QObject, public FilterInterface
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.Examples.PlugAndPaint.FilterInterface" FILE "extrafilters.json")
Q_INTERFACES(FilterInterface)
public:
QStringList filters() const;
QImage filterImage(const QString &filter, const QImage &image,
QWidget *parent);
};
Plug&Paint的例子文档解释了这个过程的细节。查看Creating Custom Widgets for Qt Designer 获取一些关于Qt Designer的特定的问题的细节。你也可以看下Echo Plugin Example查看如何实现扩展一个Qt application的插件的实现的更详细过程。注意QCoreApplication必须在插件加载之前就已经初始化过了。
定位插件
Qt application将会自动感知可获取的插件,因为插件都被存储在标准的子目录当中。因此引用程序不需要任何查找或者加载插件的代码。
在开发过程中, 插件的目录是 QTDIR/plugins(而QTDIR就是Qt所在的安装目录),每个类型的插件放在这个类型的子目录下面。例如,styles. 如果你想要你的应用程序使用插件,而你不想用标准的插件存放路径,那你的安装过程就决定了你想要使用插件的路径,例如,使用QSettings, 应用程序就需要在运行时读取设置文件。application可以通过QCoreApplication::addLibraryPath()来获取你所定义的应用程序要用到的插件。
注意:最后部分的路径(例如,styles)是不会改变的。
如果你想这个插件是可以被加载的,其中一个方式就是在这个应用程序下面创建子目录,并将插件放在这个目录中。如果你想用Qt分布任意的插件(就是可以将插件存储在本地目录),你必须拷贝这个插件下的子目录,当这个插件位于应用程序的根目录下(也就是说,不包括plugins的目录)。
查看更多的开发的信息,查看Deploying Qt Applications 和Deploying Plugins的文档。
静态插件
应用程序使用插件的最灵活和普遍的方式就是通过动态库,单独使用,独立的查找和实时加载。
Plugins也可以静态链接到你的程序中,如果你编译Qt的静态版本,这是包含Qt的预定义的插件的唯一选择。使用静态插件使用开发可以插件部署更少的出错,但是这种方式同样有缺点,就是没有办法加载功能插件,包括不能完整的重编译和重新部署的应用程序。
为了静态连接插件,你可以通过使用QTPLUGIN加载需要的plugins到你的编译中。
在.pro文件中,你需要如下的条目:
QTPLUGIN += qjpeg \
qgif \
qkrcodecs
qmake将会自动加载这些插件到QTPLUGIN,他们通常将被Qt modules使用(see QT), 同时,更多特定的插件将被手动添加。这个默认被自动添加的插件将被每个类型自动重载。例如,连接最小的插件而不是默认Qt平台移植的插件,通过:
QTPLUGIN.platforms = qminimal
如果你既不想使用默认插件,也不想使用最小的QPA plugin被自动连接,使用:
QTPLUGIN.platforms = -
默认值被调到一个开箱即用的最佳情况,但是可能使程序变臃肿。推荐使用命令行检查,用qmale编译,消除一些不必要的插件。
链接静态插件的细节
为了静态插件被真实的链接和实例化,Q_IMPORT_PLUGIN() 宏需要在application的代码中使用,但是他们也是通过qmake自动编译产生并添加到你的程序中的。
如果你不想所有的插件被添加到QTPLUGIN中,被自动连接,移除 import_plugins 从这个 CONFIG中:
CONFIG -= import_plugins
创建静态插件
这个是可能的创建自己的静态插件,通过下面的几个步骤:
- 添加 CONFIG += static 在插件的.pro文件中。
- 使用Q_IMPORT_PLUGIN()宏在你的application中。
- 使用Q_INIT_RESOURCE()宏在你的应用程序的插件qrc文件中。
- 链接你的插件在程序中,通过在.pro文件中使用LIBS.