如何創建 Qt 插件

Qt 為創建插件提供瞭 2 個 API:

  • 用於編寫 Qt 自身擴展的高級 API:自定義數據庫驅動程序、圖像格式、文本編解碼器、自定義風格、等。
  • 用於擴展 Qt 應用程序的低級 API。

例如:若想要編寫自定義 QStyle 子類並讓 Qt 應用程序動態加載它,將使用更高級 API。

由於更高級 API 建立在更低級 API 之上,因此有一些問題是兩者公共的。

若想要提供用於 Qt Designer 的插件,見 Qt Designer 模塊文檔編製。

話題:

高級 API:編寫 Qt 擴展

編寫擴展 Qt 本身的插件是通過子類化適當插件基類、實現一些函數、及添加宏達成的。

有幾個插件基類。默認情況下,派生插件存儲在標準插件目錄的子目錄下。Qt 將找不到插件,若未將它們存儲在適當目錄下。

下錶匯總瞭插件基類。某些類是私有的,因此未文檔化。可以使用它們,但不承諾兼容更高 Qt 版本。

基類 目錄名 Qt 模塊 鍵區分大小寫
QAccessibleBridgePlugin accessiblebridge Qt GUI 區分大小寫
QImageIOPlugin imageformats Qt GUI 區分大小寫
QPictureFormatPlugin (obsolete) pictureformats Qt GUI 區分大小寫
QBearerEnginePlugin bearer Qt Network 區分大小寫
QPlatformInputContextPlugin platforminputcontexts Qt Platform Abstraction 不區分大小寫
QPlatformIntegrationPlugin platforms Qt Platform Abstraction 不區分大小寫
QPlatformThemePlugin platformthemes Qt Platform Abstraction 不區分大小寫
QPlatformPrinterSupportPlugin printsupport Qt Print Support 不區分大小寫
QSGContextPlugin scenegraph Qt Quick 區分大小寫
QSqlDriverPlugin sqldrivers Qt SQL 區分大小寫
QIconEnginePlugin iconengines Qt SVG 不區分大小寫
QAccessiblePlugin accessible Qt Widgets 區分大小寫
QStylePlugin styles Qt Widgets 不區分大小寫

若有新樣式類稱為 MyStyle 想要將其用作插件,則需要按以下方式定義類 ( mystyleplugin.h ):

class MyStylePlugin : public QStylePlugin
{
    Q_OBJECT
    Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QStyleFactoryInterface" FILE "mystyleplugin.json")
public:
    QStyle *create(const QString &key);
};
					

確保類實現位於 .cpp 文件:

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

(注意, QStylePlugin 不區分大小寫,且小寫鍵版本可用於我們的 create () implementation; most other plugins are case sensitive.)

此外,JSON 文件 ( mystyleplugin.json ) 包含大多數插件所需的插件描述元數據。對於樣式插件,它僅僅包含可以由插件創建的樣式列錶:

{ "Keys": [ "mystyleplugin" ] }
					

在 JSON 文件中需要提供的信息類型取決於插件,請參閱類文檔編製瞭解在文件中需要包含信息的有關細節。

對於數據庫驅動程序、圖像格式、文本編解碼器及大多數其它插件類型,明確創建對象不是必需的。Qt 將根據需要查找並創建它們。樣式例外,由於可能想要在代碼中明確設置樣式。要應用樣式,使用代碼像這樣:

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

某些插件類要求實現其它功能。見類文檔編製,瞭解各插件類型必須重實現的虛函數的有關細節。

The 樣式插件範例 shows如何實現插件以擴展 QStylePlugin 基類。

低級 API:擴展 Qt 應用程序

不隻 Qt 本身,Qt 應用程序還可以被擴展透過插件。這要求應用程序檢測並加載插件,使用 QPluginLoader 。在這種情況下,插件可以提供任意功能,不限於數據庫驅動程序、圖像格式、文本編解碼器、樣式及擴展 Qt 功能的其它類型插件。

透過插件使應用程序可擴展,涉及以下步驟:

  1. 定義一組用於對話插件的接口 (僅具有純虛函數的類)。
  2. 使用 Q_DECLARE_INTERFACE () 宏告訴 Qt 的 元對象係統 關於接口。
  3. 使用 QPluginLoader 在應用程序中加載插件。
  4. 使用 qobject_cast () to test whether a plugin implements a given interface.

編寫插件涉及這些步驟:

  1. 聲明插件類繼承 QObject 及插件想要提供的接口。
  2. 使用 Q_INTERFACES () 宏告訴 Qt 的 元對象係統 關於接口。
  3. 導齣插件使用 Q_PLUGIN_METADATA () 宏。
  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 <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);
};
					

The 插件和描繪 範例文檔編製會詳細闡述此過程。另請參閱 創建自定義 Widget 為 Qt Designer 瞭解 Qt Designer 特定問題的有關信息。還可以查看 迴顯插件範例 ,這是有關如何實現擴展 Qt 應用程序插件的更通俗範例。請注意: QCoreApplication 必須已初始化,在可以加載插件之前。

