简体   繁体   English

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

[英]Qt/C++ call function on extended QWidget

In my Qt based program, I have a hierarchy like so: 在基于Qt的程序中,我具有如下层次结构:

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

In MyApplication I have a traditional menu, and one of the actions is to import, and needs to call a ProjectWidget->importStuff() as defined by QTabWidget->currentWidget. 在MyApplication中,我有一个传统菜单,其中一项操作是导入,并且需要调用QTabWidget-> currentWidget定义的ProjectWidget-> importStuff()。

The problem I'm having is when I use QTabWidget->currentWidget I'm limited to the subset of QWidget functions, I cannot call any of the extended functions. 我遇到的问题是,当我使用QTabWidget-> currentWidget时,我仅限于QWidget函数的子集,无法调用任何扩展函数。 I also don't know how to set up a SIGNAL/SLOT that will only affect the single ProjectWidget (without triggering the rest of them) 我也不知道如何设置仅影响单个ProjectWidget的SIGNAL / SLOT(不触发其他信号)

I'm thinking of adding a property to all the ProjectWidgets called "isCurrent", then I'll set a signal that will call the import, and check the "isCurrent" state. 我正在考虑向所有ProjectWidgets添加一个名为“ isCurrent”的属性,然后设置一个将调用导入的信号,并检查“ isCurrent”状态。 If it's the current widget, then it will execute the import function. 如果是当前小部件,则它将执行导入功能。 But this seems convoluted, is there an easier way? 但这似乎令人费解,有没有更简单的方法?

You have two straightforward options 您有两个简单的选择

You can use QMetaObject::invokeMethod static method to invoke any invokable method, all you need is a QObject* pointer and the method name (and parameters, if there are any). 您可以使用QMetaObject::invokeMethod静态方法来调用任何可调用的方法,您所需要的只是QObject*指针和方法名称(以及参数,如果有的话)。 To make method invokable, either use Q_INVOKABLE macro in your subclass definition, or simply make the method into a Qt slot. 若要使方法可调用,请在子类定义中使用Q_INVOKABLE宏,或仅使方法进入Qt插槽。 Then you need just the QObject pointer, and can (try to) call any method with any arguments (and get error if no such method exists). 然后,您只需要QObject指针,就可以(尝试)使用任何参数调用任何方法(如果不存在这样的方法,则会出错)。

Another way is to use qobject_cast<>() , which tries to cast a QObject subclass pointer to another, and will return nullptr , if it can't be done (object is not of that class). 另一种方法是使用qobject_cast<>() ,它尝试将QObject子类指针转换为另一个指针,如果无法完成,则返回nullptr (对象不是该类的对象)。 And once you have the right pointer type, just call any method you like. 一旦拥有正确的指针类型,就可以调用任何您喜欢的方法。 It is much like standard C++ dynamic_cast<> , but works only for QObject subclasses, because it uses the Qt meta-object system and does not depend on C++ RTTI. 它非常类似于标准C ++ dynamic_cast<> ,但是仅适用于QObject子类,因为它使用Qt元对象系统,并且不依赖于C ++ RTTI。

Note: these two ways are something you should use when there is no nice way to have a separate, GUI-independent way to access the widget. 注意:如果没有一种好的方法来使用一种独立于GUI的独立方式来访问小部件,则应使用这两种方式。 But in your case here, these seem to make things so much simpler, it is justified, as long as you plan to keep the QTabWidget around for the lifetime of the app. 但就您的情况而言,只要您计划在应用程序的整个生命周期内都保留QTabWidget ,这些似乎会使事情变得简单得多,这是合理的。


Code example from comment of OP, on using the invokeMethod way to solve this exact problem: OP注释中的代码示例,介绍如何使用invokeMethod方法解决此确切问题:

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

This has the benefit, that now it is possible to have two QObject subclasses which are otherwise unrelated, and just have invokable method with same name (not overriden version of a common superclass method), and the method can be called. 这样做的好处是,现在可以有两个彼此不相关的QObject子类,并且只有具有相同名称的可调用方法(不是公共超类方法的重写版本),并且可以调用该方法。 There's no need to have the class definition available at compile time, and there is no need to add a common base class or introduce an abstract interface class and use multiple inheritance . 无需在编译时提供类定义, 也无需添加公共基类或引入抽象接口类并使用多重继承 This is basically like duck typing: if QMetaObject::invokeMethod(ptr, "quack") , then it is a duck. 这基本上就像鸭子输入:如果QMetaObject::invokeMethod(ptr, "quack") ,那么它就是鸭子。

Downside is then that there is no compile time type checking , simple typo in the method name string can make the code silently fail. 缺点是没有编译时类型检查 ,方法名称字符串中的简单错字会使代码默默地失败。 So it's important to think (and implement and comment in code, and test) what to do when the invokeMethod fails at runtime (is it a bug, or a normal situation for some UI states?). 因此,重要的是思考(并在代码中实现并注释,以及测试)在invokeMethod在运行时失败时应该做什么(这是错误还是某些UI状态的正常情况?)。 But then this applies to (Qt4 syntax of) QObject::connect too, as many Qt programmers have learned the hard way, when slots did not get called because of a typo :-). 但是,这也适用于QObject::connect (的Qt4语法),因为许多Qt程序员已经学到了很难的方法,当插槽由于拼写错误而没有被调用时,:-)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM