Article: Signals and slots
From DaevsGUI
WARNING: This page is outdated
General
The signal and slot system is a nifty feature that allows us to write code for certain events. With signals and slots we have one object which emits a signal, several slots can be connected to this object, each of which will be called when the signal is emitted. A slot is a function or a member function (or in a special case, a member function of the object which emits the signal, this is discussed further in the developers tutorials).
Several signal object can be connected to the same slot and several slots can be connected to the same signal object. The only restriction there is, however, is that functions should have similar prototypes.
Every slot (member) function must be of type:
void function(); void function(DaevsGUI::Component *); void function(const DaevsGUI::Component *);
We don't expect it to return anything, and the Component object that is passed is a pointer to the object of which the event occurred. Member functions may also be const. Whenever a signal is emitted with a const 'this' pointer, the non-const parametered function will not be called. Neither will the parametrized functions be called when no pointer is emitted to 'this' with an event.
DaevsGUI::Component is replaced by DaevsGUI::Resource for resources.
How it works
Every Component has a signals object in their public scope. The signals object keeps track of all slots that are connected and is able to emit a signal. So if we want to connect a slot, we'll need to contact the signals object. How is this done?
void function(DaevsGUI::Component *element) { std::cout << "Function invoked.\n"; } int main() { DaevsGUI::Component *component = new DaevsGUI::Component; component->signals[DaevsGUI::MouseButtonLeftDown].connect(&function); component->signals[DaevsGUI::MouseButtonLeftDown].emit(); delete component; }
Here we connect the function 'function' to event ID 'MouseButtonLeftDown'. This event is called whenever the left mouse button goes down, at least, when it's connected with an eventhandler. In this case we call it ourselves, we emit the signal and the function gets invoked.
The next case works more or less the same, however, this time we use member functions...joy! :D
class A { public: A() {} ~A() {} void memberfunction(DaevsGUI::Element *element) { std::cout << "Member function invoked.\n"; } }; int main() { A a; DaevsGUI::Component *component = new DaevsGUI::Component; component->signals[DaevsGUI::MouseButtonLeftDown].connect(&a, &A::memberfunction); component->signals[DaevsGUI::MouseButtonLeftDown].emit(); delete component; }
Note that an object must exist before a member function can be bound.
Disconnecting
We can also disconnect slots from their signal objects. We can do that in 3 ways: remember the ID the library provides, give a (unique) ID or not use ID's at all. The later is rather slow when disconnecting, so if you were to disconnect a few slots, use ID's :-). All 3 methods can be mixed, so for one slot you can remember the ID, while for the other you don't, etc.
Using ID's the library provides:
void function(DaevsGUI::Element *element) { std::cout << "Function invoked.\n"; } int main() { DaevsGUI::Component *component = new DaevsGUI::Component; int id = component->signals[DaevsGUI::MouseButtonLeftDown].connect(&function); component->signals[DaevsGUI::MouseButtonLeftDown].emit(); component->signals[DaevsGUI::MouseButtonLeftDown].disconnect(id); component->signals[DaevsGUI::MouseButtonLeftDown].emit(); // does nothing delete component; }
Using your own ID's:
enum { FUNCTION }; void function(DaevsGUI::Element *element) { std::cout << "Function invoked.\n"; } int main() { DaevsGUI::Component *component = new DaevsGUI::Component; int id = component->signals[DaevsGUI::MouseButtonLeftDown].connect(FUNCTION, &function); component->signals[DaevsGUI::MouseButtonLeftDown].emit(); component->signals[DaevsGUI::MouseButtonLeftDown].disconnect(FUNCTION); component->signals[DaevsGUI::MouseButtonLeftDown].emit(); // does nothing delete component; }
Using no ID's at all:
void function(DaevsGUI::Element *element) { std::cout << "Function invoked.\n"; } int main() { DaevsGUI::Component *component = new DaevsGUI::Component; int id = component->signals[DaevsGUI::MouseButtonLeftDown].connect(&function); component->signals[DaevsGUI::MouseButtonLeftDown].emit(); component->signals[DaevsGUI::MouseButtonLeftDown].disconnect(&function); // slow (when many slots are connected) component->signals[DaevsGUI::MouseButtonLeftDown].emit(); // does nothing delete component; }
