Reputation: 53
I want to use callback functionality in QML (using Qt5.5.1). When a sensor value changes, I want to call a function of the button, that was pressed at last. I am using standard QML objects without creating custom QML objects with cpp classes. I even got it to run, but I don't understand why it is working like this.
I expect that I need to call the levelChanged_ButtonCallback manually, but that results to TypeError: Property 'levelChanged_ButtonCallback' of object QQuickItem_QML_22(0xd6ab18) is not a function.
The function binded in onPressed is called whenever the level changes, which is good. It's also called whenever the button is pressed, which is not as planned, but doesn't really matter. My main concern is, that I don't really understand where/how the function is called, and I am not sure if there may occur unwanted behaviour.
(I added a timer to simulate sensor values. The two MouseAreas only differ in their color and btnId. In my actual app, I of course use a .qml-file for those buttons.)
Is this "clean code" or may it cause problems? Is there a clean way to do it with QML only or do I need to create custom QML objects via cpp classes? I don't see a way to do this with signals/slots, because depending which button was pressed at last, a different slot should be connected.
Item {
id: sensor
property int level: 0
property int levelTreshold: 3
property var levelChanged_ButtonCallback
Timer {
running: true
interval: 5000
repeat: true
onTriggered: {
if (sensor.level == 0) {
sensor.level = sensor.levelTreshold;
}
else {
sensor.level = 0;
}
console.log("sensor changed to " + sensor.level);
/* Not needed, but why? Causes error.*/
//sensor.levelChanged_ButtonCallback();
}
}
}
MouseArea {
width: 50
height: 50
property string btnId: "red"
onPressed: {
sensor.levelChanged_ButtonCallback = Qt.binding(function() {
if (sensor.level >= sensor.levelTreshold) {
console.log("Button pressed with force: " + btnId);
}
else {
console.log("Button pressed no force: " + btnId);
}
});
}
onReleased: {
sensor.levelChanged_ButtonCallback = Qt.binding(function() {
console.log("No button pressed, do nothing on level change! Release by: " + btnId);
});
}
Rectangle {
anchors.fill: parent
color: "red"
}
}
MouseArea {
x: 80
width: 50
height: 50
property string btnId: "blue"
onPressed: {
sensor.levelChanged_ButtonCallback = Qt.binding(function() {
if (sensor.level >= sensor.levelTreshold) {
console.log("Button pressed with force: " + btnId);
}
else {
console.log("Button pressed no force: " + btnId);
}
});
}
onReleased: {
sensor.levelChanged_ButtonCallback = Qt.binding(function() {
console.log("No button pressed, do nothing on level change! Release by: " + btnId);
});
}
Rectangle {
anchors.fill: parent
color: "blue"
}
}
Upvotes: 2
Views: 4102
Reputation: 130
If you change a value in QML you can detect that with an onPropertyChanged slot / function. That's how Qt works (Signals and Slots). No need to call that on your own.
One way to do it:
import QtQuick 2.12
import QtQuick.Window 2.12
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Item {
id: sensor
property var lastActiveButton: undefined
property int level: 0
property int levelTreshold: 3
property var levelChanged_ButtonCallback
onLevelChanged:{
if(lastActiveButton){
var lastButtonString = lastActiveButton === mouseRed ? "red" : "blue"
if(level >= levelTreshold) console.log("Button pressed with force: " + lastButtonString);
else console.log("Button pressed no force: " + lastButtonString);
}
else{
console.log("No button active...");
}
}
Timer {
running: true
interval: 5000
repeat: true
onTriggered: {
if (sensor.level == 0) sensor.level = sensor.levelTreshold;
else sensor.level = 0;
console.log("sensor changed to " + sensor.level);
}
}
}
MouseArea {
id: mouseRed
width: 50
height: 50
onPressed: sensor.lastActiveButton = this
onReleased: sensor.lastActiveButton = undefined
Rectangle {
anchors.fill: parent
color: "red"
}
}
MouseArea {
id: mouseBlue
x: 80
width: 50
height: 50
onPressed: sensor.lastActiveButton = this
onReleased: sensor.lastActiveButton = undefined
Rectangle {
anchors.fill: parent
color: "blue"
}
}
}
Upvotes: 3