Reputation: 16685
In QML it is impossible to call .disconnect()
without arguments for a signal:
file:mainwindow.qml:107: Error: Function.prototype.disconnect: no arguments given
So how can I disconnect ALL slots without specifying each of them?
Or maybe it is possible by passing signal object to C++
and disconnect it somehow there?
Or maybe any workaround exists?
The goal I want to reach is to change behavior of an object by connecting different slots to it's signal. For example:
object.disconnect() // disconnect all slots
object.connect(one_super_slot)
object.disconnect() // disconnect all slots
object.connect(another_super_slot)
Upvotes: 8
Views: 6125
Reputation: 11048
I didn't check to see if the Qt source has been updated, but even in 2024, using Qt 6.7, a QML error appears in the console if you call disconnect() without an argument.
As such, I don't think one can ever disconnect from to a JS lambda connection? I'm hoping when a QML object is destroyed those connections cease firing, but I'm adding some logical protections for that until I clarify this detail...
Upvotes: 0
Reputation: 96537
No. I looked at the source code in qv4objectwrapper.cpp
, and you can see this code:
void QObjectWrapper::initializeBindings(ExecutionEngine *engine)
{
engine->functionClass->prototype->defineDefaultProperty(QStringLiteral("connect"), method_connect);
engine->functionClass->prototype->defineDefaultProperty(QStringLiteral("disconnect"), method_disconnect);
}
Those are the only two methods that are added. If you look at the source code for method_disconnect()
you can see that it always requires one or two parameters, including the name of the slot to disconnect.
There is no disconnectAll()
unfortunately.
Upvotes: 6
Reputation: 16685
Okay, 5 minutes after my question I've made a workaround: connect only once to one signal that calls jsobject from inside:
Item {
property var fire
// Any qml object. In this example it is ActionExecutor which emits actionRequest
ActionExecutor {
//signal actionRequest(int actionType)
onActionRequest: fire(actionType)
}
Action {
shortcut: "Ctrl+S"
text: "One action"
onTriggered: {
parent.fire = function(actionType) {
console.log('one slot')
}
}
}
Action {
shortcut: "Ctrl+X"
text: "Another action"
onTriggered: {
parent.fire = function(actionType) {
console.log('Another slot')
}
}
}
}
So that js object can be reassigned many times as you want so you may change your behavior by reassigning this object. If you want to disconnect all simple assign undefined
to fire
. Also you can make a chain of "slots" by modifying code to something like:
Item {
property var fire
property var slots: [
function(actionType) {
console.log('1: ' + actionType)
},
function() {
console.log('2: ' + actionType)
},
function() {
console.log('3: ' + actionType)
}
]
// Any qml object. In this example it is ActionExecutor which emits actionRequest
ActionExecutor {
//signal actionRequest(int actionType)
onActionRequest: fire(actionType)
}
Action {
shortcut: "Ctrl+S"
text: "One action"
onTriggered: {
parent.fire = function(actionType) {
console.log('calling all custom JS-slots')
for (var i in slots) {
slots[i](actionType)
}
}
}
}
}
So anyone can implement own signal-slot architecture in qml as a simple javascript observer pattern. Enjoy.
Upvotes: 2