定位插件

Qt 應用程序自動知道哪些插件可用,因為插件存儲在標準插件子目錄下。應用程序不要求采用任何代碼查找和加載插件,由於 Qt 會自動處理它們。

在開發期間,插件目錄為 QTDIR/plugins (在哪裏 QTDIR 是 Qt 的安裝目錄),各種類型的插件在該類型的子目錄下,例如, styles 。若想要應用程序使用插件但又不想使用標準插件路徑,讓安裝進程確定想要使用的插件路徑並保存路徑,例如,通過使用 QSettings ,供應用程序運行時讀取。然後,應用程序可以調用 QCoreApplication::addLibraryPath () 采用此路徑,您的插件將可用於應用程序。注意,最後部分的路徑 (例如, styles ) 無法更改。

若想要插件可加載,一種途徑是在應用程序下創建子目錄,並將插件放置於該目錄下。若分發 Qt 自帶的任何插件 (其位於 plugins 目錄),必須拷貝其子目錄在 plugins 插件,位於應用程序根文件夾下 (即:不包括 plugins 目錄)。

有關部署的更多信息,見 部署 Qt 應用程序 and 部署插件 文檔編製。

靜態插件

將插件包括在應用程序中的正常且最靈活方式,是將其編譯成單獨隨附的動態庫,並在運行時檢測並加載。

可以將插件靜態鏈接到應用程序。若構建靜態版本的 Qt,這是包括 Qt 預定義插件的唯一選項。使用靜態插件可使部署不易齣錯,但有缺點:無法添加插件功能,當不完整重新構建和重新分發應用程序時。

CMake and qmake automatically add the plugins that are typically needed by the Qt modules used, while more specialized plugins need to be added manually. The default list of automatically added plugins can be overridden per type.

The defaults are tuned towards an optimal out-of-the-box experience, but may unnecessarily bloat the application. It is recommended to inspect the linker command line and eliminate unnecessary plugins.

為促使實際鏈接並實例化靜態插件, Q_IMPORT_PLUGIN () macros are also needed in application code, but those are automatically generated by the build system and added to your application project.

Importing Static Plugins in CMake

To statically link plugins in a CMake project, you need to call the qt_import_plugins 命令。

For example, the Linux libinput plugin is not imported by default. The following command imports it:

qt_import_plugins(myapp INCLUDE Qt::QLibInputPlugin)
					

To link the minimal platform integration plugin instead of the default Qt platform adaptation plugin, use:

qt_import_plugins(myapp
    INCLUDE_BY_TYPE platforms Qt::MinimalIntegrationPlugin
)
					

Another typical use case is to link only a certain set of imageformats plugins:

qt_import_plugins(myapp
    INCLUDE_BY_TYPE imageformats Qt::QJpegPlugin Qt::QGifPlugin
)
					

If you want to prevent the linking of any imageformats plugin, use:

qt_import_plugins(myapp
    EXCLUDE_BY_TYPE imageformats
)
					

If you want to turn off the addition of any default plugin, use the NO_DEFAULT option of qt_import_plugins .

Importing Static Plugins in qmake

In a qmake project, you need to add the required plugins to your build using QTPLUGIN :

QTPLUGIN += qlibinputplugin
					

For example, to link the minimal plugin instead of the default Qt platform adaptation plugin, use:

QTPLUGIN.platforms = qminimal
					

若不想鏈接默認,也不想自動鏈接 minimal QPA 插件,使用:

QTPLUGIN.platforms = -
					

若不想要添加到 QTPLUGIN 的所有插件被自動鏈接,移除 import_plugins CONFIG 變量:

CONFIG -= import_plugins
					

創建靜態插件

創建自己的靜態插件也是可能的,通過以下這些步驟:

  1. 傳遞 STATIC 選項到 qt_add_plugin command in your CMakeLists.txt . For a qmake project, add CONFIG += static 到插件的 .pro 文件。
  2. 使用 Q_IMPORT_PLUGIN () 宏在應用程序中。
  3. 使用 Q_INIT_RESOURCE () 宏在應用程序中,若插件隨附 qrc 文件。
  4. 鏈接應用程序與插件庫,使用 target_link_libraries 在您的 CMakeLists.txt or LIBS 在您的 .pro 文件。

插件和描繪 範例和關聯的 基本工具 插件,瞭解如何做到這的有關細節。

注意: If you are not using CMake or qmake to build your plugin, you need to make sure that the QT_STATICPLUGIN 預處理器宏有定義。

部署和調試插件

The 部署插件 文檔涵蓋采用應用程序部署插件和調試它們 (當齣現問題時) 的過程。

另請參閱 QPluginLoader , QLibrary ,和 插件和描繪範例 .