這篇是之前《在 Qt Designer 內使用自定義的 widget》一文的後續。
其實本來 Heresy 一直以為之前使用 QDesignerCustomWidgetInterface 另外封包一個 plugin 物件出來後就搞定了,但是後來才發現,真正要拿來建立函式庫,還是有點問題。
原因就是:如果在一個專案裡面、按照之前的方法寫多個 plugin 出來的話,在建置的連結階段,會出現重複定義的問題。Visual Studio 得到的錯誤會向下面這樣:
錯誤 LNK2005 qt_plugin_instance 已在 moc_plugin2.obj 中定義過了
QtUIforDesigner moc_Plugin1.obj 1
錯誤 LNK2005 qt_plugin_query_metadata 已在 moc_Plugin2.obj 中定義過了
QtUIforDesigner moc_Plugin1.obj 1
這個錯誤基本上是因為在一個專案中,多次使用 Q_PLUGIN_METADATA 這個巨集產生的。
在 Qt 的 Plugin 系統中,Q_PLUGIN_METADATA 是用來定義專案是哪一種 plugin,所以在一個專案裡只能定義一次(官方文件)。
而如果希望在同一個專案裡面提供多個 Designer 的 plugin 的話,那就需要改用 plugin collection 的形式、透過單一個 plugin 的集合來統整所有 plugin 了。
以這邊是要撰寫 Qt Designer 的 plugin 來說,要使用的就是 QDesignerCustomWidgetCollectionInterface(官方文件)。
他的介面相當簡單:
class QDesignerCustomWidgetCollectionInterface { public:
virtual ~QDesignerCustomWidgetCollectionInterface() {}
virtual QList<QDesignerCustomWidgetInterface*> customWidgets() const = 0; };
這邊要重新實作的,基本上就是透過 customWidgets() 這個函式,來回傳要使用的 QDesignerCustomWidgetInterface 了。
實際上寫的話,大概可以寫成下面的樣子:
#pragma once #include "Plugin1.h" #include "Plugin2.h" #include <QtUiPlugin/QDesignerCustomWidgetCollectionInterface> class MyCustomWidgets : public QObject,
public QDesignerCustomWidgetCollectionInterface { Q_OBJECT Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QDesignerCustomWidgetCollectionInterface") Q_INTERFACES(QDesignerCustomWidgetCollectionInterface) public: MyCustomWidgets(QObject* parent = 0) { m_vWidgets << new Plugin1(parent) << new Plugin2(parent); } QList<QDesignerCustomWidgetInterface*> customWidgets() const override { return m_vWidgets; } private: QList<QDesignerCustomWidgetInterface*> m_vWidgets; };
如此一來,MyCustomWidgets 這個 plugin collection 裡面,就會有 Plugin1 和 Plugin1 這兩個 plugin 了。
而在 Plugin 的部分,也必須把定義中的 Q_PLUGIN_METADATA 拿掉,變成下面的形式:
class Plugin1 : public QObject, public QDesignerCustomWidgetInterface { Q_OBJECT Q_INTERFACES(QDesignerCustomWidgetInterface) ... }
經過這樣的修改,就可以把所有的 Qt Designer plugin 放到同一個專案下了。
而把這樣建置出來的 plugin DLL 檔拿到 Designer 用的話,在「說明」的「關於插件」視窗,就可以看到一個 dll 下有多個 Qt widget 了~
另外補充,在 Qt Designer 的 Plugin 中,其實在屬性、還有 signal / slot 的部分,也僅能使用基礎型別、還有一部分 QVariant 支援的型別(參考)。
自定義型別雖然可以使用,但是基本上應該是沒辦法帶到 Qt Designer 裡面用的;這點應該是系統面上的限制了。