It should be clear by now that if you want to react to an action, you must
connect its signal to a signal handler that you have written, so that
PHP-GTK 2 can call that function whenever the signal is triggered. Let's
look into how you can connect signals to signal handlers.
There are 4 main functions that you can use to connect signals to callbacks:
- connect_simple
- connect_simple_after
- connect
- connect_after
The *_after methods are used if you want your signal handlers to be invoked
after the ones connected using
connect and connect_simple. We will be
discussing only the connect_simple and
connect methods. The respective *_after methods behave in
the same way except for the fact that the signal handler is guaranteed to be
invoked only after those connected via connect or
connect_simple have.
First we'll look into how to connect a signal to a signal handler in the most
simplest way. We'll be using, you guessed it, the
connect_simple method.
Of course, it is vital that you know the names of the signals that you would
want to connect to. The PHP-GTK 2 documentation contains a list of all signals
that are relevant for a particular widget. Once you know that, and once you
have written a function that contains the code you want to be executed when
the signal is generated all you have to do is:
${widget}->connect_simple('{signal-name}', '{callback-name}'); |
where, {widget} is the object whose signal you want to connect,
{signal-name} is the signal name, which of course must be relevant to
{widget}, and {callback-name} is the name of the callback function.
Signal handlers are invoked whenever a signal is generated, by whatever means.
Remember that it is possible to generate signals through functions, and hence
a signal generation does not guarantee that the user has performed an
action.
To make things a little clearer, let's take a full fledged example. Here, we
add a button to a window. When a user clicks the button, the application
quits:
Example 9.1. A simple connection
<?php
$win = new GtkWindow();
$but = new GtkButton('Click to Quit!');
$win->add($but);
$win->show_all();
$but->connect_simple('clicked', 'quit');
function quit()
{
echo "You have quit!\n";
Gtk::main_quit();
}
Gtk::main();
?> |
It's quite a simple program. We create a button and a window, add the button
to the window and show them. The line we are concerned with is:
$but->connect_simple('clicked', 'quit'); |
As you can see, we have connected the
"clicked" signal of a
GtkButton widget to the signal handler named
quit. Simple, eh? The function
quit
will be called whenever the
clicked signal is emitted
from our button, or, whenever the user clicks on our button.
You can see in the quit function definition that we
display a message and then call the Gtk::main_quit()
function to exit the program.
What if I connect the same signal twice to two different
callbacks?, I hear you ask. Well, the signal handlers will simply
be called in the order in which they were connected.
If any of your signal handlers return true then no more
signal handlers will be called for the current signal being handled. This is
a useful way of controlling logic when you have multiple signal handlers.
An example to make things crystal clear:
Example 9.2. Multiple signal connections
<?php
$win = new GtkWindow();
$but = new GtkButton('Click to Quit!');
$win->add($but);
$win->show_all();
$but->connect_simple('clicked', 'first');
$but->connect_simple('clicked', 'second');
$but->connect_simple('clicked', 'third');
function first()
{
echo "I am the first function!\n";
}
function second()
{
echo "I am the second function!\n";
}
function third()
{
echo "And I'm the function that's going to stop this program!\n";
Gtk::main_quit();
}
Gtk::main();
?> |
Run the program and you will see that signal handlers are indeed
invoked in the order in which they were connected.
OK, but what if I connect the signal to the same callback a hundred
times? The callback will be invoked a hundred times. But there's no
reason anyone would want to do this.
Can I connect multiple signals to the same callback?
Yes, and in fact this is actually very useful. Many applications will have
multiple ways of quitting the program: the regular "cross" button, a "quit"
button on the file menu etc. You can connect signals for each one of them
to a single quit function. You don't have to worry about
where the signal came from, you just know that the user wants to quit the
application.
Sometimes, its useful to know which widget had triggered a particular
signal. If your application has more than one button, and you've connected
all their clicked signals to a single callback, you'd
definitely want to know which button the signal came from. It is in fact
efficient to write a single signal handler for multiple signals.
Here is where the connect method comes into the picture.
This method passes the object of the widget that generated the signal as the
first parameter to the signal handler.
$button1 = new GtkButton('First');
$button2 = new GtkButton('Second');
$button1->connect('clicked', 'show');
$button2->connect('clicked', 'show');
function show($whichbutton)
{
echo $whichbutton->get_label();
} |
In the above example, you will get an output of "First" or "Second"
depending on which button was clicked.
It is also useful at times if you could pass custom parameters to your
signal handlers. PHP-GTK 2 provides this functionality in both the
connect and connect_after methods. You
simply pass your parameters after the second argument to both these methods
separated by commas like this:
Example 9.3. Passing custom parameters
<?php
$win = new GtkWindow();
$but = new GtkButton('Move over me!');
$win->add($but);
$win->show_all();
$win->connect_simple('destroy', array('gtk', 'main_quit'));
$but->connect_simple('enter-notify-event', 'showMessage', true, 'You moved the mouse');
$but->connect_simple('leave-notify-event', 'showMessage', false, 'You moved the mouse');
function showMessage($enter, $message)
{
if ($enter) {
echo $message." over the button!\n";
} else {
echo $message." away from the button!\n";
}
}
Gtk::main();
?> |
In this example, we pass two custom parameters to our signal handler that
helps us from differentiating whether the mouse entered the button or left
it. Note that your custom parameters can be of any type: string, boolean,
integer, an array or even an object, as long as its a valid type in PHP.
In fact, it is a very common necessity to pass widget objects as parameters
to signal handlers, because a callback connected to a signal triggered by
some widget may need to modify some other widget. You may pass as many
custom parameters as you want. Just ensure that your signal handler is
designed to receive the same number of parameters, or you may raise
warnings.
For more information on signals such as
enter-notify-event, see the section on
events, because
there is more to this than meets the eye.
Object-oriented connections
Let us analyze the line that you might have seen frequently:
$window->connect_simple('destroy', array('gtk', 'main_quit')); |
Why an array as the second argument?
Remember that whenever you connect to callback functions in an
object-oriented context, the second argument to the connect_* functions must
be an array. The first element of the array should point to the class that
contains the callback and the second element must contain the name of the
callback itself.
When the callback is static in nature (like
Gtk::main_quit()), we generally specify the name of the
class as a string. However if the callback is not static in nature, but is a
member of your current class instead, the first element should be the
special $this variable. Have a look at the tutorial on
Object Oriented
Programming for examples of usage in such a context. The point is to
somehow make the first element of the array point to the class that contains
the callback and the second element point to the callback.