如何創建 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 區分大小寫
QAudioSystemPlugin audio Qt Multimedia 不區分大小寫
QDeclarativeVideoBackendFactoryInterface video/declarativevideobackend Qt Multimedia 不區分大小寫
QGstBufferPoolPlugin video/bufferpool Qt Multimedia 不區分大小寫
QMediaPlaylistIOPlugin playlistformats Qt Multimedia 不區分大小寫
QMediaResourcePolicyPlugin resourcepolicy Qt Multimedia 不區分大小寫
QMediaServiceProviderPlugin mediaservice Qt Multimedia 不區分大小寫
QSGVideoNodeFactoryPlugin video/videonode Qt Multimedia 不區分大小寫
QBearerEnginePlugin bearer Qt Network 區分大小寫
QPlatformInputContextPlugin platforminputcontexts Qt Platform Abstraction 不區分大小寫
QPlatformIntegrationPlugin platforms Qt Platform Abstraction 不區分大小寫
QPlatformThemePlugin platformthemes Qt Platform Abstraction 不區分大小寫
QGeoPositionInfoSourceFactory 位置 Qt Positioning 區分大小寫
QPlatformPrinterSupportPlugin printsupport Qt Print Support 不區分大小寫
QSGContextPlugin scenegraph Qt Quick 區分大小寫
QScriptExtensionPlugin script Qt Script 區分大小寫
QSensorGesturePluginInterface sensorgestures Qt Sensors 區分大小寫
QSensorPluginInterface sensors Qt Sensors 區分大小寫
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() 實現;其它大多數插件區分大小寫。)

此外,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. Use 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 預定義插件的唯一選項。使用靜態插件可使部署不易齣錯,但有缺點:無法添加插件功能,當不完整重新構建和重新分發應用程序時。

要靜態鏈接插件,需要將所需插件添加到構建使用 QTPLUGIN .

.pro 文件對於應用程序而言,需要以下條目:

QTPLUGIN     += qjpeg \
                qgif \
                qkrcodecs
					

通常,qmake 將使用 Qt 模塊所需的插件自動添加到 QTPLUGIN (見 QT ),而更專用的插件則需要手動添加。可以按類型覆蓋自動添加的默認插件列錶。例如,要鏈接 minimal 插件而不是默認 Qt 平颱適配插件,使用:

QTPLUGIN.platforms = qminimal
					

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

QTPLUGIN.platforms = -
					

默認微調至最優開箱即用體驗,但可能不必要膨脹應用程序。推薦通過 qmake 構建審查鏈接器命令行,並消除不必要插件。

鏈接靜態插件的細節

為促使實際鏈接並實例化靜態插件, Q_IMPORT_PLUGIN () 宏還需要在應用程序代碼中,但這些是由 qmake 自動生成的,並已添加到應用程序工程中。

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

CONFIG -= import_plugins
					
					

創建靜態插件

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

  1. 添加 CONFIG += static 到插件的 .pro 文件。
  2. 使用 Q_IMPORT_PLUGIN () 宏在應用程序中。
  3. 使用 Q_INIT_RESOURCE () 宏在應用程序中,若插件隨附 qrc 文件。
  4. 鏈接應用程序與插件庫,使用 LIBS .pro 文件。

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

注意: 若不使用 qmake 構建插件,需要確保 QT_STATICPLUGIN 預處理器宏有定義。

部署和調試插件

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

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