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

First off, here is the context of the application: basic calculations need to be done using values in TextFields. Button labels for the TextFields are used to indicate value to be derived. For a simple, contrived example say you have a function y=x+1, and you want to have two fields for y and x and two buttons to indicate whether you are solving for y or x. So a calculator of sorts but for which value to be solved can be any of the operands.

So the approach I am taking is to create a calcXY C++ class with public slots into which QML signals for each button would tie into. So that when a user presses the Y button, the C++ class would take the value of x and calculate y, or conversely if a user presses the X button, calcXY would take the value of y and calculate x. However, I am not really clear on the best way to reference the QML component.

So, what I am hoping to get is a minimal example, which illustrates the signals and slots mechanism between QML and C++; one that shows how a button press can invoke a slot function in C++ which will then take the values in TextFields on the page to derive a result and then display it back on one of the TextField.

I imagine that this should be simple, standard fare but I cannot seem to get a template that works. The actual calculator is much more sophisticated, but the same principles would apply. Any help would be greatly appreciated.

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.

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:

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?

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.

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.

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.

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.

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:

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?

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

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.

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.