20 августа 2009 г.

Полоса прогресса

В GTK+ для отображения прогресбара существует класс GtkProgressBar. Правда, в PHP-GTK от него практической пользы мало, т.к. в PHP отсутствует многопоточность. Процесс происходит примерно так: сначала выполняется PHP-код, а только потом перерисовывается интерфейс. В статье будет понятно, что при выполнении большого количества простых операций (например, копирование большого количества маленьких файлов) применение прогрессбара оправдано, но выполнить одну длительную операцию (копирование одного файла большого объёма) и в это время отобразить полосу прогресса не получится.

Добавлено: как выяснилось позже, на Unix-платформах реализовать полноценный прогрессбар вполне реально. О том, как это сделать говорится в статьях Отображение прогрессбара и параллельное выполнение операции и Реальный пример применения прогрессбара.


Существует два типа прогрессбаров: пульсирующий и нарастающий. Если известно количество выполняемой работы, то применяется нарастающий, иначе - пульсирующий. Оба создаются конструктором класса GtkProgressBar().

Пульсирующий запускается методом pulse(). Шаг пульсирования указывается методом set_pulse_step().

Текст на нарастающий прогрессбар устанавливается методом set_text(), определить количество прошедших шагов можно с помощью get_fraction() (может быть от 0 до 1), а установить - set_fraction().

Данная программа никаких реальных действий не выполняет, поэтому для имитации действий я использовал timeout_add().

Полный код программы:

<?php
 
$window = new GtkWindow();
$window->set_position(Gtk::WIN_POS_CENTER);
$window->set_size_request(200, -1);
$window->connect_simple('destroy', array('Gtk', 'main_quit'));
 
$vbox = new GtkVBox();
 
$vbox->pack_start(new GtkLabel('Пульсирующий режим:'), FALSE, FALSE);
 
$pulse = new GtkProgressBar();
$pulse->set_pulse_step(0.05);
$vbox->pack_start($pulse, FALSE, FALSE);
 
$vbox->pack_start(new GtkLabel('Режим нарастания:'), FALSE, FALSE);
 
$normal = new GtkProgressBar();
$normal->set_text('0%');
$vbox->pack_start($normal, FALSE, FALSE);
 
$button_run = new GtkButton('Запустить');
$button_run->connect_simple('clicked', 'run', $pulse, $normal);
$vbox->pack_start($button_run, FALSE, FALSE);
 
$button_stop = new GtkButton('Остановить');
$button_stop->set_sensitive(FALSE);
$button_stop->connect_simple('clicked', 'stop');
$vbox->pack_start($button_stop, FALSE, FALSE);
 
$window->add($vbox);
$window->show_all();
Gtk::main();
 
function run($pulse, $normal)
{
global $timeout, $button_run, $button_stop;
 
$button_run->set_sensitive(FALSE);
$button_stop->set_sensitive(TRUE);
 
$pulse->pulse();
 
// Если полоса дошла до конца, то сбрасываем значение
if ($normal->get_fraction() == 1)
{
$normal->set_fraction(0);
$normal->set_text('0%');
return TRUE;
}
 
$normal->set_fraction($normal->get_fraction() + 0.1);
$normal->set_text($normal->get_fraction() * 100 . '%');
 
$timeout = Gtk::timeout_add(100, 'run', $pulse, $normal);
}
 
function stop()
{
global $timeout, $button_run, $button_stop;
 
$button_run->set_sensitive(TRUE);
$button_stop->set_sensitive(FALSE);
 
Gtk::timeout_remove($timeout);
}
 
?>

3 комментария:

alex комментирует...

http://framework.zend.com/manual/ru/zendx.console.process.unix.html

$process1 = new MyProcess();
$process1->start();

$process2 = new MyProcess();
$process2->start();

Shecspi комментирует...

alex, спасибо. Реализацию данного способа я описал в соответствующей статье.

Gene комментирует...

Спасибо, весьма интересно!
Правда, даже такую операцию как копирование одного файла большого объёма в Windows тоже можно выполнить с прогресс-баром, пусть и без многопоточности. Для этого придется копировать данные блоками, то есть не используя copy(), а читая данные блоками по несколько мегабайт (по 5 МБ, к примеру):

$handle1 = fopen("myvideo1.avi", "rb");
$handle2 = fopen("myvideo2.avi", "wb");
while (!feof($handle1))
{
fwrite($handle2, fread($handle1, 5000000));
// здесь код обновления прогресс-бара
}
fclose($handle1);
fclose($handle2);

Конечно, это обходное решение, но все же вполне работающее, да и, наверное, единственное что можно придумать в плане копирования.