如何创建 Qt 插件

Qt 为创建插件提供了 2 个 API:

  • A higher-level API for writing extensions to Qt itself: custom database drivers, image formats, text codecs, custom styles, etc.
  • A lower-level API for extending Qt applications.

例如:若想要编写自定义 QStyle 子类并让 Qt 应用程序动态加载它,将使用更高级 API。

由于更高级 API 建立在更低级 API 之上,因此有一些问题是两者公共的。

If you want to provide plugins for use with Qt Designer ,见 QtDesigner 模块文档编制。

话题:

The Higher-Level API: Writing Qt Extensions

编写扩展 Qt 本身的插件是通过子类化适当插件基类、实现一些函数、及添加宏达成的。

There are several plugin base classes. Derived plugins are stored by default in sub-directories of the standard plugin directory. Qt will not find plugins if they are not stored in the right directory.

基类 目录名 键区分大小写
QAccessibleBridgePlugin accessiblebridge 区分大小写
QAccessiblePlugin accessible 区分大小写
QDecorationPlugin decorations 不区分大小写
QFontEnginePlugin fontengines 不区分大小写
QIconEnginePlugin iconengines 不区分大小写
QImageIOPlugin imageformats 区分大小写
QInputContextPlugin inputmethods 区分大小写
QKbdDriverPlugin kbddrivers 不区分大小写
QMouseDriverPlugin mousedrivers 不区分大小写
QScreenDriverPlugin gfxdrivers 不区分大小写
QScriptExtensionPlugin script 区分大小写
QSqlDriverPlugin sqldrivers 区分大小写
QStylePlugin styles 不区分大小写
QTextCodecPlugin codecs 区分大小写

Suppose that you have a new style class called MyStyle that you want to make available as a plugin. The required code is straightforward, here is the class definition ( mystyleplugin.h ):

class MyStylePlugin : public QStylePlugin
{
public:
    QStringList keys() const;
    QStyle *create(const QString &key);
};
					

确保类实现位于 .cpp file (including the class definition):

#include "mystyleplugin.h"
QStringList MyStylePlugin::keys() const
{
    return QStringList() << "MyStyle";
}
QStyle *MyStylePlugin::create(const QString &key)
{
    if (key.toLower() == "mystyle")
        return new MyStyle;
    return 0;
}
Q_EXPORT_PLUGIN2(pnp_mystyleplugin, MyStylePlugin)
					

(注意, QStylePlugin is case insensitive, and the lower-case version of the key is used in our create() 实现;其它大多数插件区分大小写。)

对于数据库驱动程序、图像格式、文本编解码器及大多数其它插件类型,明确创建对象不是必需的。Qt 将根据需要查找并创建它们。样式例外,由于可能想要在代码中明确设置样式。要应用样式,使用代码像这样:

QApplication::setStyle(QStyleFactory::create("MyStyle"));
					

某些插件类要求实现其它功能。见类文档编制,了解各插件类型必须重实现的虚函数的有关细节。

The 样式插件范例 shows如何实现插件以扩展 QStylePlugin 基类。

The Lower-Level API: Extending Qt Applications

不只 Qt 本身,Qt 应用程序还可以被扩展透过插件。这要求应用程序检测并加载插件,使用 QPluginLoader 。在这种情况下,插件可以提供任意功能,不限于数据库驱动程序、图像格式、文本编解码器、样式及扩展 Qt 功能的其它类型插件。

透过插件使应用程序可扩展,涉及以下步骤:

  1. 定义一组用于对话插件的接口 (仅具有纯虚函数的类)。
  2. 使用 Q_DECLARE_INTERFACE () 宏告诉 Qt 的 元对象系统 关于接口。
  3. 使用 QPluginLoader 在应用程序中加载插件。
  4. 使用 qobject_cast () 测试插件是否有实现给定接口。

编写插件涉及这些步骤:

  1. 声明插件类继承 QObject 及插件想要提供的接口。
  2. 使用 Q_INTERFACES () 宏告诉 Qt 的 元对象系统 关于接口。
  3. 导出插件使用 Q_EXPORT_PLUGIN2 () 宏。
  4. 构建插件使用合适 .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 <QStringList>
#include <QImage>
#include <plugandpaint/interfaces.h>
class ExtraFiltersPlugin : public QObject, public FilterInterface
{
    Q_OBJECT
    Q_INTERFACES(FilterInterface)
public:
    QStringList filters() const;
    QImage filterImage(const QString &filter, const QImage &image,
                       QWidget *parent);
};
					

The 插件和描绘 范例文档编制会详细阐述此过程。另请参阅 创建自定义 Widget 为 Qt Designer for information about issues that are specific to Qt Designer . You can also take a look at the 回显插件范例 is a more trivial example on how to implement a plugin that extends Qt applications. Please note that a QCoreApplication 必须已初始化,在可以加载插件之前。

定位插件

Qt 应用程序自动知道哪些插件可用,因为插件存储在标准插件子目录下。应用程序不要求采用任何代码查找和加载插件,由于 Qt 会自动处理它们。

