1

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

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

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

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

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

4

1 回答 1

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 状态的正常情况?)。但这也适用于(Qt4 语法)QObject::connect,因为许多 Qt 程序员已经学会了艰难的方法,当插槽由于拼写错误而没有被调用时 :-)。

于 2013-11-05T18:43:55.460 回答