使用 Qt 插件管理 Qt 对象
Posted
技术标签:
【中文标题】使用 Qt 插件管理 Qt 对象【英文标题】:Qt object management with Qt Plugins 【发布时间】:2015-12-16 13:07:53 【问题描述】:我的问题是在使用 Qt 插件时如何进行适当的对象/资源管理。默认 RAII 似乎不适用于 Qt。
在我们的应用程序中,我们使用在运行时动态加载的模块(Qt 插件)。当加载的插件可以初始化自己,作为初始化阶段的一部分,他们可以将自己的小部件添加到应用程序中。 - 到工具栏 - 到侧面板 - ETC。 添加到主窗口的小部件的所有权也会转移。
这一切都很好,但是现在我们的应用程序变得越来越复杂,我们还需要注意关闭阶段。简单地卸载模块会给我们带来各种各样的麻烦。不存在的对象或在其对象仍然存在时已卸载的类型。
要实现可靠的关机,似乎唯一正确的方法是进行反向初始化。这也意味着向主窗口添加小部件的每个模块也必须删除它们。已经尝试使用第一个小部件来做到这一点让我遇到了麻烦。
模块 A 将小部件 W 注册到 MainWindow。最好我想返回一个范围对象,当超出范围时删除和删除小部件。然而,似乎给定的小部件 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;
;
【问题讨论】:
【参考方案1】:这有点难以回答,因为它取决于您的架构。
一般而言,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 的父对象是您的插件根目录的父对象。
【讨论】:
谢谢,但我不确定我是否明白这如何解决我的问题。我在开篇文章中添加了一个示例,以使其更加具体。除非我弄错了,否则您建议让小部件将插件对象作为所有者,但这不起作用,因为如果我理解正确,MainWindow 将窃取此所有权。【参考方案2】:在Qt forum 上交叉发布这个问题让我得到了以下答案。 即使 Qt 拥有添加到 Ui 的 QWidgets/QObjects 的所有权,仍然可以从客户端删除它们。 Qts 资源管理系统的构建方式是它会知道 QObject 何时被删除,并且它将通过更新 UI 以及删除对它的内部引用来处理此删除。有关详细信息,请参阅链接。
【讨论】:
以上是关于使用 Qt 插件管理 Qt 对象的主要内容,如果未能解决你的问题,请参考以下文章