Tap into QWidget::create
-
Hello,
I have a push button dial custom widget derived fromQStackedWidget
and I wish to lay it out (create the buttons) depending on theQAction
instances attached to the widget. Currently I do that in a separate function that initializes the widget, but I want that to be done after the widget is created. Unfortunately,QWidget::create
is not virtual so reimplementing it seems impossible, are there any workarounds? Could I use one of the change events handled inQWidget::changeEvent
instead?Kind regards.
-
@kshegunov
there is a QEvent::ActionAdded (QActionEvent) event which is fired to the widget where addAction() is called on.
Does this help you? -
@raven-worx
Hello,
I don't see how I could use it, but maybe I shouldn't have been so laconic in my original post. I'll give the whole picture and hopefully it'll become clear what and why exactly I'm needing this. I have a push button dial but it's not "flat" as one might ordinarily expect. What I mean is that some of the buttons are actually opening another dial with another set of buttons and a return button. The tree-like behaviour is similar to what you might expect from a menu. Some actions have subactions and some subactions can have subactions and so on. This is the reason I'm actually deriving fromQStackedWidget
and am not initializing the dial ui in the ordinary fashion (with a form), but instead am building the pages recursively. The hierarchy of actions I simply build throughQObject
's parent, in the conventional manner. Everything is fine and dandy, except I have to explicitly call my method that creates the stacked pages, the layouts and the buttons based on the actions. This is what I'd wish to avoid. Obviously I couldn't do it in the constructor of my widget, since there are no actions added at that point. I was thinking to maybe intercept the show event and do a lazy init there, but was unsure if there isn't a better way. It just occurred to me while typing that your suggestion might be viable if I build the pages incrementally at eachActionAdded
event, so I'll try that and if in the meantime anyone has another idea I'd appreciate it.Thanks for the help!
Kind regards. -
@kshegunov
analog there is also a QEvent::ChildAdded event (QChildEvent) which is triggered when a QObject parent/child relation is created.Something like this?
void childEvent(QChildEvent * event) { BaseClass::childEvent( event ); if( event->added() ) { if( MyObj* obj = qobject_cast<MyObj*>( event->child() ) ) { // add page } } }
-
@raven-worx
Hm, this also could possibly be useful to monitor theQAction
instances for changes in the hierarchy, but for this I'll have to install an event filter on each of them, which I'm reluctant to do. Still, I might go with it in the end. Thanks!Kind regards.
-
@raven-worx
Hello,
TheQEvent::ActionAdded
worked wondrously, however your second suggestion withQEvent::ChildAdded
is a bit more involved. I have put an event filter to each of my attached actions to capture the ChildAdded/ChildRemoved events but the handling of these events should be scheduled through the event loop, because at the point whereQWidget::childEvent
is invoked the object returned byevent->child()
is not completely constructed! I'm writing this only to let you know that this lineMyObj* obj = qobject_cast<MyObj*>( event->child() )
will not work and for further reference to anyone reading this thread. Still, I thank you for the input, it helped me quite a lot!Kind regards.
-
@kshegunov
a workaround for this would be not to continue processing with the child pointer immediately , but access it delayed:void childEvent(QChildEvent * event) { BaseClass::childEvent( event ); if( event->added() ) { QMetaObject::invokeMethod( this, "childAdded", Qt::QueuedConnection, Q_ARG(QObject*,event->child() ); } } // this method must be a SLOT or have the Q_INVOKABLE macro set void childAdded( QObject* child ) { MyObj* obj = qobject_cast<MyObj*>( chidl ); // fully constructed by now }
-
@raven-worx
Hello,
Thanks for the code, but I know how to do the scheduling. I actually went withQPointer<QObject>
since theQObject
might be deleted while waiting in the event loop. Like this:bool AgDial::eventFilter(QObject * object, QEvent * event) { switch (event->type()) { case QEvent::ChildAdded: QMetaObject::invokeMethod(this, "scheduleChildAdd", Qt::QueuedConnection, Q_ARG(QPointer<QObject>, QPointer<QObject>(reinterpret_cast<QChildEvent *>(event)->child()))); break; case QEvent::ChildRemoved: d()->detachAction(reinterpret_cast<QChildEvent *>(event)->child()); break; } return QStackedWidget::eventFilter(object, event); }
Thanks for taking the time though!
Kind regards.