How to emit parentWidget's signal from its child?
-
@Emon-Haque said in How to emit parentWidget's signal from its child?:
parentWidget()
first of, what isparentWidget()
thats a custom function, what does it do?
it is apparently a base QWidget function 😅, oopssecondly, the child should not know/access functions from the parent. Thats bad design.
Let the child emit a signal that the parent catches and forwards. You can connect signals to signals, no problem.thirdly are you sure all classes have the Q_OBJECT macro in the headers ? qobject_cast, at least, will misbehave/not work if its missing.
-
@Emon-Haque said in How to emit parentWidget's signal from its child?:
parentWidget()
first of, what isparentWidget()
thats a custom function, what does it do?
it is apparently a base QWidget function 😅, oopssecondly, the child should not know/access functions from the parent. Thats bad design.
Let the child emit a signal that the parent catches and forwards. You can connect signals to signals, no problem.thirdly are you sure all classes have the Q_OBJECT macro in the headers ? qobject_cast, at least, will misbehave/not work if its missing.
@J-Hilk said in How to emit parentWidget's signal from its child?:
first of, what is parentWidget() thats a custom function, what does it do?
QWidget *QWidget::parentWidget() const
Returns the parent of this widget, or 0 if it does not have any parent widget.auto w = qobject_cast<QueryWidget*>(parentWidget());
Here parent() or parentWidget() it doesn't matter because of the cast.
-
@Emon-Haque
That is not what I meant, it doesn't prove anything. ThesetObjectName()
must be done on the actualQueryWidget
instance where it is created, not in this method. We are trying to find out what the object(s) pointed to here byparentWidget()
andparent()
are.My last word: print out what is in the
dynamic_cast
&qobject_cast
variables, do not rely on what the debugger is showing you.I do not know how those can be
nullptr
when yourstatic_cast<>
works.I do not not know why you can apparently call
objectName()
on the pointer but the signal does not seem to be emitted. You could verify that where you have an actual instance ofQueryWidget
(nowhere near this method, and after you have connected the slot) you can callinstance->noSelect(...);
so that you know that works.@JonB, looks like it returns another instance of
QueryWidget
. WithsetObjectName("Test");
in the costructor ofQueryWidget
, if I do:auto scw = static_cast<QueryWidget*>(parentWidget()); auto qcw = qobject_cast<QueryWidget*>(parentWidget()); auto dcw = dynamic_cast<QueryWidget*>(parentWidget()); auto scp = static_cast<QueryWidget*>(parent()); auto qcp = qobject_cast<QueryWidget*>(parent()); auto dcp = dynamic_cast<QueryWidget*>(parent()); qDebug() << scw->objectName(); qDebug() << scp->objectName(); qDebug() << qcw->objectName(); qDebug() << qcp->objectName(); qDebug() << dcw->objectName(); qDebug() << dcp->objectName();
it prints
""
, empty string, twice and then app crashes. Bothqobject_cast
anddynamic_cast
returnsnullptr
? -
@Emon-Haque said in How to emit parentWidget's signal from its child?:
parentWidget()
first of, what isparentWidget()
thats a custom function, what does it do?
it is apparently a base QWidget function 😅, oopssecondly, the child should not know/access functions from the parent. Thats bad design.
Let the child emit a signal that the parent catches and forwards. You can connect signals to signals, no problem.thirdly are you sure all classes have the Q_OBJECT macro in the headers ? qobject_cast, at least, will misbehave/not work if its missing.
@J-Hilk, everywhere I've
Q_OBJECT
at the top like this:class MyObjectName : public QWidget{ Q_OBJECT public: ...
Yes, you get those parent()/parentWidget() from
QWidget
. Philosophically, it could be bad design BUT if you could do so, it'll reduce significant amount of unnecessary code bloat. -
auto w = qobject_cast<QueryWidget*>(parentWidget()); if(w) emit w->noSelect(query); else qDebug()<<"parent() not a QueryWidget"<<parent();
@mpergand, that's always null with that
cast
so it'll enter theelse
block BUT the thing that will print inelse
block is incorrect because:QueryWidget::QueryWidget(QWidget *parent) : QWidget(parent){ .. queryresult = new QueryResultView(this); .... )
QueryWidget
is indeed the parent ofqueryresult
. -
@mpergand, that's always null with that
cast
so it'll enter theelse
block BUT the thing that will print inelse
block is incorrect because:QueryWidget::QueryWidget(QWidget *parent) : QWidget(parent){ .. queryresult = new QueryResultView(this); .... )
QueryWidget
is indeed the parent ofqueryresult
.@Emon-Haque said in How to emit parentWidget's signal from its child?:
queryresult = new QueryResultView(this);
....What's behind ...
I predicte nasty stuff here :) -
@Emon-Haque said in How to emit parentWidget's signal from its child?:
queryresult = new QueryResultView(this);
....What's behind ...
I predicte nasty stuff here :)@mpergand, what?
-
@mpergand, what?
@Emon-Haque
Are you sure QueryResultView is not reapparented
What parent() prints at the end of the constructor ? -
@Emon-Haque
Are you sure QueryResultView is not reapparented
What parent() prints at the end of the constructor ?@mpergand, hmm
qDebug() << parent() << parentWidget(); QSplitter(0x425d470) QSplitter(0x425d470)
so
this
actually has no meaning there! as soon as I add it in QSplittersplit2->addWidget(queryresult);
the splitter becomes its parent. Now I'll try to work with its grand parent and will let you know what happens. -
Bingo, that's what I guess from the begining !
void QSplitter::addWidget(QWidget *widget)
Adds the given widget to the splitter's layout after all the other items.
If widget is already in the splitter, it will be moved to the new position.
Note: The splitter takes ownership of the widget. -
Bingo, that's what I guess from the begining !
void QSplitter::addWidget(QWidget *widget)
Adds the given widget to the splitter's layout after all the other items.
If widget is already in the splitter, it will be moved to the new position.
Note: The splitter takes ownership of the widget.@mpergand, now it gets into the
slot
of&TableWidget::onNoSelect
auto scp = static_cast<QueryWidget*>(parent()->parent()); emit scp->noSelect(query); qDebug() << parent()->parent() << parentWidget()->parent();
and that
qDebug
prints:QueryWidget(0x2245c30, name = "Test") QueryWidget(0x2245c30, name = "Test")
Thanks for the insight.
-
@Emon-Haque said in How to emit parentWidget's signal from its child?:
BUT
s
got it rightNo, it did not! As I wrote, with
static_cast<>
" does not check or returnnullptr
, it takes your word for it. " But here you apparently lied to it, because the other two tell you thatparentWidget()
is not aQueryWidget*
. So goodness knows what happens when you then gow->noSelect()
. Do not usestatic_cast<>
!So what is your
QueryResultView
, and what is itsparentWidget()
orparent()
?Ah:
queryresult = new QueryResultView(this);
, so itsparent
should be aQueryWidget
.Not[e] in both cases,
parentWidget()
andparent()
theo
andd
are nullI give up.
parent()
at least should beQueryWidget*
. What class isQueryResultView
derived from?Instead of puzzling over whether a signal is emitted, and whether that is connected to your slot, try calling some direct method of
QueryWidget
on the cast-pointer where you can check its result. For example, you couldsetObjectName()
onqueryWidget
and then verify what a laterobjectName()
off your pointer actually returns.@JonB, you asked for that
parent
/parentWidget
BUT I didn't know at that point that If I set parent explicitly, it doesn't matter, the widget that contains my widget automatically becomes the parent. -
@J-Hilk, everywhere I've
Q_OBJECT
at the top like this:class MyObjectName : public QWidget{ Q_OBJECT public: ...
Yes, you get those parent()/parentWidget() from
QWidget
. Philosophically, it could be bad design BUT if you could do so, it'll reduce significant amount of unnecessary code bloat.@Emon-Haque said in How to emit parentWidget's signal from its child?:
Philosophically, it could be bad design BUT if you could do so, it'll reduce significant amount of unnecessary code bloat
oh wow, are you also one of those that have everything public then?
If inflexible, intervened spaghetti code is your style, fine enough.Anyway,
I'm glad you got your issue solved! -
@Emon-Haque said in How to emit parentWidget's signal from its child?:
Philosophically, it could be bad design BUT if you could do so, it'll reduce significant amount of unnecessary code bloat
oh wow, are you also one of those that have everything public then?
If inflexible, intervened spaghetti code is your style, fine enough.Anyway,
I'm glad you got your issue solved!@J-Hilk, not only
public
when it's simple, a coupleglobal
as well. In other framework I've spent a couple of years and tried to keep theMVVM
principle everywhere and what I realized is if I keep myself stuck in those principles it makes things harder so whenever necessary/simple I get out of those.For example, if someone wants to show a dialog and want the result of the dialog for something else in some function, why would he create a dialog factory for that? Just instantiate a dialog and call show/exec in the place where necessary.
-
Why don't use just make a signal/slot connection between the 'child' widget and the slot of whatever other QObject you want something triggered from the 'child' object. It makes it much clearer what's happening than relying on the parent-child, or even worse, grandparent-child relationships.
-
Why don't use just make a signal/slot connection between the 'child' widget and the slot of whatever other QObject you want something triggered from the 'child' object. It makes it much clearer what's happening than relying on the parent-child, or even worse, grandparent-child relationships.
@mchinand, in this case it'll be complicated. 2 separate main views (widgets in the stacked widget) rely on that signal. In between child widgets inside QueryWidget, that's ok.
TableWidget, which is not a child of QueryWidget, also relies on this signal and in the MainWindow, I instantiate QueryWidget and TableWidget. In this case, I either have to make the child widget of the QueryWidget, that emits the signal, public (or can make it more complex by creating a getter) or create another signal in QueryWidget to connect to the slot of TableWidget.
So, to me, the best approach is to make a signal in QueryWidget and let it be used by every other widgets that needs it, be it child or sibling.