416. How to switch signal handlers on the fly - Part 3 - using state machine?

Problem

This is in response to Manar's post titled "How to disconnect an event?"

He has set up a button-press-event, and he would like to switch the signal handler processing the button-press-event depending on some conditions.

In Part 1 we used the methods connect() and disconnect().

In Part 2 we used the methods block() and unblock().

In this Part 3, instead of using two callback functions, we'll achieve the same effect using just one callback function, with the use of a simple state machine, as shown below:


Solution

  • In the situation described by Manar in his post, you can also use just one callback function.
  • The variable $state is used to maintain the different state the button is in.
  • The advantage of this method is that you do not need to connect/disconnect or block/unblcok the different signals.

How to switch signal handlers on the fly - Part 3 - using state machine?


Sample Code

1   
2   
3   
4   
5   
6   
7   
8   
9   
10   
11   
12   
13   
14   
15   
16   
17   
18   
19   
20   
21   
22   
23   
24   
25   
26   
27   
28   
29   
30   
31   
32   
33   
34   
35   
36   
37   
38   
39   
40   
41   
42   
43   
44   
46   
47   
48   
49   
50   
51   
52   
53   
54   
55   
56   
57   
58   
59   
60   
61   
62   
63   
64   
65   
66   
67   
68   
69   
<?php
$window = new GtkWindow();
$window->set_size_request(400, 175);
$window->connect_simple('destroy', array('Gtk','main_quit'));
$window->add($vbox = new GtkVBox());

// display title
$title = new GtkLabel("Switching signal handlers on the fly\n".
"      Part 3 - using 'state machine'");
$title->modify_font(new PangoFontDescription("Times New Roman Italic 10"));
$title->modify_fg(Gtk::STATE_NORMAL, GdkColor::parse("#0000ff"));
$title->set_size_request(-1, 40);
$vbox->pack_start($title, 0);
$vbox->pack_start(new GtkLabel(), 0);

$label = new GtkLabel('Click on the blue sqaure once. '.
    'It will change to green.');
$vbox->pack_start($label, 0);

$state = 1; // note 1
setup_colorbox('#0000ff', 'blue', $vbox);

$window->show_all();
Gtk::main();


function setup_colorbox($color, $label, $vbox) {
    $hbox = new GtkHBox();
    $hbox->set_size_request(30, 30);
    $eventbox = new GtkEventBox();
    $eventbox->add($hbox);
    $eventbox->modify_bg(Gtk::STATE_NORMAL, GdkColor::parse($color));

    $eventbox->connect('button-press-event', 
        'on_button_press'); // note 2

    $hbox = new GtkHBox();
    $vbox->pack_start($hbox, 0);
    $hbox->pack_start(new GtkLabel());
    $hbox->pack_start($eventbox, 0);
    $hbox->pack_start(new GtkLabel());
}

function on_button_press($eventbox, $event) {
    if ($event->type!=Gdk::BUTTON_PRESS) return false;

    global $state;
    echo "on_button_press. state = $state!\n";

    if ($state == 1) {

        $eventbox->modify_bg(Gtk::STATE_NORMAL, 
            GdkColor::parse('#00ff00')); // note 3
        $state = 2; // note 3

    } elseif ($state == 2) {

        $eventbox->modify_bg(Gtk::STATE_NORMAL, 
        GdkColor::parse('#ffff00')); // note 4
        $state = 1; // note 5

    }

    global $label;
    $label->set_text('Click on this again. It will change to yellow.');
}

?>

Output

As shown above.

 

Explanation

  1. Set the next state of the button to be 1.
  2. Set up the button-press-event signal. Note that using this method, we do not need to take note of the signal handler id.
  3. For state 1, we change the color box from blue to green, and change the state to 2.
  4. For state 2, we change the color box from green to yellow, and change the state back to 1.

Related Links

Add comment


Security code
Refresh