在开发期间,插件目录为 QTDIR/plugins (在哪里 QTDIR is the directory where Qt is installed), with each type of plugin in a subdirectory for that type, e.g. styles . If you want your applications to use plugins and you don't want to use the standard plugins path, have your installation process determine the path you want to use for the plugins, and save the path, e.g. using QSettings ,供应用程序运行时读取。然后,应用程序可以调用 QCoreApplication::addLibraryPath () with this path and your plugins will be available to the application. Note that the final part of the path (e.g., styles ) 无法更改。

If you want the plugin to be loadable then one approach is to create a subdirectory under the application and place the plugin in that directory. If you distribute any of the plugins that come with Qt (the ones located in the plugins directory), you must copy the sub-directory under plugins 插件,位于应用程序根文件夹下 (即:不包括 plugins 目录)。

注意: In Symbian all binaries must be located in the directory \sys\bin, so each Qt plugin has a stub with the same basename as the plugin dll and suffix ".qtplugin" to make Qt extension plugins work similarly to other platforms. When trying to locate the plugin, Qt actually looks for the stub instead of the plugin binary. While plugin stub files have the suffix ".qtplugin", they can still be loaded also by specifying a filename with the normal library suffix ".dll" for QPluginLoader , so normally application developer doesn't need to care about the different suffix of the stub. Because of the way applications can be installed on ROM or various other drives in Symbian, Qt looks for the stub from the same directory on all available drives if it is not located in the given directory when loading a plugin.

有关部署的更多信息,见 部署 Qt 应用程序 and 部署插件 文档编制。

静态插件

将插件包括在应用程序中的正常且最灵活方式,是将其编译成单独随附的动态库,并在运行时检测并加载。

Plugins can be linked statically against your application. If you build the static version of Qt, this is the only option for including Qt's predefined plugins. Using static plugins makes the deployment less error-prone, but has the disadvantage that no functionality from plugins can be added without a complete rebuild and redistribution of the application.

When compiled as a static library, Qt provides the following static plugins:

Plugin name 类型 描述
qtaccessiblecompatwidgets 可访问性 Accessibility for Qt 3 support widgets
qtaccessiblewidgets 可访问性 Accessibility for Qt widgets
qdecorationdefault Decorations (Qt Extended) Default style
qdecorationwindows Decorations (Qt Extended) Windows style
qgif Image formats GIF
qjpeg Image formats JPEG
qmng Image formats MNG
qico Image formats ICO
qsvg Image formats SVG
qtiff Image formats TIFF
qimsw_multi Input methods (Qt Extended) Input Method Switcher
qwstslibmousehandler Mouse drivers (Qt Extended) tslib mouse
qgfxtransformed Graphic drivers (Qt Extended) Transformed screen
qgfxvnc Graphic drivers (Qt Extended) VNC
qscreenvfb Graphic drivers (Qt Extended) Virtual frame buffer
qsqldb2 SQL driver IBM DB2
qsqlibase SQL driver Borland InterBase
qsqlite SQL driver SQLite version 3
qsqlite2 SQL driver SQLite version 2
qsqlmysql SQL driver MySQL
qsqloci SQL driver Oracle (OCI)
qsqlodbc SQL driver Open Database Connectivity (ODBC)
qsqlpsql SQL driver PostgreSQL
qsqltds SQL driver Sybase Adaptive Server (TDS)
qcncodecs Text codecs Simplified Chinese (People's Republic of China)
qjpcodecs Text codecs 日语
qkrcodecs Text codecs 韩语
qtwcodecs Text codecs Traditional Chinese (Taiwan)

To link statically against those plugins, you need to use the Q_IMPORT_PLUGIN () macro in your application and you need to add the required plugins to your build using QTPLUGIN . For example, in your main.cpp :

#include <QApplication>
#include <QtPlugin>
Q_IMPORT_PLUGIN(qjpeg)
Q_IMPORT_PLUGIN(qgif)
Q_IMPORT_PLUGIN(qkrcodecs)
int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    ...
    return app.exec();
}
					

.pro 文件对于应用程序而言,需要以下条目:

QTPLUGIN     += qjpeg \
                qgif \
                qkrcodecs
					

创建自己的静态插件也是可能的,通过以下这些步骤:

  1. 添加 CONFIG += static 到插件的 .pro 文件。
  2. 使用 Q_IMPORT_PLUGIN () 宏在应用程序中。
  3. 链接应用程序与插件库,使用 LIBS .pro 文件。

插件和描绘 范例和关联的 基本工具 插件,了解如何做到这的有关细节。

注意: If you are not using qmake to build your application you need to make sure that the QT_STATICPLUGIN 预处理器宏有定义。

部署和调试插件

The 部署插件 文档涵盖采用应用程序部署插件和调试它们 (当出现问题时) 的过程。

另请参阅 QPluginLoader , QLibrary ,和 插件和描绘范例 .