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. Need some guidance on using signals to communicate between QML and C++
QtWS25 Last Chance

Need some guidance on using signals to communicate between QML and C++

Scheduled Pinned Locked Moved QML and Qt Quick
13 Posts 2 Posters 7.3k 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.
  • M Offline
    M Offline
    mlong
    wrote on last edited by
    #4

    I find exposing the C++ slots to QML much simpler than trying to expose the QML signals to C++. But, I suppose it's just a matter of preference, necessity, and design.

    Software Engineer
    My views and opinions do not necessarily reflect those of anyone -- living or dead, real or fictional -- in this universe or any other similar multiverse node. Void where prohibited. Your mileage may vary. Caveat emptor.

    1 Reply Last reply
    0
    • P Offline
      P Offline
      pavneetarora
      wrote on last edited by
      #5

      Your method worked wonderfully once I figured out that I could use QmlApplicationViewer just like a QDeclarativeView:

      @
      QmlApplicationViewer viewer;
      viewer.setMainQmlFile(QLatin1String("qml/calcXY/main.qml"));
      viewer.rootContext()->setContextProperty("calcXYObject, &calcXYClass);
      viewer.showExpanded();
      @

      I was confused initially as to how to setContextProperty to the root of the "Page" that was relevant for my function invocations, but then I figured out that handing the root of the entire QML tree should suffice.

      So I suppose that I can set up all the various Calc classes (for the different functions to be calculated) using separate setContextProperty calls in main.cpp.

      1 Reply Last reply
      0
      • P Offline
        P Offline
        pavneetarora
        wrote on last edited by
        #6

        With the signal approach, things are complicated by the fact that if you use Qt Components the delayed instantiation of the page makes it difficult to set the signal up in main.cpp. Or am I missing something? The above example with the signal approach would read something like:

        @
        CalcXY calcXY;

        QObject rootObject = dynamic_cast<QObject>(viewer.rootObject());
        QObject::connect(rootObject, SIGNAL(calcXYSignal()),
        &calcXY, SLOT(calcXYSlot()));
        @

        but then I get the following error at runtime:

        @
        Object::connect: No such signal PageStackWindow_QMLTYPE_13::calcXYSignal()
        @

        which makes sense since calcXYSignal isn't declared in main.qml, which is the start page of the PageStack. It is declared in another QtComponent, calcxy.qml. One can easily imagine a set of such qml files: calcxy.qml, calcab.qml, calccd.qml, etc., each dealing with a specific function.

        Is there a way of making this signals example work with Qt Components which are instantiated as needed and so I am presuming one cannot search the QML tree to get the appropriate node?

        1 Reply Last reply
        0
        • M Offline
          M Offline
          mlong
          wrote on last edited by
          #7

          I'm not sure what hoops would have to be jumped through to dynamically search through the QML as needed. It may be possible, but I'm much too tired to think through it at the moment. At any rate, that's partially why I prefer to expose the C++ code to the QML. In my mind, the QML is much more dynamic and prone to change (either in the short-term, like loading and unloading of pages/components, or in the long-term via page redesign and layout changes and such) whereas the business logic (written in C++) is typically more stable and less likely to change as much. This way, your program only has to rely on a looser coupling between the C++ and QML than you'd have to have in order to have the C++ code know more details about the interface. I prefer to think of it as the solid, structured C++ code presenting itself to the QML, which is much more dynamic, fluid, and arbitrary.

          Granted, there are always other options and different designs and philosophies, but this is just my opinion based on my experience.

          Software Engineer
          My views and opinions do not necessarily reflect those of anyone -- living or dead, real or fictional -- in this universe or any other similar multiverse node. Void where prohibited. Your mileage may vary. Caveat emptor.

          1 Reply Last reply
          0
          • P Offline
            P Offline
            pavneetarora
            wrote on last edited by
            #8

            Your approach makes a lot of sense now that I have experimented a bit. The C++ object is a singleton and so the namespace will be consistent to the various Qt Components. I see now why you prefer to expose the C++ slots to the dynamic QML code.

            This will be the approach that I will take for my project.

            Thanks for your (late night) help. It certainly removed the logjam in me proceeding with development.

            1 Reply Last reply
            0
            • M Offline
              M Offline
              mlong
              wrote on last edited by
              #9

              It was my pleasure! I'm glad to help. If you have any other issues, feel free to ask! (And welcome to the forums, btw!)

              One more thing, if you feel your issue is solved, please edit the initial post and change the title to add [Solved] to the beginning. Thanks!

              Software Engineer
              My views and opinions do not necessarily reflect those of anyone -- living or dead, real or fictional -- in this universe or any other similar multiverse node. Void where prohibited. Your mileage may vary. Caveat emptor.

              1 Reply Last reply
              0
              • P Offline
                P Offline
                pavneetarora
                wrote on last edited by
                #10

                Okay, I thought that the flip side—that is getting and setting the values of QML components from C++—would be easier to get through given the link provided above, but I am still stuck at a basic conceptual level.

                My problem is two-fold:

                1. Say I have a Button and its associated TextField as a child:

                @
                Button {
                id: xButton
                x: 45
                y: 231
                text: "x"
                onClicked: calcXY.calcX()

                            Item {
                                property alias x: xTextField.text
                
                                TextField {
                                    id: xTextField
                                    /*
                                    anchors { left: parent.right; leftMargin: 10;
                                        verticalCenter: parent.verticalCenter }
                                        */
                                    y: 136
                                    width: 126
                                    height: 50
                                    text: "120"
                                }
                            }
                        }
                

                @

                I need to be able to access the value of the TextField in my C++ code. Again using the link given above, the example points to using a property. However, the example doesn't really go into how to access an existing property. So I have attempted to use the example given "here":http://stackoverflow.com/questions/9062189/how-to-modify-a-qml-text-from-c.

                The second problem listed below remains, but my first question is whether an intermediate Item wrapper is required at all? Is there no way to directly manipulate the text "property" in the TextField?

                And if the Item wrapper is required, then what is the best way to preserve the anchor relationship between xButton and xTextField? The code given above binds the anchors to Item, which isn't what I want.

                1. My second problem is more fundamental: how does one get the root of the QML stack anywhere other than in main where the viewer is created and set:

                @
                QmlApplicationViewer viewer;

                viewer.setMainQmlFile&#40;QLatin1String("qml/CalcXY/main.qml"&#41;);
                QObject *rootObject = viewer.rootObject();
                

                @

                In my CalcXY class, I need the root object if I am to use the example to affect the property x:

                @
                void CalcXY::calcXSlot()
                {
                qDebug() << "Property value:" << QDeclarativeProperty::read(rootObject, "x").toInt();
                }
                @

                In other words I need to have rootObject to navigate the QML tree. Is this a global variable? Do I need to set it up as a global in main, or is there a better method? How do I make rootObject visible inside the CalcXY object?

                Thanks.

                1 Reply Last reply
                0
                • M Offline
                  M Offline
                  mlong
                  wrote on last edited by
                  #11

                  It would be simpler to just let the calcX slot accept a parameter. Then you could just send the data into C++ when you call the slot. Again, this decouples the C++ code from the QML.

                  As in:
                  @
                  Button {
                  ...
                  onClicked: calcXY.calcX(xTextField.text);
                  }
                  @

                  The calcX slot could then emit its result via a signal which the QML code could reference and respond to.

                  Typically, if you find yourself needing your C++ code to dig down into the QML, there's probably some redesign that can be done.

                  Additionally, there's no need to wrap your TextField in an Item. TextField, itself, IS an Item.

                  Is there any particular reason you choose to have the TextField as a child of the Button? From the commented-out anchor code, it appears you intend them to be laid out next to each other on-screen. I would make them siblings:

                  @
                  Button {
                  id: xButton
                  ...
                  }

                  TextField {
                  id: xTextField
                  ...
                  }
                  @

                  (An item doesn't need to be a child in order to allow access to its properties.)

                  Software Engineer
                  My views and opinions do not necessarily reflect those of anyone -- living or dead, real or fictional -- in this universe or any other similar multiverse node. Void where prohibited. Your mileage may vary. Caveat emptor.

                  1 Reply Last reply
                  1
                  • P Offline
                    P Offline
                    pavneetarora
                    wrote on last edited by
                    #12

                    I had initially handcoded the QML with the TextField and Buttons as siblings, but in one of my manipulations with Designer, I think the TextFields (there are three Button/TextField combinations) adopted child relationships.

                    I'll give your approach a try right now.

                    Thanks.

                    1 Reply Last reply
                    0
                    • P Offline
                      P Offline
                      pavneetarora
                      wrote on last edited by
                      #13

                      Nearly there. I have the signal mechanism working from C++ being caught via Connections in the QML.

                      Just a quick question: how does one trap when the user has finished editing a TextField, i.e., by leaving the field. In my case such an event would indicate that the other values may be calculated based on this change. I have tried 'onActiveFocusChanged' but that triggers upon both entry and exit of the TextField. 'onTextChanged' triggers an event for every character stroke. My other guess 'onDataChanged' was reported as invalid by the compiler. I also cannot seem to find a comprehensive list of these for the Qt Components for Symbian. In the Docs they are listed for Qt classes.

                      Essentially I have a (linear) function of 3 variables. When one of the values changes (the event that I would like to trap for indicated by the user leaving the field), the other two values will get updated to keep the function consistent. It is this 'value change' that I am trying to trap inside QML:

                      @
                      onActiveFocusChanged: calcXYObject.setX(xTextField.text)

                                  /* If x has been recalculated because either y or z were changed. */
                                  Connections {
                                      target: calcXYObject
                                      onXHasChanged: console.log("x has changed")
                                  }
                      

                      @

                      This code triggers both on entry into the x TextField as well as exit from the same.

                      Thanks.

                      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