Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. QObject::findChild() - "simple" case not working
Forum Updated to NodeBB v4.3 + New Features

QObject::findChild() - "simple" case not working

Scheduled Pinned Locked Moved Unsolved QML and Qt Quick
12 Posts 3 Posters 11.7k Views
  • 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.
  • Tom assoT Offline
    Tom assoT Offline
    Tom asso
    wrote on last edited by Tom asso
    #3

    @jsulm - thanks very much! That was a clumsy typo in my post, but using the correct name in my actual code still does not find the Surface3DSeries object. Another test - following is a qml that creates several items: Window, Item, Surface3D, Surface3DSeries, and Button - each has a unique objectName. Of these, my C++ code does NOT find the Window and Surface3DSeries objects. Why is that?

    import QtQuick 2.12
    import QtQuick.Window 2.12
    import QtQuick.Controls 2.3
    import QtDataVisualization 1.2
    
    Window {
        objectName: "myWindow"
        visible: true
        width: 640
        height: 480
        id: mainView
    
        Item {
            objectName: "myItem"
            width: parent.width
            height: parent.height
    
            Surface3D {
                objectName: "mySurface"
                width: parent.width
                height: parent.height
    
                Surface3DSeries {
                     objectName: "mySurfaceSeries"
    
                    ItemModelSurfaceDataProxy {
                        itemModel: dataModel
                        rowRole: "longitude"
                        columnRole: "latitude"
                        yPosRole: "elevation"
                    }
                }
            }
            ListModel {
                id: dataModel
                ListElement{ longitude: "20"; latitude: "10"; elevation: "1000"; }
                ListElement{ longitude: "21"; latitude: "10"; elevation: "1200"; }
                ListElement{ longitude: "22"; latitude: "10"; elevation: "900"; }
                ListElement{ longitude: "23"; latitude: "10"; elevation: "1100"; }
                ListElement{ longitude: "20"; latitude: "11"; elevation: "1000"; }
                ListElement{ longitude: "21"; latitude: "11"; elevation: "1300"; }
                ListElement{ longitude: "22"; latitude: "11"; elevation: "1250"; }
                ListElement{ longitude: "23"; latitude: "11"; elevation: "1200"; }
            }
    
            Button {
                objectName: "myButton"
                text: qsTr("my button")
            }
        }
    }
    

    Here is main.cpp snippet, which tries to find each of the object names:

        QObject *root = qobject_cast<QObject *>(engine.rootObjects().value(0));
        char *objectName = "myWindow";
        findObject(objectName, root);
    
        objectName = "myItem";
        findObject(objectName, root);
    
        objectName = "mySurface";
        findObject(objectName, root);
    
        objectName = "mySurfaceSeries";
        findObject(objectName, root);
    
        objectName = "myButton";
        findObject(objectName, root);
    
        return app.exec();
    }
    
    QObject *findObject(char *name, QObject *root) {
        QObject *object = root->findChild<QObject *>(name);
        if (!object) {
            qDebug() << "Couldn't find object " << name;
        }
        else {
            qDebug() << "Found object " << name;
        }
        return object;
    }
    

    Here's the program output:

    Couldn't find object  myWindow
    Found object  myItem
    Found object  mySurface
    Couldn't find object  mySurfaceSeries
    Found object  myButton
    

    Again, thanks for your help.

    1 Reply Last reply
    0
    • Tom assoT Offline
      Tom assoT Offline
      Tom asso
      wrote on last edited by
      #4

      @jsulm - I thought my qml might have some weird problem, but the qmlsurface example provided with Qt seems to have the same issue; C++ code in main.cpp cannot find a Surface3DSeries in main.qml. I slightly modified the example's main.qml, adding objectName "heightSeries" and objectName "surfaceSeries" to the two Surface3DSeries:

                 Surface3DSeries {
                      id: surfaceSeries
                      objectName: "surfaceSeries"
                      flatShadingEnabled: false
                      drawMode: Surface3DSeries.DrawSurface
      
                      ItemModelSurfaceDataProxy {
                          //! [5]
                          //! [6]
                          itemModel: surfaceData.model
                          rowRole: "longitude"
                          columnRole: "latitude"
                          yPosRole: "height"
                      }
                      //! [6]
                      onDrawModeChanged: checkState()
                  }
                  //! [4]
                  Surface3DSeries {
                      id: heightSeries
                      objectName: "heightSeries"
                      flatShadingEnabled: false
                      drawMode: Surface3DSeries.DrawSurface
                      visible: false
      

      I slightly modified the example's main.cpp to search for objects named "heightView" and "surfaceView":

         viewer.show();
      
          QObject *root = viewer.rootObject();
          QObject *object = root->findChild<QObject *>("surfaceSeries");
          if (!object) {
              qDebug() << "Could not find surfaceSeries";
          }
          else {
              qDebug() << "Found surfaceSeries";
          }
          
          object = root->findChild<QObject *>("heightSeries");
          if (!object) {
              qDebug() << "Could not find heightSeries";
          }
          else {
              qDebug() << "Found heightSeries";
          }
          return app.exec();
      

      And the above code cannot find "surfaceSeries" or "heightSeries". I must have some fundamental misunderstanding of how the Qt object hierarchy works... :-(

      jsulmJ 1 Reply Last reply
      0
      • Tom assoT Tom asso

        @jsulm - I thought my qml might have some weird problem, but the qmlsurface example provided with Qt seems to have the same issue; C++ code in main.cpp cannot find a Surface3DSeries in main.qml. I slightly modified the example's main.qml, adding objectName "heightSeries" and objectName "surfaceSeries" to the two Surface3DSeries:

                   Surface3DSeries {
                        id: surfaceSeries
                        objectName: "surfaceSeries"
                        flatShadingEnabled: false
                        drawMode: Surface3DSeries.DrawSurface
        
                        ItemModelSurfaceDataProxy {
                            //! [5]
                            //! [6]
                            itemModel: surfaceData.model
                            rowRole: "longitude"
                            columnRole: "latitude"
                            yPosRole: "height"
                        }
                        //! [6]
                        onDrawModeChanged: checkState()
                    }
                    //! [4]
                    Surface3DSeries {
                        id: heightSeries
                        objectName: "heightSeries"
                        flatShadingEnabled: false
                        drawMode: Surface3DSeries.DrawSurface
                        visible: false
        

        I slightly modified the example's main.cpp to search for objects named "heightView" and "surfaceView":

           viewer.show();
        
            QObject *root = viewer.rootObject();
            QObject *object = root->findChild<QObject *>("surfaceSeries");
            if (!object) {
                qDebug() << "Could not find surfaceSeries";
            }
            else {
                qDebug() << "Found surfaceSeries";
            }
            
            object = root->findChild<QObject *>("heightSeries");
            if (!object) {
                qDebug() << "Could not find heightSeries";
            }
            else {
                qDebug() << "Found heightSeries";
            }
            return app.exec();
        

        And the above code cannot find "surfaceSeries" or "heightSeries". I must have some fundamental misunderstanding of how the Qt object hierarchy works... :-(

        jsulmJ Offline
        jsulmJ Offline
        jsulm
        Lifetime Qt Champion
        wrote on last edited by
        #5

        @tom-asso I'm not sure, but maybe you're searching for the object too early? I mean, if QML loading is asynchronous and you try to search just after load() the QML is maybe not yet completely loaded? Try to use a timer and search after one second or so just to check.

        https://forum.qt.io/topic/113070/qt-code-of-conduct

        1 Reply Last reply
        1
        • Tom assoT Offline
          Tom assoT Offline
          Tom asso
          wrote on last edited by
          #6

          @jsulm - added sleep(2) right after engine.load(url) in main.cpp - does not alter the result...
          Anyone able to reproduce my results?
          Thanks!

          JonBJ 1 Reply Last reply
          0
          • Tom assoT Tom asso

            @jsulm - added sleep(2) right after engine.load(url) in main.cpp - does not alter the result...
            Anyone able to reproduce my results?
            Thanks!

            JonBJ Offline
            JonBJ Offline
            JonB
            wrote on last edited by JonB
            #7

            @tom-asso
            When @jsulm says "if QML loading is asynchronous", if that happens in the same process (I assume it does, I don't use QML) your sleep(2) won't help! If you wish to check the issue he suggests I think you do need to set up a QTimer.

            Or better, if I understand right, there is signal https://doc.qt.io/qt-5/qqmlapplicationengine.html#objectCreated for when loading is completed? Ah, I see you have a slot for this, you could try your search from there.

            1 Reply Last reply
            2
            • Tom assoT Offline
              Tom assoT Offline
              Tom asso
              wrote on last edited by Tom asso
              #8

              @jonb said in QObject::findChild() - "simple" case not working:

              https://doc.qt.io/qt-5/qqmlapplicationengine.html#objectCreated

              @jonB - thanks! I set up a QTimer as advised, but the C++ still does not find objects for Window or Surface3DSeries after several seconds. Both the Window and Surface3DSeries clearly exist, e.g. the Surface3D is displayed by the app.

              main.cpp is searching this root object:

                 QObject *root = 
                 qobject_cast<QObject *>(engine.rootObjects().value(0));
              

              All qml objects should be children of that root, is that right?

              JonBJ 1 Reply Last reply
              0
              • Tom assoT Offline
                Tom assoT Offline
                Tom asso
                wrote on last edited by
                #9

                Listing all children of the root object, I do not see one of type QSurface3DSeries, even though the qml declares a Surface3DSeries and Surface3D is displayed with the data specified by the series.

                I've modified main.cpp to list names and types of all objects returned by root->findChildren():

                    qDebug() << "found " << children.size() << "children";
                    for (int i = 0; i < children.size(); i++) {
                        qDebug() << "child name " << children[i]->objectName() << ", class " << children[i]->metaObject()->className();
                    }
                

                But there is no child of type QSurface3DSeries under root,:

                found  9 children
                child name  "" , class  QQuickRootItem
                child name  "myItem" , class  QQuickItem
                child name  "mySurface" , class  QtDataVisualization::DeclarativeSurface
                child name  "" , class  QQmlListModel
                child name  "myButton" , class  QQuickButton
                child name  "" , class  QQuickRectangle
                child name  "" , class  QQuickPen
                child name  "" , class  QQuickIconLabel
                child name  "label" , class  QQuickMnemonicLabel
                
                1 Reply Last reply
                0
                • Tom assoT Tom asso

                  @jonb said in QObject::findChild() - "simple" case not working:

                  https://doc.qt.io/qt-5/qqmlapplicationengine.html#objectCreated

                  @jonB - thanks! I set up a QTimer as advised, but the C++ still does not find objects for Window or Surface3DSeries after several seconds. Both the Window and Surface3DSeries clearly exist, e.g. the Surface3D is displayed by the app.

                  main.cpp is searching this root object:

                     QObject *root = 
                     qobject_cast<QObject *>(engine.rootObjects().value(0));
                  

                  All qml objects should be children of that root, is that right?

                  JonBJ Offline
                  JonBJ Offline
                  JonB
                  wrote on last edited by JonB
                  #10

                  @tom-asso
                  I would not know about the "all QML objects being children of the root", but it does not seem unreasonable.

                  For the Window/myWindow one, because that's the top-level node maybe that is what engine.rootObjects().value(0) is, and therefore findChild() does not find it because it looks one level down, I don't know.

                  If engine.rootObjects() can be multiple objects you could always try searching each of them just in case.

                  For the SurfaceSeries/mySurfaceSeries, if it were me I'd just try with a plain findChild<QSurface3DSeries*>(), no name, to find any.

                  EDIT
                  My reply has crossed with your latest. You are doing the right thing by debug-walking the hierarchy. You need to go down now into "mySurface" and see what is there.

                  1 Reply Last reply
                  0
                  • Tom assoT Offline
                    Tom assoT Offline
                    Tom asso
                    wrote on last edited by
                    #11

                    Checked to see if mySurface has children and it does not.
                    My ultimate goal is to access Surface3DSeries from C++. I'm thinking I could do that by accessing the mySurface object, but my debug shows mySurface is of type QtDataVisualization::DeclarativeSurface, which does not seem to be documented. :-(

                    JonBJ 1 Reply Last reply
                    0
                    • Tom assoT Tom asso

                      Checked to see if mySurface has children and it does not.
                      My ultimate goal is to access Surface3DSeries from C++. I'm thinking I could do that by accessing the mySurface object, but my debug shows mySurface is of type QtDataVisualization::DeclarativeSurface, which does not seem to be documented. :-(

                      JonBJ Offline
                      JonBJ Offline
                      JonB
                      wrote on last edited by JonB
                      #12

                      @tom-asso

                      Checked to see if mySurface has children and it does not.

                      So the implementation does not just create in the fashion you hoped/expected. They have wrapped it away differently from the declarative.

                      My ultimate goal is to access Surface3DSeries from C++.

                      You might want to start a new thread for this, as it's very different from current title. Though expert people may see it there anyway.

                      QtDataVisualization::DeclarativeSurface, which does not seem to be documented

                      And so probably not intended to be used. But you could look at https://code.woboq.org/qt5/qtdatavis3d/src/datavisualizationqml2/declarativesurface.cpp.html, it has functions like QQmlListProperty<QSurface3DSeries> DeclarativeSurface::seriesList() which presumably accesses the series. Use at your own risk.

                      1 Reply Last reply
                      1

                      • Login

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