466. How to set up a countdown timer - Part 3 - accurate to hundredth of a second?

Problem

The method we've used in How to set up a countdown timer - Part 2 - a more accurate timer? allows us to set up a countdown timer accurate to a hundredth of a second as shown below:

How to set up a countdown timer - Part 3 - accurate to hundredth of a second?


Solution

  • We make use of the same technique as described in Part 2.
  • The only difference is that we have changed the interval of the timeout event from 1000ms (i.e. 1 second) to 10ms (i.e. hundredth of a second).

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   
47   
49   
52   
53   
54   
55   
56   
57   
58   
59   
60   
62   
63   
64   
65   
66   
67   
68   
69   
70   
72   
73   
76   
77   
78   
79   
80   
81   
82   
83   
84   
87   
88   
89   
90   
91   
92   
94   
95   
96   
97   
98   
99   
100   
101   
102   
106   
110   
111   
112   
113   
114   
115   
116   
117   
118   
119   
120   
121   
122   
123   
125   
126   
127   
128   
129   
130   
131   
132   
<?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\n".
"Part 3 - accurate to a hundredth of a second");
$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->total_time = 10;
    $do_long_task->process_task();
    $do_long_task->timeout_ID = Gtk::timeout_add(10, 
        array(&$do_long_task, 'process_task')); // note 1
}

class DoLongTask {

    var $progress;
    var $dialog;
    var $subtask_count = 0;
    var $max_task_count = 10; // note 2
    var $timeout_ID;
    var $start_time;

    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->start_time = microtime(1);
    }

    // this is where you process your task
    function process_task() {
        $elapsed_time = microtime(1)-$this->start_time;
        $remaining_time = $this->total_time - $elapsed_time;

        if ($remaining_time>=0) {
            $remaining_time_min = intval($remaining_time / 60);
            $remaining_time_sec = $remaining_time % 60;
            $remaining_time_hsec = $remaining_time - intval($remaining_time);
            $remaining_time_hsec = round($remaining_time_hsec * 100);
            $remaining_time_hsec = str_pad($remaining_time_hsec, 2, STR_PAD_LEFT, '0'); // note 3
            $this->progress->set_text(date('i:s', $remaining_time). '.' . $remaining_time_hsec);
            while (Gtk::events_pending()) {Gtk::main_iteration();}

            return true; // not yet!
        } else {
            $this->progress->set_text('00:00.00');
            alert("time's up!");
            $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.
 

Add comment


Security code
Refresh