扩展 QWidget 上的 Qt/C++ 调用函数

Posted

技术标签:

【中文标题】扩展 QWidget 上的 Qt/C++ 调用函数【英文标题】:Qt/C++ call function on extended QWidget 【发布时间】:2013-11-05 18:14:36 【问题描述】:

在我的基于 Qt 的程序中,我有这样的层次结构:

MyApplication::QMainWindow -> QTabWidget -> ProjectWidget::QWidget

在 MyApplication 中,我有一个传统菜单,其中一个操作是导入,需要调用 QTabWidget->currentWidget 定义的 ProjectWidget->importStuff()。

我遇到的问题是,当我使用 QTabWidget->currentWidget 时,我仅限于 QWidget 函数的子集,我无法调用任何扩展函数。我也不知道如何设置一个只会影响单个 ProjectWidget 的 SIGNAL/SLOT(不会触发其余部分)

我正在考虑向所有 ProjectWidgets 添加一个名为“isCurrent”的属性,然后我将设置一个将调用导入的信号,并检查“isCurrent”状态。如果它是当前小部件,那么它将执行导入功能。但这似乎很复杂,有没有更简单的方法?

【问题讨论】:

【参考方案1】:

你有两个简单的选择

您可以使用QMetaObject::invokeMethod 静态方法来调用任何可调用的方法,您只需要一个QObject* 指针和方法名称(和参数,如果有的话)。要使方法可调用,请在子类定义中使用Q_INVOKABLE 宏,或者简单地将方法放入Qt 槽中。然后你只需要QObject 指针,并且可以(尝试)调用任何带有任何参数的方法(如果不存在这样的方法则会出错)。

另一种方法是使用qobject_cast<>(),它会尝试将QObject 子类指针转换为另一个,如果无法完成将返回nullptr(对象不是那个班级)。一旦你有了正确的指针类型,就可以调用你喜欢的任何方法。它很像标准 C++ dynamic_cast<>,但仅适用于 QObject 子类,因为它使用 Qt 元对象系统并且不依赖于 C++ RTTI。

注意:如果没有很好的方式来获得单独的、独立于 GUI 的方式来访问小部件,则应该使用这两种方式。但是在您的情况下,这些似乎使事情变得如此简单,这是合理的,只要您计划在应用程序的整个生命周期内保留QTabWidget


来自 OP 评论的代码示例,关于使用 invokeMethod 方法来解决这个确切问题:

QMetaObject::invokeMethod(myTabWidget->currentWidget(), "callbackFunction");

这样做的好处是,现在可以有两个不相关的QObject 子类,并且只有具有相同名称的可调用方法(不是通用超类方法的覆盖版本),并且可以调用该方法.无需在编译时提供类定义,并且无需添加公共基类或引入抽象接口类并使用多重继承。这基本上就像鸭子打字:如果QMetaObject::invokeMethod(ptr, "quack"),那么它就是鸭子。

缺点是没有编译时类型检查,方法名称字符串中的简单拼写错误会使代码静默失败。因此,当invokeMethod 在运行时失败时(是错误还是某些 UI 状态的正常情况?),思考(并在代码中实现和注释,并测试)是很重要的。但这也适用于QObject::connect 的(Qt4 语法),因为许多 Qt 程序员已经学会了艰难的方法,当插槽由于拼写错误而没有被调用时 :-)。

【讨论】:

(抱歉缺少 Qt 文档的链接,在路上用平板电脑写,明天会添加链接来回答......) 感谢 Hyde,我设法找到了合适的文档。在这种情况下,我喜欢方法#2——我同意传递指针是理想的,但在这种情况下,强制对特定类的更多依赖似乎是不可取的。主窗口中只有几个 QActions 需要与项目对话,所以即使它不那么优雅,我也愿意接受一个“丑陋”的组件来支持整体更清洁的设计。 ++ 很好的建议。 (刚刚收到编辑/更新)完美运行,我将用解决方案为未来的读者更新我的问题。 @Kver 只接受答案,在 Stack Overflow,您不应该编辑以添加问题的答案。 好的。但是对于前面提到的未来读者,这是解决方案最终导致的代码行:QMetaObject::invokeMethod(myTabWidget->currentWidget(), "callbackFunction");

以上是关于扩展 QWidget 上的 Qt/C++ 调用函数的主要内容,如果未能解决你的问题,请参考以下文章

将 PySide/PyQt 小部件嵌入到 Qt/C++ 应用程序中

重新映射 qwidget 上的上下文菜单调用

Qt:在子部件上使用 QPainter

如何从 Qt/C++ 的子函数中调用非静态父函数?

QWidget初始化函数调用中的不同行为

调用 setVisible(false) 在 QWidget 的构造函数中不起作用