2015-12-16 26 views
3

我的問題是如何在使用Qt插件時進行適當的對象/資源管理。默認的RAII似乎並不適用於Qt。使用Qt插件進行Qt對象管理

在我們的應用程序中,我們使用在運行時動態加載的模塊(Qt插件)。當被加載的插件可以初始化自己並且作爲這個初始化階段的一部分時,他們可以將他們自己的小部件添加到應用程序中 - 轉到工具欄 - 轉到側面板 - 等 添加到主窗口的窗口小部件的所有權也已轉移。

這一切都很好,但現在我們的應用程序變得更加複雜了,我們還需要注意關閉階段。簡單地卸載模塊將使我們陷入各種麻煩。不存在的對象或在對象仍處於活動狀態時卸載的類型。

要有可靠的關閉,似乎唯一正確的方法是進行反向初始化。這也意味着向主窗口添加小部件的每個模塊都必須刪除它們。已經試圖用第一個小工具做到這一點讓我陷入困境。

模塊A使用MainWindow註冊W部件。最好我想要返回一個範圍對象,當超出範圍時刪除和刪除小部件。然而,已經看起來給定的小部件W不能從工具欄簡單地刪除它,因爲它與動作一起工作(並且刪除動作不會刪除小部件!請參閱下面的示例)。

最後總結一下,在我看來,Qt是以這樣一種方式獲得的,它獲得了所有權的所有權,您必須依靠Qt來刪除它。這不適用於模塊。我正在尋找解決方案/最佳做法。

編輯:
我添加了一個示例,其中一個模塊將一個自定義小部件添加到MainWindow的工具欄中。我的目標是,由於之前所述的原因,該模塊負責刪除小部件。例子是讓問題更具體。它代表了通用問題--qt對象的所有權 - 將這種模式與插件結合使用。

例如:
executable.cpp

class MainWindow : public QMainWindow 
{ 
    Q_OBJECT 

public: 
    explicit MainWindow(QWidget *parent = 0) { 
     ui->setupUi(this); 
     LoadPlugin(); 
    } 

    void LoadPlugin() { 
     m_plugin = new QPluginLoader("module.dll"); 
     m_plugin->load(); 
     IModule* moduleInstance = qobject_cast<IModule*>(m_plugin->instance()); 
     moduleInstance->Initialize(this); 
    } 

    void AddToolbarSection(QWidget* widget) { 
     /** ownership is transferred here to Qt */ 
     mainToolBar->insertWidget(pWidget); 
    } 

    void RemoveToolbarSection(){ 
     /** How to get the widget deleted? */ 
    } 

    /** this is called before the destructor */ 
    void UnloadPlugin() { 
     moduleInstance->Shutdown(); 
     m_plugin->unload(); 
    } 

    ~MainWindow() { 
     /** deletion of toolbar sections must already been done here 
      as the modules are already unloaded. Otherwise access violations occur 
      because specific type information is not accessible anymore.     
     */ 
    } 

private:   
    Ui::MainWindow *ui; 
    QPluginLoader* m_plugin; 
    IModule* m_moduleInstance; 
}; 

module.cpp

class EXPORT_MODULE IModule : public QObject 
{ 
    Q_OBJECT 
    Q_PLUGIN_METADATA(IID IModuleIID) 
    Q_INTERFACES(IModule) 

public: 
    IModule() { 
    } 

    void Initialize(QMainWindow* window) { 
     /** QMyToolbarSectionWidget is a custom widget defined in this module (module.dll) 
      it has a specific destructor and triggers all kinds application 
      specific cleanup */ 
     m_toolbarSection = new QMyToolbarSectionWidget(); 
     window->AddToolbarSection(m_toolbarSection); 
    } 

    void Shutdown() { 
     window->RemoveToolbarSection(m_toolbarSection); 
    } 

private: 
    QWidget* m_toolbarSection; 
}; 

回答

0

交叉點這個問題上Qt forum給了我下面的答案。 儘管Qt擁有添加到UI的QWidgets/QObjects的所有權,但仍然可以從客戶端刪除它們。 Qts資源管理系統的構建方式是,它將知道何時刪除QObject,並通過更新UI以及刪除內部引用來處理刪除操作。請參閱鏈接查看更多細節。

0

這是一個有點難以回答,因爲它取決於你的架構。

總的來說,Qt的清理想法與父指針有關。即

QObject *root; 
QObject *leaf = new QObject(); 
leaf->setParent(root); 
root->deleteLater(); 

QPluginLoader將在卸載甚至清理你的根組件,因此從理論上講,你的插件下方的任何樹被清除。只要確保你從根目錄返回的所有內容都是一個QObject父元素。如果它不是QObject,則將其封裝在QObject中。

class MyExtension : public QWidget { 
    QAction *myAction; 
    MyExtension() : QWidget() { 
     myAction = new QAction(this); 
    } 
    QAction *getAction() { 
     return myAction 
    } 
} 

從你的問題我明白你也可能這樣工作:

class MyExtension : public QObject { 
    MyWindow * myWindow; 
    QAction * myAction; 
    MyExtension() : QObject() { 
     myWindow = new MyWindow(this); 
     myAction = new QAction(this); 
    } 
    void addToMainThing(TheMainThing *tmt) { 
     tmt->addWidget(myAction); 
    } 
} 

同樣的事情。只要始終確保你的QObject已經成爲你的插件根目錄的父對象。

+0

謝謝,但我不知道我得到如何解決我的問題。我在我的開場白中增加了一個例子,使其更加具體。除非我誤解了,否則你會建議讓小部件擁有作爲所有者的插件對象,但是如果我理解正確,那麼這種方法不起作用,因爲MainWindow會竊取此所有權。 –