How to emit parentWidget's signal from its child?
-
In the main window, I've these widgets:
stack = new QStackedWidget(this); queryWidget = new QueryWidget(stack); tableWidget = new TableWidget(stack); stack->addWidget(queryWidget); stack->addWidget(tableWidget); setCentralWidget(stack); ... connect(queryWidget, &QueryWidget::noSelect, tableWidget, &TableWidget::onNoSelect);queryWidgetadds these as children in its constructor:QueryWidget::QueryWidget(QWidget *parent) : QWidget(parent){ objects = new ObjectsView(this); codeEditor = new QueryView(this); queryresult = new QueryResultView(this); log = new LogView(this); .... )in the
queryresultI've following function where I tried toemitthenoSelectsignal ofQueryWidget:void QueryResultView::executeQuery(const QString &query){ ... model->setQuery(query, db); if(model->query().isSelect()) while (model->canFetchMore()) model->fetchMore(); else{ //auto w = dynamic_cast<QueryWidget*>(parentWidget()); auto w = static_cast<QueryWidget*>(parentWidget()); emit w->noSelect(query); } ... }with
dynamic_castapp crashes and withstatic_cast, doesn't crash BUT looks like it doesn't emit the signal. In thetableWidget, I've this slot:void TableWidget::onNoSelect(const QString &query){ qDebug() << "Here"; if(query.contains(tableName)) refreshModel(); }and I don't see it printing
Herein the Qt Creator output. -
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. -
In the main window, I've these widgets:
stack = new QStackedWidget(this); queryWidget = new QueryWidget(stack); tableWidget = new TableWidget(stack); stack->addWidget(queryWidget); stack->addWidget(tableWidget); setCentralWidget(stack); ... connect(queryWidget, &QueryWidget::noSelect, tableWidget, &TableWidget::onNoSelect);queryWidgetadds these as children in its constructor:QueryWidget::QueryWidget(QWidget *parent) : QWidget(parent){ objects = new ObjectsView(this); codeEditor = new QueryView(this); queryresult = new QueryResultView(this); log = new LogView(this); .... )in the
queryresultI've following function where I tried toemitthenoSelectsignal ofQueryWidget:void QueryResultView::executeQuery(const QString &query){ ... model->setQuery(query, db); if(model->query().isSelect()) while (model->canFetchMore()) model->fetchMore(); else{ //auto w = dynamic_cast<QueryWidget*>(parentWidget()); auto w = static_cast<QueryWidget*>(parentWidget()); emit w->noSelect(query); } ... }with
dynamic_castapp crashes and withstatic_cast, doesn't crash BUT looks like it doesn't emit the signal. In thetableWidget, I've this slot:void TableWidget::onNoSelect(const QString &query){ qDebug() << "Here"; if(query.contains(tableName)) refreshModel(); }and I don't see it printing
Herein the Qt Creator output.@Emon-Haque
dynamic_cast<>does not crash. But it does returnnullptrif the object is not of the desired type, and if you then deference the pointer without checking that will crash.static_cast<>does not check or returnnullptr, it takes your word for it. If yourw->noSelect(query)then does not crash, either it was indeed aQueryWidget*or you are "very lucky/unlucky" thatw->noSelect(query)did not crash.Here you could have used
qobject_cast<>instead of either of these (generally preferred forQObject-derived classes).Go back and use either
dynamic_cast<>orqobject_cast<>. Check whether they returnnullptr. You can also look in the debugger at whatparentWidget()is actually returning (store it in a variable to examine).In principle you can choose to
emita signal viasomeObject->signalMethod()from another class/instance. So I'm not sure why your slot would not then be called if everything were legit here. However, assuming yourdynamic_cast<>returnednullptr, it probably is not legit. -
@Emon-Haque
dynamic_cast<>does not crash. But it does returnnullptrif the object is not of the desired type, and if you then deference the pointer without checking that will crash.static_cast<>does not check or returnnullptr, it takes your word for it. If yourw->noSelect(query)then does not crash, either it was indeed aQueryWidget*or you are "very lucky/unlucky" thatw->noSelect(query)did not crash.Here you could have used
qobject_cast<>instead of either of these (generally preferred forQObject-derived classes).Go back and use either
dynamic_cast<>orqobject_cast<>. Check whether they returnnullptr. You can also look in the debugger at whatparentWidget()is actually returning (store it in a variable to examine).In principle you can choose to
emita signal viasomeObject->signalMethod()from another class/instance. So I'm not sure why your slot would not then be called if everything were legit here. However, assuming yourdynamic_cast<>returnednullptr, it probably is not legit.@JonB, I've tried all 3 three of these:
auto o = qobject_cast<QueryWidget*>(parentWidget()); auto d = dynamic_cast<QueryWidget*>(parentWidget()); auto s = static_cast<QueryWidget*>(parentWidget());Here's what I got with a breakpoint on
emit:looks like both
oanddarenullptrBUTsgot it right. If I changeparentWidget()toparent(), all ofo,dandsget it right BUT it doesn't emit the signal.EDIT
Not in both cases,parentWidget()andparent()theoanddare null BUT s gets the widget in either case BUT it doesn't emit the signal so I don't see slot printingHerein the output. No threading is involved. -
@JonB, I've tried all 3 three of these:
auto o = qobject_cast<QueryWidget*>(parentWidget()); auto d = dynamic_cast<QueryWidget*>(parentWidget()); auto s = static_cast<QueryWidget*>(parentWidget());Here's what I got with a breakpoint on
emit:looks like both
oanddarenullptrBUTsgot it right. If I changeparentWidget()toparent(), all ofo,dandsget it right BUT it doesn't emit the signal.EDIT
Not in both cases,parentWidget()andparent()theoanddare null BUT s gets the widget in either case BUT it doesn't emit the signal so I don't see slot printingHerein the output. No threading is involved.@Emon-Haque said in How to emit parentWidget's signal from its child?:
BUT
sgot 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 itsparentshould be aQueryWidget.Not[e] in both cases,
parentWidget()andparent()theoanddare nullI give up.
parent()at least should beQueryWidget*. What class isQueryResultViewderived from?Instead of puzzling over whether a signal is emitted, and whether that is connected to your slot, try calling some direct method of
QueryWidgeton the cast-pointer where you can check its result. For example, you couldsetObjectName()onqueryWidgetand then verify what a laterobjectName()off your pointer actually returns. -
@Emon-Haque said in How to emit parentWidget's signal from its child?:
BUT
sgot 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 itsparentshould be aQueryWidget.Not[e] in both cases,
parentWidget()andparent()theoanddare nullI give up.
parent()at least should beQueryWidget*. What class isQueryResultViewderived from?Instead of puzzling over whether a signal is emitted, and whether that is connected to your slot, try calling some direct method of
QueryWidgeton the cast-pointer where you can check its result. For example, you couldsetObjectName()onqueryWidgetand then verify what a laterobjectName()off your pointer actually returns.@JonB,
class QueryResultView : public QWidget { ... };EDIT
Here's another snapshot with bothparent()andparentWidget(): -
@JonB,
class QueryResultView : public QWidget { ... };EDIT
Here's another snapshot with bothparent()andparentWidget():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 could setObjectName() on queryWidget and then verify what a later objectName() off your pointer actually returns.
-
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 could setObjectName() on queryWidget and then verify what a later objectName() off your pointer actually returns.
@JonB, it:
auto os = static_cast<QueryWidget*>(parentWidget()); os->setObjectName("Test"); os = static_cast<QueryWidget*>(parentWidget()); qDebug() << os->objectName();prints
Test -
@JonB, it:
auto os = static_cast<QueryWidget*>(parentWidget()); os->setObjectName("Test"); os = static_cast<QueryWidget*>(parentWidget()); qDebug() << os->objectName();prints
Test@Emon-Haque
That is not what I meant, it doesn't prove anything. ThesetObjectName()must be done on the actualQueryWidgetinstance 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_castvariables, do not rely on what the debugger is showing you.I do not know how those can be
nullptrwhen 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. -
@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 actualQueryWidgetinstance 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_castvariables, do not rely on what the debugger is showing you.I do not know how those can be
nullptrwhen 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_castanddynamic_castreturnsnullptr? -
@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_OBJECTat 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
castso it'll enter theelseblock BUT the thing that will print inelseblock is incorrect because:QueryWidget::QueryWidget(QWidget *parent) : QWidget(parent){ .. queryresult = new QueryResultView(this); .... )QueryWidgetis indeed the parent ofqueryresult. -
@mpergand, that's always null with that
castso it'll enter theelseblock BUT the thing that will print inelseblock is incorrect because:QueryWidget::QueryWidget(QWidget *parent) : QWidget(parent){ .. queryresult = new QueryResultView(this); .... )QueryWidgetis 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
thisactually 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
slotof&TableWidget::onNoSelectauto scp = static_cast<QueryWidget*>(parent()->parent()); emit scp->noSelect(query); qDebug() << parent()->parent() << parentWidget()->parent();and that
qDebugprints:QueryWidget(0x2245c30, name = "Test") QueryWidget(0x2245c30, name = "Test")Thanks for the insight.