您好,登錄后才能下訂單哦!
本文討論Qt4.8的插件機(jī)制
插件是一種遵循一定規(guī)范的應(yīng)用程序接口編寫(xiě)出來(lái)的程序,定位于開(kāi)發(fā)實(shí)現(xiàn)應(yīng)用軟件平臺(tái)不具備的功能的程序。
Qt提供了兩種API用于創(chuàng)建插件:一種是高階API,用于擴(kuò)展Qt本身的功能,如自定義數(shù)據(jù)庫(kù)驅(qū)動(dòng),圖像格式,文本編碼,自定義樣式等;一種是低階API,用于擴(kuò)展Qt應(yīng)用程序。
A、定義一個(gè)接口集(只有純虛函數(shù)的類(lèi)),用來(lái)與插件交流。
B、用宏Q_DECLARE_INTERFACE()將該接口告訴Qt元對(duì)象系統(tǒng)。
C、應(yīng)用程序中用QPluginLoader來(lái)加載插件。
D、用宏qobject_cast()來(lái)判斷一個(gè)插件是否實(shí)現(xiàn)了接口。
創(chuàng)建一個(gè)插件的步驟如下:
A、聲明插件類(lèi),插件類(lèi)繼承自QObject和插件實(shí)現(xiàn)的接口。
B、用宏Q_INTERFACES()將插件接口告訴Qt元對(duì)象系統(tǒng)。
C、用宏Q_EXPORT_PLUGIN2()導(dǎo)出插件類(lèi)。
D、用適當(dāng)?shù)?pro文件構(gòu)建插件。
在加載插件前,?QCoreApplication對(duì)象必須被初始化。
創(chuàng)建工程,選擇“Other Project”->“Subdirs Project”,填寫(xiě)工程名稱(chēng)為PluginApp,選擇保存目錄。
在PluginApp工程上右鍵選擇“New Subproject”菜單項(xiàng),選擇創(chuàng)建一個(gè)GUI應(yīng)用,工程名稱(chēng)為MainWindow。
填寫(xiě)工程應(yīng)用名稱(chēng)
填寫(xiě)主界面類(lèi)的名稱(chēng):
在MainWindow應(yīng)用增加一個(gè)接口Echonterface.h。
#ifndef ECHOINTERFACE_H
#define ECHOINTERFACE_H
#include <QString>
//定義接口
class EchoInterface
{
public:
virtual ~EchoInterface() {}
virtual QString echo(const QString &message) = 0;
};
#define EchoInterface_iid "Examples.Plugin.EchoInterface"
QT_BEGIN_NAMESPACE
Q_DECLARE_INTERFACE(EchoInterface, EchoInterface_iid)
QT_END_NAMESPACE
#endif // ECHOINTERFACE_H
在PluginApp工程上右鍵選擇“New Subproject”菜單項(xiàng),選擇創(chuàng)建一個(gè)空的Qt工程,名稱(chēng)為EchoPlugin。
EchoPlugin.pro工程文件內(nèi)容如下:
TEMPLATE = lib
CONFIG += plugin
QT += widgets
INCLUDEPATH += ../MainWindow
TARGET = $$qtLibraryTarget(echoplugin)
DESTDIR = ../plugins
在插件子工程中添加一個(gè)插件類(lèi)EchoPlugin,實(shí)現(xiàn)如下:
EchoPlugin.h文件:
#ifndef ECHOPLUGIN_H
#define ECHOPLUGIN_H
#include <QObject>
#include <QtPlugin>
#include "EchoInterface.h"
class EchoPlugin : public QObject, public EchoInterface
{
Q_OBJECT
Q_INTERFACES(EchoInterface)
public:
explicit EchoPlugin(QObject *parent = 0);
QString echo(const QString &message);
};
#endif // ECHOPLUGIN_H
EchoPlugin.cpp文件:
#include "EchoPlugin.h"
EchoPlugin::EchoPlugin(QObject *parent) :
QObject(parent)
{
}
QString EchoPlugin::echo(const QString &message)
{
return message;
}
Q_EXPORT_PLUGIN2(EchoPlugin, EchoPlugin);
實(shí)現(xiàn)MainWindow主界面
Widget.h文件:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include "EchoInterface.h"
QT_BEGIN_NAMESPACE
class QString;
class QLineEdit;
class QLabel;
class QPushButton;
class QGridLayout;
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget();
private slots:
void sendEcho();
private:
void createGUI();
//加載插件
bool loadPlugin();
EchoInterface *echoInterface;
QLineEdit *lineEdit;
QLabel *label;
QPushButton *button;
QGridLayout *layout;
};
#endif // WIDGET_H
Widget.cpp文件:
#include "Widget.h"
#include <QtGui>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
createGUI();
setLayout(layout);
setWindowTitle("Echo Plugin Example");
if (!loadPlugin())
{
QMessageBox::information(this, "Error", "Could not load the plugin");
lineEdit->setEnabled(false);
button->setEnabled(false);
}
}
void Widget::sendEcho()
{
QString text = echoInterface->echo(lineEdit->text());
label->setText(text);
}
void Widget::createGUI()
{
lineEdit = new QLineEdit;
label = new QLabel;
label->setFrameStyle(QFrame::Box | QFrame::Plain);
button = new QPushButton(tr("Send Message"));
connect(lineEdit, SIGNAL(editingFinished()),
this, SLOT(sendEcho()));
connect(button, SIGNAL(clicked()),
this, SLOT(sendEcho()));
layout = new QGridLayout;
layout->addWidget(new QLabel(tr("Message:")), 0, 0);
layout->addWidget(lineEdit, 0, 1);
layout->addWidget(new QLabel(tr("Answer:")), 1, 0);
layout->addWidget(label, 1, 1);
layout->addWidget(button, 2, 1, Qt::AlignRight);
layout->setSizeConstraint(QLayout::SetFixedSize);
}
bool Widget::loadPlugin()
{
bool ret = true;
//獲取當(dāng)前應(yīng)用程序所在路徑
QDir pluginsDir(qApp->applicationDirPath());
#if defined(Q_OS_WIN)
if (pluginsDir.dirName().toLower() == "debug" || pluginsDir.dirName().toLower() == "release")
pluginsDir.cdUp();
#elif defined(Q_OS_MAC)
if (pluginsDir.dirName() == "MacOS")
{
pluginsDir.cdUp();
pluginsDir.cdUp();
pluginsDir.cdUp();
}
#elif defined(Q_OS_LINUX)
pluginsDir.cdUp();
#endif
//切換到插件目錄
pluginsDir.cd("plugins");
//遍歷plugins目錄下所有文件
foreach (QString fileName, pluginsDir.entryList(QDir::Files))
{
QPluginLoader pluginLoader(pluginsDir.absoluteFilePath(fileName));
QObject *plugin = pluginLoader.instance();
if (plugin)
{
//插件名稱(chēng)
QString pluginName = plugin->metaObject()->className();
//對(duì)插件初始化
if(pluginName == "EchoPlugin")
{
echoInterface = qobject_cast<EchoInterface *>(plugin);
if (echoInterface)
ret = true;
break;
}
else
{
ret = false;
}
}
}
return ret;
}
Widget::~Widget()
{
}
Main.cpp文件:
#include "Widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
程序運(yùn)行結(jié)果如下:
查看構(gòu)建目錄,生成的插件文件存放在plugins目錄下:
Qt應(yīng)用程序?qū)?huì)自動(dòng)感知可用的插件,因?yàn)椴寮急淮鎯?chǔ)在標(biāo)準(zhǔn)的子目錄當(dāng)中。因此應(yīng)用程序不需要任何查找或者加載插件的代碼。
在開(kāi)發(fā)過(guò)程中,插件的目錄是QTDIR/plugins(QTDIR是Qt的安裝目錄),每個(gè)類(lèi)型的插件放在相應(yīng)類(lèi)型的目錄下面。如果想要應(yīng)用程序使用插件,但不想用標(biāo)準(zhǔn)的插件存放路徑,可以在應(yīng)用程序的安裝過(guò)程中指定要使用的插件的路徑,可以使用QSettings,保存插件路徑,在應(yīng)用程序運(yùn)行時(shí)讀取配置文件。應(yīng)用程序可以通過(guò)QCoreApplication::addLibraryPath()函數(shù)將指定的插件路徑加載到應(yīng)用程序中。
使插件可加載的一種方法是在應(yīng)用程序所在目錄創(chuàng)建一個(gè)子目錄,用于存放插件。如果要發(fā)布和Qt一起發(fā)布的插件(存放在plugins目錄)中的任何插件,必須拷貝plugins目錄下的插件子目錄到應(yīng)用程序的根目錄下。
將一個(gè)插件與一個(gè)應(yīng)用程序一起使用的通常和最靈活的方法是將插件編譯成一個(gè)動(dòng)態(tài)庫(kù),動(dòng)態(tài)庫(kù)可以獨(dú)立轉(zhuǎn)移,并在運(yùn)行時(shí)被檢測(cè)和加載。
插件可以靜態(tài)鏈接到應(yīng)用程序。構(gòu)建Qt的靜態(tài)版本是包含Qt的預(yù)定義插件的唯一選項(xiàng)。使用靜態(tài)插件使部署不易出錯(cuò),但缺點(diǎn)是插件中沒(méi)有的功能不能在應(yīng)用程序的完全重編譯和重發(fā)布的情況下添加。
Qt提供了如下靜態(tài)插件:
要靜態(tài)鏈接靜態(tài)插件,必須在應(yīng)用程序中使用Q_IMPORT_PLUGIN宏,同時(shí)需要使用QTPLUGIN增加相應(yīng)的插件到工程中。如:
#include <QtPlugin>
Q_IMPORT_PLUGIN(qjpeg)
Q_IMPORT_PLUGIN(qgif)
在.pro工程文件中,
QTPLUGIN += qjpeg \
qgif
使用如下步驟可以創(chuàng)建一個(gè)靜態(tài)插件:
A、在.pro工程文件中增加CONFIG += static?
B、在應(yīng)用程序中使用?Q_IMPORT_PLUGIN()宏導(dǎo)入靜態(tài)插件
C、在應(yīng)用程序.pro工程文件中使用?LIBS鏈接應(yīng)用程序和靜態(tài)插件。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。