362. How to prevent concurrent button clicks - Part 3 - using emit stop by name?

Problem

This is in response to Benjamin Smith's post titled Preventing concurrent processing.

Suppose you have set up two buttons as shown below.

In this article, I will show you the third method in preventing concurrent clicks on the buttons. You will find that if you click on the first button1, until button1 finishes its processing, clicking on button1 or button2 will not have any effect.

How to prevent concurrent button clicks - Part 3 - using emit stop by name?


Solution

  • First we use a global variable $in_progress to let us know if there's any process in progres.
  • When we receive a button click in the signal handler, we first test if $in_progress=1. If there's currently a process running, we "gobble" up this signal with GObject::emit_stop_by_name()

Important Note: This only works for PHP-GTK2 compliled with gtk+ v2.10 and above. If you are using an older version, for linux, you may follow the step-by-step instructions to recompile php-gtk2 with gtk+ v2.10. For windows, please refer to How to install php gtk2 on windows? You may also want to take a look here to see some of the new exciting PHP-GTK2 Functionalities.


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   
56   
57   
58   
59   
61   
62   
63   
64   
65   
66   
67   
68   
69   
70   
71   
72   
73   
74   
75   
77   
78   
79   
80   
81   
82   
83   
84   
85   
87   
88   
91   
92   
93   
94   
95   
96   
<?php
$window = new GtkWindow();
$window->set_title($argv[0]);
$window->set_size_request(400, 175);
$window->connect_simple('destroy', array('Gtk','main_quit'));
$window->add($vbox = new GtkVBox());

// display title
$title = new GtkLabel("   Prevent concurrent button clicks\n".
"Part 3 - using emit_stop_by_name()");
$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);

$vbox->pack_start($hbox = new GtkHBox(), 0);
$hbox->pack_start($vbox1 = new GtkVBox(), 0);
$hbox->pack_start(new GtkVBox());
$hbox->pack_start($vbox2 = new GtkVBox(), 0);

$vbox1->pack_start($button1 = new GtkButton('Button 1'), 0);
$vbox1->pack_start($status11 = new GtkLabel(), 0);
$vbox1->pack_start($status12 = new GtkLabel(), 0);
$vbox1->pack_start($progress1 = new GtkProgressBar(), 0);
$progress1->set_orientation(Gtk::PROGRESS_LEFT_TO_RIGHT);
$handler[1] = $button1->connect('clicked', 'on_button', 1,
    $progress1, $status11, $status12);
$num_clicks[1] = 0;

$vbox2->pack_start($button2 = new GtkButton('Button 2'), 0);
$vbox2->pack_start($status21 = new GtkLabel(), 0);
$vbox2->pack_start($status22 = new GtkLabel(), 0);
$vbox2->pack_start($progress2 = new GtkProgressBar(), 0);
$progress2->set_orientation(Gtk::PROGRESS_LEFT_TO_RIGHT);
$handler[2] = $button2->connect('clicked', 'on_button', 2,
    $progress2, $status21, $status22);
$num_clicks[2] = 0;

$in_progress = 0; // note 1
$window->show_all();
Gtk::main();

function on_button($button, $id, $progress, $status1, $status2) {
    global $handler, $button1, $button2;
    global $in_progress;
    if ($in_progress) {
        $button->emit_stop_by_name ('clicked'); // note 2
        return true;
    }

    $in_progress = 1;

    global $num_clicks, $progress_count;
    ++$num_clicks[$id];
    $progress_count[$id][$num_clicks[$id]] = 0;
    $status1->set_text("Total number of clicks ($id): {$num_clicks[$id]}");
    Gtk::idle_add('update_progressbar', $progress, $id, $num_clicks[$id],
        $status1, $status2);
}

function update_progressbar($progress, $id, $num_clicks, $status1, $status2) {
    $max = 1000;
    global $progress_count;
    ++$progress_count[$id][$num_clicks];
    $count = $progress_count[$id][$num_clicks];
    $percent_complete = $count/$max;
    $percent_complete2 = number_format($count/$max*100, 0);
    $progress->set_fraction($percent_complete);
    $progress->set_text($percent_complete2.'% Complete');
    while (Gtk::events_pending()) {Gtk::main_iteration();}
    $status2->set_text("Now running click #$num_clicks");
    if ($count < $max) { // task completed?
        return true; // not yet!
    } else {
        global $num_clicks;
        --$num_clicks[$id];
        $status1->set_text("Total number of clicks: {$num_clicks[$id]}");
        while (Gtk::events_pending()) {Gtk::main_iteration();}

        global $in_progress;
        $in_progress = 0; // note 3

        return false;
    }
}

?>

Output

As shown above.
 

Explanation

The above example make use of the code from How to process concurrent button clicks?.

What's new here:

  1. The global variable $in_progress to let us know if there's any process in progres.
  2. Gobble up this signal if there's currently a process running.
  3. Set $in_progress back to 0 so that we can receive button clicks again.

Related Links

Add comment


Security code
Refresh