qt 的插件
什么是插件
插件是一種遵循一定規范的應用程式介面撰寫出來的程式,定位于開發實作應用軟體平臺不具備的功能的程式,
2個特點:
1、基于介面編程
2、提供擴展性
qt插件的2種形式
可以有2種插件形式
1、動態插件,也就是動態庫
2、靜態插件
插件是一個動態庫,可以在運行時加載該庫以擴展應用程式,Qt使得創建自定義插件并使用QPluginLoader加載它們成為可能,為了確保插件不會丟失,還可以將它們靜態鏈接到可執行檔案
示例可以查看Qt的demo: https://doc.qt.io/qt-5/qtwidgets-tools-plugandpaint-app-example.html
plugin實作
對于插件工程來說,需要實作一個介面:
- 定義一個繼承 QObject 和 介面的插件;
- 使用
Q_INTERFACES()宣告使用的介面型別;在moc中支持按照對應的介面轉換, - 使用
Q_PLUGIN_METADATA()宏匯出元資訊;在moc中匯出元資料和類,
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 override;
QImage filterImage(const QString &filter, const QImage &image,
QWidget *parent) override;
};
主程式實作
對于主工程來說,需要定一個插件的介面:
動態:
- 使用
Q_DECLARE_INTERFACE()是生成對應介面轉換函式 qobject_cast ;Q_INTERFACES 也會用到, - 使用
QPluginLoader來加載插件; - 使用
qobject_cast()進行插件造型,判斷插件實作了哪個介面;
靜態:
1、Q_IMPORT_PLUGIN(BasicToolsPlugin),匯入類
2、QPluginLoader::staticInstances() 加載靜態插件
void MainWindow::loadPlugins()
{
//靜態插件
const auto staticInstances = QPluginLoader::staticInstances();
for (QObject *plugin : staticInstances)
populateMenus(plugin);
//動態插件
const auto entryList = pluginsDir.entryList(QDir::Files);
for (const QString &fileName : entryList) {
QPluginLoader loader(pluginsDir.absoluteFilePath(fileName));
QObject *plugin = loader.instance();
if (plugin) {
populateMenus(plugin);
pluginFileNames += fileName;
}
}
}
//根據介面判斷,也就IID來判斷的,下面會講
void MainWindow::populateMenus(QObject *plugin)
{
//一個插件可以實作多個介面,所以需要多次判斷
auto iBrush = qobject_cast<BrushInterface *>(plugin);
if (iBrush)
addToMenu(plugin, iBrush->brushes(), brushMenu, &MainWindow::changeBrush,
brushActionGroup);
auto iShape = qobject_cast<ShapeInterface *>(plugin);
if (iShape)
addToMenu(plugin, iShape->shapes(), shapesMenu, &MainWindow::insertShape);
auto iFilter = qobject_cast<FilterInterface *>(plugin);
if (iFilter)
addToMenu(plugin, iFilter->filters(), filterMenu, &MainWindow::applyFilter);
}
下面介紹下幾個宏的作用
Q_DECLARE_INTERFACE
宏的作用生成2種函式,主要作用是宣告介面轉換函式 qobject_cast ;
1、qobject_interface_iid 回傳當前類介面id IId,
2、qobject_cast 判斷引數是否可以轉成當前類,
關聯一個唯一的標識類,通過唯一標識可以訪問類
#define BrushInterface_iid "org.qt-project.Qt.Examples.PlugAndPaint.BrushInterface/1.0"
Q_DECLARE_INTERFACE(BrushInterface, BrushInterface_iid)
# define Q_DECLARE_INTERFACE(IFace, IId) \
template <> inline const char *qobject_interface_iid<IFace *>() \
{ return IId; } \
template <> inline IFace *qobject_cast<IFace *>(QObject *object) \
{ return reinterpret_cast<IFace *>((object ? object->qt_metacast(IId) : nullptr)); } \
template <> inline IFace *qobject_cast<IFace *>(const QObject *object) \
{ return reinterpret_cast<IFace *>((object ? const_cast<QObject *>(object)->qt_metacast(IId) : nullptr)); }
例如:qobject_cast 所依賴qt_metacast是由元物件系統生成的
class BasicToolsPlugin : public QObject,
public BrushInterface,
public ShapeInterface,
public FilterInterface
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.Examples.PlugAndPaint.BrushInterface" FILE "basictools.json")
Q_INTERFACES(BrushInterface ShapeInterface FilterInterface)
}
在moc_BasicToolsPlugin.cpp中就生成了qt_metacast方法來判斷是否可以轉換
void *BasicToolsPlugin::qt_metacast(const char *_clname)
{
if (!_clname) return nullptr;
if (!strcmp(_clname, qt_meta_stringdata_BasicToolsPlugin.stringdata0))
return static_cast<void*>(this);
if (!strcmp(_clname, "BrushInterface"))
return static_cast< BrushInterface*>(this);
if (!strcmp(_clname, "ShapeInterface"))
return static_cast< ShapeInterface*>(this);
if (!strcmp(_clname, "FilterInterface"))
return static_cast< FilterInterface*>(this);
if (!strcmp(_clname, "org.qt-project.Qt.Examples.PlugAndPaint.BrushInterface/1.0"))
return static_cast< BrushInterface*>(this);
if (!strcmp(_clname, "org.qt-project.Qt.Examples.PlugAndPaint.ShapeInterface/1.0"))
return static_cast< ShapeInterface*>(this);
if (!strcmp(_clname, "org.qt-project.Qt.Examples.PlugAndPaint.FilterInterface/1.0"))
return static_cast< FilterInterface*>(this);
return QObject::qt_metacast(_clname);
}
Q_PLUGIN_METADATA
這個宏的作用,是在moc_**.cpp中生成元資料,并且匯出插件類
class BasicToolsPlugin : public QObject,
public BrushInterface,
public ShapeInterface,
public FilterInterface
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.Examples.PlugAndPaint.BrushInterface" FILE "basictools.json")
}
//moc_**.cpp中生成元資料
static constexpr unsigned char qt_pluginMetaData[] = {
'Q', 'T', 'M', 'E', 'T', 'A', 'D', 'A', 'T', 'A', ' ', '!',
// metadata version, Qt version, architectural requirements
0, QT_VERSION_MAJOR, QT_VERSION_MINOR, qPluginArchRequirements(),
0xbf,
// "IID"
0x02, 0x78, 0x36, 'o', 'r', 'g', '.', 'q',
't', '-', 'p', 'r', 'o', 'j', 'e', 'c',
't', '.', 'Q', 't', '.', 'E', 'x', 'a',
'm', 'p', 'l', 'e', 's', '.', 'P', 'l',
'u', 'g', 'A', 'n', 'd', 'P', 'a', 'i',
'n', 't', '.', 'B', 'r', 'u', 's', 'h',
'I', 'n', 't', 'e', 'r', 'f', 'a', 'c',
'e',
// "className"
0x03, 0x70, 'B', 'a', 's', 'i', 'c', 'T',
'o', 'o', 'l', 's', 'P', 'l', 'u', 'g',
'i', 'n',
0xff,
};
QT_MOC_EXPORT_PLUGIN(BasicToolsPlugin, BasicToolsPlugin)
Q_INTERFACES
在moc_**.cpp中支持通過介面名稱轉成對應的型別,例如:
org.qt-project.Qt.Examples.PlugAndPaint.FilterInterface/1.0
class ExtraFiltersPlugin : public QObject, public FilterInterface
{
Q_OBJECT
Q_INTERFACES(FilterInterface)
};
//為了支持通過介面名稱轉成對應的型別,org.qt-project.Qt.Examples.PlugAndPaint.FilterInterface/1.0
void *ExtraFiltersPlugin::qt_metacast(const char *_clname)
{
if (!_clname) return nullptr;
if (!strcmp(_clname, qt_meta_stringdata_ExtraFiltersPlugin.stringdata0))
return static_cast<void*>(this);
if (!strcmp(_clname, "FilterInterface"))
return static_cast< FilterInterface*>(this);
if (!strcmp(_clname, "org.qt-project.Qt.Examples.PlugAndPaint.FilterInterface/1.0"))
return static_cast< FilterInterface*>(this);
return QObject::qt_metacast(_clname);
}
如果沒有使用Q_DECLARE_INTERFACE 對 FilterInterface 進行宣告就會報錯
//Q_DECLARE_INTERFACE(FilterInterface, FilterInterface_iid)
原因就是 template <> inline const char *qobject_interface_iid<IFace *>() 沒有宣告導致的,

Qt 自帶插件
先看一下一個平臺的插件,windows的類圖
1、基于介面開發,插件只是回傳 QPlatformIntegration

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/261094.html
標籤:其他
下一篇:BFPRT(線性查找演算法)
