Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. How to emit parentWidget's signal from its child?
Forum Updated to NodeBB v4.3 + New Features

How to emit parentWidget's signal from its child?

Scheduled Pinned Locked Moved Solved General and Desktop
25 Posts 5 Posters 4.4k Views 3 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • D Offline
    D Offline
    deleted385
    wrote on last edited by
    #1

    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);
    

    queryWidget adds 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 queryresult I've following function where I tried to emit the noSelect signal of QueryWidget:

    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_cast app crashes and with static_cast, doesn't crash BUT looks like it doesn't emit the signal. In the tableWidget, I've this slot:

    void TableWidget::onNoSelect(const QString &query){
        qDebug() << "Here";
        if(query.contains(tableName)) refreshModel();
    }
    

    and I don't see it printing Here in the Qt Creator output.

    JonBJ 1 Reply Last reply
    0
    • M Offline
      M Offline
      mpergand
      wrote on last edited by mpergand
      #19

      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.

      D 1 Reply Last reply
      1
      • D deleted385

        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);
        

        queryWidget adds 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 queryresult I've following function where I tried to emit the noSelect signal of QueryWidget:

        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_cast app crashes and with static_cast, doesn't crash BUT looks like it doesn't emit the signal. In the tableWidget, I've this slot:

        void TableWidget::onNoSelect(const QString &query){
            qDebug() << "Here";
            if(query.contains(tableName)) refreshModel();
        }
        

        and I don't see it printing Here in the Qt Creator output.

        JonBJ Online
        JonBJ Online
        JonB
        wrote on last edited by JonB
        #2

        @Emon-Haque
        dynamic_cast<> does not crash. But it does return nullptr if 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 return nullptr, it takes your word for it. If your w->noSelect(query) then does not crash, either it was indeed a QueryWidget* or you are "very lucky/unlucky" that w->noSelect(query) did not crash.

        Here you could have used qobject_cast<> instead of either of these (generally preferred for QObject-derived classes).

        Go back and use either dynamic_cast<> or qobject_cast<>. Check whether they return nullptr. You can also look in the debugger at what parentWidget() is actually returning (store it in a variable to examine).

        In principle you can choose to emit a signal via someObject->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 your dynamic_cast<> returned nullptr, it probably is not legit.

        D 1 Reply Last reply
        1
        • JonBJ JonB

          @Emon-Haque
          dynamic_cast<> does not crash. But it does return nullptr if 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 return nullptr, it takes your word for it. If your w->noSelect(query) then does not crash, either it was indeed a QueryWidget* or you are "very lucky/unlucky" that w->noSelect(query) did not crash.

          Here you could have used qobject_cast<> instead of either of these (generally preferred for QObject-derived classes).

          Go back and use either dynamic_cast<> or qobject_cast<>. Check whether they return nullptr. You can also look in the debugger at what parentWidget() is actually returning (store it in a variable to examine).

          In principle you can choose to emit a signal via someObject->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 your dynamic_cast<> returned nullptr, it probably is not legit.

          D Offline
          D Offline
          deleted385
          wrote on last edited by deleted385
          #3

          @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:

          cap.PNG

          looks like both o and d are nullptr BUT s got it right. If I change parentWidget() to parent(), all of o, d and s get it right BUT it doesn't emit the signal.

          EDIT
          Not in both cases, parentWidget() and parent() the o and d are null BUT s gets the widget in either case BUT it doesn't emit the signal so I don't see slot printing Here in the output. No threading is involved.

          JonBJ 1 Reply Last reply
          0
          • D deleted385

            @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:

            cap.PNG

            looks like both o and d are nullptr BUT s got it right. If I change parentWidget() to parent(), all of o, d and s get it right BUT it doesn't emit the signal.

            EDIT
            Not in both cases, parentWidget() and parent() the o and d are null BUT s gets the widget in either case BUT it doesn't emit the signal so I don't see slot printing Here in the output. No threading is involved.

            JonBJ Online
            JonBJ Online
            JonB
            wrote on last edited by
            #4

            @Emon-Haque said in How to emit parentWidget's signal from its child?:

            BUT s got it right

            No, it did not! As I wrote, with static_cast<> " does not check or return nullptr, it takes your word for it. " But here you apparently lied to it, because the other two tell you that parentWidget() is not a QueryWidget*. So goodness knows what happens when you then go w->noSelect(). Do not use static_cast<>!

            So what is your QueryResultView, and what is its parentWidget() or parent()?

            Ah: queryresult = new QueryResultView(this);, so its parent should be a QueryWidget.

            Not[e] in both cases, parentWidget() and parent() the o and d are null

            I give up. parent() at least should be QueryWidget*. What class is QueryResultView 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 could setObjectName() on queryWidget and then verify what a later objectName() off your pointer actually returns.

            D 2 Replies Last reply
            1
            • JonBJ JonB

              @Emon-Haque said in How to emit parentWidget's signal from its child?:

              BUT s got it right

              No, it did not! As I wrote, with static_cast<> " does not check or return nullptr, it takes your word for it. " But here you apparently lied to it, because the other two tell you that parentWidget() is not a QueryWidget*. So goodness knows what happens when you then go w->noSelect(). Do not use static_cast<>!

              So what is your QueryResultView, and what is its parentWidget() or parent()?

              Ah: queryresult = new QueryResultView(this);, so its parent should be a QueryWidget.

              Not[e] in both cases, parentWidget() and parent() the o and d are null

              I give up. parent() at least should be QueryWidget*. What class is QueryResultView 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 could setObjectName() on queryWidget and then verify what a later objectName() off your pointer actually returns.

              D Offline
              D Offline
              deleted385
              wrote on last edited by deleted385
              #5

              @JonB, class QueryResultView : public QWidget { ... };

              EDIT
              Here's another snapshot with both parent() and parentWidget():

              cap2.PNG

              JonBJ 1 Reply Last reply
              0
              • D deleted385

                @JonB, class QueryResultView : public QWidget { ... };

                EDIT
                Here's another snapshot with both parent() and parentWidget():

                cap2.PNG

                JonBJ Online
                JonBJ Online
                JonB
                wrote on last edited by
                #6

                @Emon-Haque

                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.

                D 1 Reply Last reply
                0
                • JonBJ JonB

                  @Emon-Haque

                  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.

                  D Offline
                  D Offline
                  deleted385
                  wrote on last edited by
                  #7

                  @JonB, it:

                  auto os = static_cast<QueryWidget*>(parentWidget());
                  os->setObjectName("Test");
                  os = static_cast<QueryWidget*>(parentWidget());
                  qDebug() << os->objectName();
                  

                  prints Test

                  JonBJ 1 Reply Last reply
                  0
                  • D deleted385

                    @JonB, it:

                    auto os = static_cast<QueryWidget*>(parentWidget());
                    os->setObjectName("Test");
                    os = static_cast<QueryWidget*>(parentWidget());
                    qDebug() << os->objectName();
                    

                    prints Test

                    JonBJ Online
                    JonBJ Online
                    JonB
                    wrote on last edited by JonB
                    #8

                    @Emon-Haque
                    That is not what I meant, it doesn't prove anything. The setObjectName() must be done on the actual QueryWidget instance where it is created, not in this method. We are trying to find out what the object(s) pointed to here by parentWidget() and parent() 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 your static_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 of QueryWidget (nowhere near this method, and after you have connected the slot) you can call instance->noSelect(...); so that you know that works.

                    D 1 Reply Last reply
                    0
                    • M Offline
                      M Offline
                      mpergand
                      wrote on last edited by mpergand
                      #9
                      auto w = qobject_cast<QueryWidget*>(parentWidget());
                             
                       if(w)
                              emit w->noSelect(query);
                       else
                              qDebug()<<"parent() not a QueryWidget"<<parent();
                      
                      D 1 Reply Last reply
                      1
                      • J.HilkJ Online
                        J.HilkJ Online
                        J.Hilk
                        Moderators
                        wrote on last edited by J.Hilk
                        #10

                        @Emon-Haque said in How to emit parentWidget's signal from its child?:

                        parentWidget()

                        first of, what is parentWidget() thats a custom function, what does it do?
                        it is apparently a base QWidget function 😅, oops

                        secondly, 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.


                        Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


                        Q: What's that?
                        A: It's blue light.
                        Q: What does it do?
                        A: It turns blue.

                        M D 2 Replies Last reply
                        3
                        • J.HilkJ J.Hilk

                          @Emon-Haque said in How to emit parentWidget's signal from its child?:

                          parentWidget()

                          first of, what is parentWidget() thats a custom function, what does it do?
                          it is apparently a base QWidget function 😅, oops

                          secondly, 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.

                          M Offline
                          M Offline
                          mpergand
                          wrote on last edited by mpergand
                          #11

                          @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.

                          1 Reply Last reply
                          1
                          • JonBJ JonB

                            @Emon-Haque
                            That is not what I meant, it doesn't prove anything. The setObjectName() must be done on the actual QueryWidget instance where it is created, not in this method. We are trying to find out what the object(s) pointed to here by parentWidget() and parent() 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 your static_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 of QueryWidget (nowhere near this method, and after you have connected the slot) you can call instance->noSelect(...); so that you know that works.

                            D Offline
                            D Offline
                            deleted385
                            wrote on last edited by
                            #12

                            @JonB, looks like it returns another instance of QueryWidget. With setObjectName("Test"); in the costructor of QueryWidget, 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. Both qobject_cast and dynamic_cast returns nullptr?

                            1 Reply Last reply
                            0
                            • J.HilkJ J.Hilk

                              @Emon-Haque said in How to emit parentWidget's signal from its child?:

                              parentWidget()

                              first of, what is parentWidget() thats a custom function, what does it do?
                              it is apparently a base QWidget function 😅, oops

                              secondly, 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.

                              D Offline
                              D Offline
                              deleted385
                              wrote on last edited by
                              #13

                              @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.

                              J.HilkJ 1 Reply Last reply
                              0
                              • M mpergand
                                auto w = qobject_cast<QueryWidget*>(parentWidget());
                                       
                                 if(w)
                                        emit w->noSelect(query);
                                 else
                                        qDebug()<<"parent() not a QueryWidget"<<parent();
                                
                                D Offline
                                D Offline
                                deleted385
                                wrote on last edited by
                                #14

                                @mpergand, that's always null with that cast so it'll enter the else block BUT the thing that will print in else block is incorrect because:

                                QueryWidget::QueryWidget(QWidget *parent) : QWidget(parent){
                                    ..
                                    queryresult = new QueryResultView(this);
                                    ....
                                )
                                

                                QueryWidget is indeed the parent of queryresult.

                                M 1 Reply Last reply
                                0
                                • D deleted385

                                  @mpergand, that's always null with that cast so it'll enter the else block BUT the thing that will print in else block is incorrect because:

                                  QueryWidget::QueryWidget(QWidget *parent) : QWidget(parent){
                                      ..
                                      queryresult = new QueryResultView(this);
                                      ....
                                  )
                                  

                                  QueryWidget is indeed the parent of queryresult.

                                  M Offline
                                  M Offline
                                  mpergand
                                  wrote on last edited by
                                  #15

                                  @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 :)

                                  D 1 Reply Last reply
                                  1
                                  • M mpergand

                                    @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 :)

                                    D Offline
                                    D Offline
                                    deleted385
                                    wrote on last edited by
                                    #16

                                    @mpergand, what?

                                    M 1 Reply Last reply
                                    0
                                    • D deleted385

                                      @mpergand, what?

                                      M Offline
                                      M Offline
                                      mpergand
                                      wrote on last edited by
                                      #17

                                      @Emon-Haque
                                      Are you sure QueryResultView is not reapparented
                                      What parent() prints at the end of the constructor ?

                                      D 1 Reply Last reply
                                      1
                                      • M mpergand

                                        @Emon-Haque
                                        Are you sure QueryResultView is not reapparented
                                        What parent() prints at the end of the constructor ?

                                        D Offline
                                        D Offline
                                        deleted385
                                        wrote on last edited by deleted385
                                        #18

                                        @mpergand, hmm

                                        qDebug() << parent() << parentWidget();
                                        QSplitter(0x425d470) QSplitter(0x425d470)
                                        

                                        so this actually has no meaning there! as soon as I add it in QSplitter split2->addWidget(queryresult);
                                        the splitter becomes its parent. Now I'll try to work with its grand parent and will let you know what happens.

                                        1 Reply Last reply
                                        0
                                        • M Offline
                                          M Offline
                                          mpergand
                                          wrote on last edited by mpergand
                                          #19

                                          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.

                                          D 1 Reply Last reply
                                          1
                                          • M mpergand

                                            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.

                                            D Offline
                                            D Offline
                                            deleted385
                                            wrote on last edited by
                                            #20

                                            @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.

                                            1 Reply Last reply
                                            0

                                            • Login

                                            • Login or register to search.
                                            • First post
                                              Last post
                                            0
                                            • Categories
                                            • Recent
                                            • Tags
                                            • Popular
                                            • Users
                                            • Groups
                                            • Search
                                            • Get Qt Extensions
                                            • Unsolved