While developing tools and/or utilities using Daz Script, when one object (the “sender”) changes we often want another object (the “receiver”) to be notified of that change so that the receiving object can react accordingly. Generally speaking, we want objects to be able to communicate with each other when certain events occur. An example of this could be, when the user clicks a DzButton labeled “Browse…” in a dialog, convention suggests that perhaps a DzFileDialog would appear and allow the user to navigate to a file and select it.
Other toolkits achieve this type of interaction using a technique referred to as a callback. While traditional callbacks can be used to an extent in Daz Script 1), the Qt framework 2) provides an alternative and achieves this inter-object communication through its Signals and Slots mechanism.
A Signal is emitted by an object when its internal state has changed in some way that may be interesting to another object. Notice that many of the objects available to Daz Script have a dedicated 'Signals' section in their documentation.
Signals are not traditional methods. On the C++ side (i.e., the SDK), only the class that declares a signal and its descendants can “emit” (call) it, but in script causing a signal to “emit” can be accomplished by invoking the function on an instance of an object and passing in the value to emit.
sender.signal( "hello world!" );
NOTE: Signals cannot be defined in script - signals are defined by C++ classes.
As far as script is concerned, a Slot (signal handler) is any function that can be called in response to a signal - i.e. script functions and all script-accessible QObject (and derived) member functions with the exception of constructors.
In order for a signal to invoke a slot, a connection between the signal and slot must be established. A signal may have one or more slot connected to it. A slot may be listening (connected) to more than one signal.
When a signal is emitted, the slot(s) connected to it are executed immediately - as though a direct call to the function was made at the same point in the code. The signals and slots mechanism is completely independent of the GUI event loop when this occurs. Once each connected slot has returned, execution of the code that follows the signal being emitted will occur. If more than one slot is connected to a signal, each slot will be executed sequentially, in the order that their connections were established.
In script, establishing a connection is accomplished by using one of the following methods (in order of recommended use):
connect(…)
scriptConnect(…)
connect(…)
disconnect(…)
or it can result in a memory leak of the receiver object (and the connection) in future versions - see Disconnectingconnect( sender, “signal”, slot )
sender.signal.scriptConnect( slot )
sender.signal.connect( slot )
- deprecatedWith this type of connection:
slot
is the identifier (not quoted) of the function to connect toslot
can be a member function of a QObject (receiver), as in the first and second examplessignal
and slot
do not necessarily have to be compatible - the application will attempt to perform conversion of signal
arguments to match the types of slot
arguments.3)slot
can be a script function, as in the third exampleconnect( sender, "signal", QObject.slot );
sender.signal.scriptConnect( QObject.slot );
function scriptFunc() { // ... } // ... sender.signal.scriptConnect( scriptFunc );
connect( sender, “signal”, thisObject, slot )
- since 4.15.0.18sender.signal.scriptConnect( thisObject, slot )
sender.signal.connect( thisObject, slot )
- deprecatedWith this type of connection:
thisObject
is the object that will be bound to this
in the scope of the slot
function if slot
is a Functionfunction scriptFunc() { print( this.x ); } var oSomeObject = { x: 123 }; connect( sender, signal, oSomeObject, scriptFunc );
function scriptFunc() { print( this.x ); } var oSomeObject = { x: 123 }; sender.signal.scriptConnect( oSomeObject, scriptFunc );
connect( sender, “signal”, receiver, “slot” )
sender.signal.scriptConnect( receiver, “slot” )
sender.signal.connect( receiver, “slot” )
- deprecatedWith this type of connection:
receiver
is the object that will be bound to this
in the scope of the slot
functionvar oSomeObject = { x: 123, func: function() { print( this.x ); } }; connect( sender, "signal", oSomeObject, "func" );
var oSomeObject = { x: 123, func: function() { print( this.x ); } }; sender.signal.connect( oSomeObject, "func" );
When a signal or slot is overloaded, the application will attempt to pick the appropriate overload based on the actual types of the arguments involved in the function invocation. For example, if an object has slots someOverloadedSlot(int)
and someOverloadedSlot(QString)
, the following example will behave reasonably:
someQObject.someOverloadedSlot( 10 ); // calls the int overload someQObject.someOverloadedSlot( "10" ); // calls the QString overload
You can specify a particular overload by using array-style property access with the normalized signature of the C++ function as the property name:
someQObject['someOverloadedSlot(int)']( "10" ); // calls the int overload; the argument is converted to an int someQObject['someOverloadedSlot(QString)']( 10 ); // calls the QString overload; the argument is converted to a string
If the overloads have different number of arguments, the application will pick the overload with the argument count that best matches the actual number of arguments passed to the slot.
For overloaded signals, the application will throw an error if you try to connect to the signal by name; you have to refer to the signal with the full normalized signature of the particular overload you want to connect to.
NOTE: Due to changes in future versions of the Qt framework 4), this syntax may not be supported in future versions of the application and should therefore be avoided where possible.
Signal-Slot connections can also be disconnected. This occurs automatically when the object that emits the signal is destroyed. Similarly, if the object with the slot that receives the signal is destroyed, the connection is automatically broken.
Signal-Slot connections can also be broken programmatically via:
disconnect()
functionsconnect
in a connection statement with disconnect
scriptDisconnect()
functionsscriptConnect
in a connection statement with scriptDisconnect
disconnect()
functions - deprecatedconnect
in a connection statement with disconnect
When connect()
or disconnect()
succeeds, the function will return undefined
. If either function does not succeed a script exception will be thrown. Obtaining an error message from the resulting Error object can be accomplished as shown below.
var oSomeObject = { x: 123 }; try { sender.signal.connect( oSomeObject, "functionThatDoesNotExist" ); } catch (e) { print( e ); }
The descriptions provided on this page were adapted from relevant portions of the Qt documentation at: