464. How to set up a countdown timer - Part 1?

Problem

This is in response to Nitro7's post titled "Countdown Timer".

When a button is pressed in an application, he wants another window to open up that displays a minute and second countdown as shown below:

How to set up a countdown timer - Part 1?

When the time is up, an alert message will be displayed:


Solution

  • We make use of the same technique as described in How to display progress bar while processing long task - Part 2 using_idle_add?
  • Instead of displaying a progress bar, we display the remaining time using a GtkLabel.
  • Also, note that instead of Gtk::idle_add(), we use a Gtk::timeout_add(), since all we need is an update once every second.
  • In this example, when the time is up, I simply display an alert dialog box.
  • If you want you can also play a sound file. If you're on windows, you can make use of the technique as described in How to launch external app in winxp without the flashing of cmd window? to call an external application that plays your sound file:
  • $shell = new COM('WScript.Shell'); 
    $shell->Run('cmd /c start "" "' . $cmd_to_play_sound_file . '"', 0, FALSE); 
    unset($shell);
    

    where $cmd_to_play_sound_file is the command from system prompt to play your sound file. You can try to put just the name of the sound file here. It should be able to launch the appropriate player automatically.


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   
45   
46   
48   
51   
52   
53   
54   
55   
56   
57   
58   
59   
60   
61   
62   
63   
64   
65   
66   
67   
68   
70   
71   
74   
75   
76   
77   
78   
79   
80   
81   
82   
85   
86   
87   
88   
90   
91   
92   
93   
94   
95   
96   
97   
98   
99   
100   
101   
102   
103   
104   
105   
107   
108   
109   
110   
111   
112   
113   
114   
<?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("Set up a countdown timer - Part 1");
$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, 0);
$vbox->pack_start(new GtkLabel(), 0, 0);

$vbox->pack_start(new GtkLabel('Click the button to start the timer'), 0, 0);
$vbox->pack_start(new GtkLabel('When the time is up, an alert message is displayed.'), 0, 0);
$vbox->pack_start(new GtkLabel(), 0, 0);

$vbox->pack_start($hbox = new GtkHBox(), 0, 0);
$hbox->pack_start($button = new GtkButton('Start timer'), 1, 0);
$vbox->pack_start(new GtkLabel());
$button->connect('clicked', 'start_timer');

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

// display an alert dialog box
function alert($msg) {
    $dialog = new GtkDialog('Alert', null, Gtk::DIALOG_MODAL);
    $dialog->set_position(Gtk::WIN_POS_CENTER_ALWAYS);
    $top_area = $dialog->vbox;
    $top_area->pack_start($hbox = new GtkHBox());
    $stock = GtkImage::new_from_stock(Gtk::STOCK_DIALOG_WARNING,
        Gtk::ICON_SIZE_DIALOG);
    $hbox->pack_start($stock, 0, 0);
    $hbox->pack_start(new GtkLabel($msg));
    $dialog->add_button(Gtk::STOCK_OK, Gtk::RESPONSE_OK);
    $dialog->set_has_separator(false);
    $dialog->show_all();
    $dialog->run();
    $dialog->destroy();
}

function start_timer($button) {
    $do_long_task = new DoLongTask();
    $do_long_task->time_left = 10; // note 1
    $do_long_task->process_task(); // note 2
    $do_long_task->timeout_ID = Gtk::timeout_add(1000, 
        array(&$do_long_task, 'process_task')); // note 3
}

class DoLongTask {

    var $progress;
    var $dialog;
    var $time_left;
    var $subtask_count = 0;
    var $max_task_count = 10;
    var $timeout_ID;

    function DoLongTask() {
        // setup a dialog containing progress bar
        $dialog = new GtkDialog('Timer',
            null, Gtk::DIALOG_MODAL); // create a new dialog
        $top_area = $dialog->vbox;
        $dialog->set_size_request(200, 60);
        $this->progress = new GtkLabel();
        $this->progress->modify_font(new PangoFontDescription("Times New Roman Italic 20"));
        $top_area->pack_start($this->progress);
        $dialog->set_has_separator(false);
        $dialog->show_all(); // show the dialog
        $this->dialog = $dialog; // keep a copy of the dialog ID

        $dialog->connect('delete-event',
            array( &$this, "on_delete_event"));
    }

    // this is where you process your task
    function process_task() {
        $this->progress->set_text(date('i:s', $this->time_left)); // note 4
        --$this->time_left;
        while (Gtk::events_pending()) {Gtk::main_iteration();}

        if ($this->time_left>=0) { // note 5
            return true; // not yet!
        } else {
            alert("time's up!"); // note 6
            $this->dialog->destroy(); // yes, all done. close the dialog
            Gtk::timeout_remove($this->timeout_ID);
            return false;
        }
    }

    // function that is called when user closes the timer
    function on_delete_event($widget, $event) {
        $this->dialog->destroy();
        Gtk::idle_remove($this->timeout_ID);
        // any other clean-up that you may want to do
        return true;
    }
}

?>

Output

As shown above.
 

Explanation

The above code is based on How to display progress bar while processing long task - Part 2 using_idle_add?

We also make use of the code from How to display a popup alert for required fields - Part 1? to display the alert message.

What's new here:

  1. Sets the time in seconds. Here I set it at 10 seconds. For 15 minutes, set it as 15*60.
  2. Display the initial time first.
  3. Update the timer once every second.
  4. Display the remaining time.
  5. Time's up?
  6. Yes, here we display an alert message. You can replace this with playing of sound file, etc.

Related Links

Add comment


Security code
Refresh