Reputation: 955
I'm working on a QML project. In the UI I'm working on, I need to both update slider from C++ and read the current value into C++ from QML. Properties seems to be the right solution. So far I've read different questions on SO without success Two way binding C++ model in QML, Changed Properties do not trigger signal, etc... In my current code I declared a property in my C++ class
class MyClass : public QObject {
Q_OBJECT
public:
MyClass(QObject*);
Q_PROPERTY(double myValue READ getMyValue WRITE setMyValue NOTIFY myValueChanged)
void setMyValue(double n) {
std::cerr << "myValue being update: " << n << "\n";
myValue = n;
}
double myValue = 30;
...
}
And exposed it into Qt via a singleton
qmlRegisterSingletonInstance("com.me.test", 1, 0, "MyClass", &myClass);
Then bound the C++ property to a QML slider
import com.me.test
ApplicationWindow {
Slider {
id: slider
height: 30
width: 100
from: 0
to: 100
value: myClass.myValue
onValueChanged {
console.log("value = " + value)
console.log("myClass.myValue = " + myClass.myValue)
}
/* Doesn't help
Binding {
target: slider
property: "value"
value: myClass.myValue
}*/
}
}
The binding seems to work. I can modify the value of myValue
then emit myValueChanged
to make QML update it's slider. But given that myClass.myValue
is bounded to slider.value
. I'd assume both values gets updated at the same time. But dragging the slider shows that they have different values. The following it what is printed in the console when I drag my slider.
qml: value = 19.863013698630137
qml: myClass.myValue = 30
Furthermore setMyValue
seems to not being called unless an explicit assignment is made like myClass.myValue = 0
. I also tried the Binding component without success. Why is this the case and could I make the C++ property updated whenever i drag the slider?
Qt: 6.2.1
Compiler: clang/gcc
OS: Windows/Linux
Update: tested a reverse binding. Still printing the same result
import com.me.test
ApplicationWindow {
Slider {
id: slider
height: 30
width: 100
from: 0
to: 100
value: myClass.myValue
onValueChanged {
console.log("value = " + value)
console.log("myClass.myValue = " + myClass.myValue)
}
Binding {
target: myClass
property: "myValue"
value: slider.value
}
}
}
Upvotes: 1
Views: 1022
Reputation: 3288
You're missing the signal when modifying the value:
Q_PROPERTY(double myValue READ getMyValue WRITE setMyValue NOTIFY myValueChanged)
This means that you promise you'll send the myValueChanged
signal whenever the C++ code changes the value. So the following should work:
void setMyValue(double n) {
std::cerr << "myValue being update: " << n << "\n";
myValue = n;
emit(myValueChanged());
}
Upvotes: 2
Reputation: 311
Here's a minimal working example of two way updating Slider:
main.cpp:
data dataObj;
engine.rootContext()->setContextProperty("dataCpp", (QObject*)&dataObj);
data.h:
class data : public QObject
{
Q_OBJECT
Q_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged)
public:
explicit data(QObject *parent = nullptr);
int value(void);
void setValue(int new_value);
public slots:
void reset(void);
signals:
void valueChanged();
private:
int dataValue;
};
data.cpp:
data::data(QObject *parent) : QObject(parent)
{
dataValue = 250;
}
int data::value()
{
return dataValue;
}
void data::setValue(int new_value)
{
if(dataValue != new_value)
{
qDebug() << "setting" << new_value;
dataValue = new_value;
emit valueChanged();
}
}
void data::reset()
{
if(dataValue != 0)
{
qDebug() << "resetting to 0";
dataValue = 0;
emit valueChanged();
}
}
main.qml:
Slider {
id: slider
height: 50
width: 500
from: 0
to: 500
live: false
value: dataCpp.value
onValueChanged: dataCpp.value = value
}
Button{
anchors.top: slider.bottom
text: "Reset"
onPressed: dataCpp.reset()
}
Upvotes: 0
Reputation: 76
To update C++ property from QML, you can use Binding
:
import com.me.test
ApplicationWindow {
Slider {
id: slider
height: 30
width: 100
from: 0
to: 100
value: myClass.myValue
onValueChanged {
console.log("value = " + value)
console.log("myClass.myValue = " + myClass.myValue)
}
// C++ property was bounded to QML above, now we should bind QML to C++
Binding {
target: myClass
property: "myValue"
value: slider.value
}
}
}
Upvotes: 0