Table of Contents
gtkmm widget classes have signal accessor methods, such as
Gtk::Button::signal_clicked()
, which allow you to connect
your signal handler. Thanks to the flexibility of
libsigc++, the callback library used by gtkmm, the
signal handler can be almost any kind of function, but you will probably want
to use a class method. Among GTK C coders, these
signal handlers are often named callbacks.
Here's an example of a signal handler being connected to a signal:
#include <gtkmm/button.h> void on_button_clicked() { std::cout << "Hello World" << std::endl; } class some_class { public: some_class { button.signal_clicked().connect(sigc::ptr_fun(&on_button_clicked)); } private: Gtk::Button button {"Hello World"}; };
There's rather a lot to think about in this (non-functional) code. First let's identify the parties involved:
The signal handler is on_button_clicked()
.
We're hooking it up to the Gtk::Button
object called
button
.
When the Button emits its clicked
signal,
on_button_clicked()
will be called.
Now let's look at the connection again:
... button.signal_clicked().connect(sigc::ptr_fun(&on_button_clicked)); ...
Note that we don't pass a pointer to on_button_clicked()
directly to the signal's connect()
method. Instead, we
call sigc::ptr_fun()
, and pass the result to
connect()
.
sigc::ptr_fun()
generates a sigc::slot
.
A slot is an object which
looks and feels like a function, but is actually an object. These are also
known as function objects, or functors.
sigc::ptr_fun()
generates a slot for a standalone function or static method.
sigc::mem_fun()
generates a slot for a member method of a particular instance.
A C++ lambda expression is a functor which can be implicitly converted to a
sigc::slot
in the call to connect()
.
A lambda expression can be used instead of sigc::ptr_fun()
.
It's also possible to use a lambda expression instead of sigc::mem_fun()
,
but then you won't get automatic disconnection of the signal handler when a
sigc::trackable
-derived object goes out of scope.
Here's a slightly larger example of slots in action:
#include <gtkmm/button.h> void on_button_clicked() { std::cout << "Hello World" << std::endl; } class some_class { public: some_class { button.signal_clicked().connect(sigc::ptr_fun(&on_button_clicked)); button.signal_clicked().connect(sigc::mem_fun(*this, &some_class::on_button_clicked)); } void on_button_clicked(); private: Gtk::Button button {"Hello World"}; };
The first call to connect()
is just like the one we saw
last time; nothing new here.
The next is more interesting.
sigc::mem_fun()
is called with two arguments. The first
argument is *this
, which is the object that our
new slot will be pointing at. The second argument is a pointer to one of its
methods. This particular version of sigc::mem_fun()
creates a slot which will, when "called", call the pointed-to method of the
specified object.
Another thing to note about this example is that we made the call to
connect()
twice for the same signal object. This is
perfectly fine - when the button is clicked, both signal handlers will be
called.
We just told you that the button's clicked
signal is expecting
to call a method with no arguments. All signals have
requirements like this - you can't hook a function with two arguments
to a signal expecting none (unless you use an adapter, such as
sigc::bind()
, of course). Therefore, it's important to
know what type of signal handler you'll be expected to connect to a given
signal.