29 марта 2010 г.

GtkDrawingArea. Усовершенствование

В данной статье мы усовершенствуем программу для рисования, разработанную в "GtkDrawingArea. Автоматическое рисование точек на холсте". Во-первых, избавимся от существенного бага прошлой версии - стирания нарисованного после перекрытия области для рисования другим окном. Во-вторых, обработаем клики по холсту левой кнопкой мыши.





За основу был взят код демо-программы из дистрибьютива PHP-GTK.

Сначала добавим перехват ещё нескольких событий: 'configure_event', 'button_press_event' (издаётся при клике мышью) и 'motion_notify_event' (издаётся при перемещении мыши с зажатой кнопкой). Сразу же генерацию точек вынесем в отдельную функцию - draw_brush() и вместо прямоугольника будем рисовать дугу методом draw_arc().

При создании области для рисования издаётся сигнал 'configure_event'. Вызываем функцию do_configure(), в которой устанавливаем параметры холста. Затем в функции do_exponse() рисуем холст по заданным параметрам.

При нажатии любой кнопкой мыши по области GtkDrawingArea вызывается функция do_button_press(), в которой обрабатывается только нажатие левой клавиши по холсту (аналогично можно обработать и остальные клавиши), в ответ на которое вызывается функция draw_brush(), которой передаются координаты указателя мыши.

При перемещении мыши с зажатой кнопкой вызывается функция do_motion_notify(), которая также обрабатывает только нажатие левой клавиши и вызывает draw_brush().

Как видите, ничего сверхсложного в GtkDrawingArea нет, стоит лишь немного покопаться в коде и в гугле. Используя этот класс вполне возможно создать простенький растровый графический редактор. Может у кого-нибудь появится желание заняться им?

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

<?php
 
define('WIDTH', 400);
define('HEIGHT', 170);
 
$window = new GtkWindow();
$window->set_position(Gtk::WIN_POS_CENTER);
$window->set_title('Работа с GtkDrawingArea');
$window->set_size_request(400, 200);
$window->connect_simple('destroy', array('Gtk', 'main_quit'));
 
$vbox = new GtkVBox();
 
$vbox->pack_start($button = new GtkButton('Нарисовать случайную точку'), FALSE, FALSE);
 
$vbox->pack_start($drawing = new GtkDrawingArea());
 
$button->connect_simple('clicked', 'drawing_rand_point', $drawing);
$drawing->connect('expose-event', 'do_expose');
$drawing->connect('configure_event', 'do_configure');
// Перемещение мыши при зажатой кнопке
$drawing->connect('motion_notify_event', 'do_motion_notify');
// Клик мыши
$drawing->connect('button_press_event', 'do_button_press');
$drawing->set_events(
Gdk::EXPOSURE_MASK |
Gdk::LEAVE_NOTIFY_MASK |
Gdk::BUTTON_PRESS_MASK |
Gdk::POINTER_MOTION_MASK |
Gdk::POINTER_MOTION_HINT_MASK
);
 
$window->add($vbox);
$window->show_all();
Gtk::main();
 
function draw_brush($widget, $x, $y)
{
global $pixmap;
 
// Генерируем случайный цвет
$color_rand = new GdkColor(rand(0, 65535), rand(0, 65535), rand(0, 65535));
$point = new GdkGc($widget->window);
$point->set_rgb_fg_color($color_rand);
 
// Рисует дугу
$pixmap->draw_arc(
$point,
TRUE,
$x - 4,
$y - 4,
8, 8, 0, 64 * 360
);
$widget->queue_draw_area($x - 4, $y - 4, 8, 8);
}
 
function drawing_rand_point($widget)
{
draw_brush($widget, rand(0, WIDTH), rand(0, HEIGHT));
}
 
function do_configure($widget, $event)
{
global $pixmap;
 
$pixmap = new GdkPixmap(
$widget->window,
WIDTH,
HEIGHT,
-1
);
$pixmap->draw_rectangle(
$widget->style->white_gc,
TRUE,
0,
0,
WIDTH,
HEIGHT
);
 
return TRUE;
}
 
function do_expose($widget, $event)
{
global $pixmap;
 
$widget->window->draw_drawable(
$widget->style->fg_gc[$widget->state],
$pixmap,
$event->area->x,
$event->area->y,
$event->area->x,
$event->area->y,
$event->area->width,
$event->area->height
);
 
return FALSE;
}
 
function do_button_press($widget, $event)
{
global $pixmap;
 
if ($event->button == 1 && $pixmap)
{
draw_brush($widget, (int)$event->x, (int)$event->y);
}
 
return TRUE;
}
 
function do_motion_notify($widget, $event)
{
global $pixmap;
 
$window = $event->window;
$pointer = $window->get_pointer();
$x = $pointer[0];
$y = $pointer[1];
$state = $pointer[2];
 
if (($state & Gdk::BUTTON1_MASK) && $pixmap)
{
draw_brush($widget, $x, $y);
}
 
return TRUE;
}
 
?>

8 комментариев:

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

Привет, извини, что не по теме, но у меня есть пара вопросов..

1. Ты (надеюсь что на "ТЫ" общаться проще) не в курсе, есть ли возможность через php управлять треем или создавать аплет для панели Gnome?

2. Пробовал ли ты компилятор php. Я про hiphop (от разработчиков facebook). Если пробовал, то как скорость работы и инициализация окон и компонентов? Ощутимо быстрее?

PS Спасибо за блог, очень сложно быть флагманом и не иметь аналогов в рунете. Но ты делаешь хорошее дело. :)

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

1. Что ты имеешь ввиду под управлением треем? Апплет создать не получится, т.к. не хватает модуля, название не помню.
2. На счет HipHop for PHP - я еще не успел его попробовать, в конце мая буду дома, тогда протестирую.
Спасибо за слова поддержки)

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

В Gnome есть подобие виндового трея, т.н. "Область уведомлений". Т.е. это место рядом с часиками, куда засовываются всякие иконки запущенных приложений.

Например скайп, пиджин или трансмишен - там показывает свою иконку.

PS Если вспомнишь, напиши, пожалуйста, что за модуль требуется для поддержки апплетов. Не модуль для работы с бонобо случаем?

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

Про работу с треем я уже писал в блоге, статьи "Программа управления веб-сервером Apache" первая и вторая части, а также "Работа с треем". Найти их можешь в списке всех статей.
А для апплета, по-моему, именно бонобо и нужен.

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

Годовщина тишины в блоге :-(.

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

Что поделать)) Судьба ;)

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

Почему с блогом завязал? (

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

Всё, что я хотел рассказать - я рассказал. PHP-GTK в данном блоге охвачен полностью. Все аспекты работы с этой библиотекой рассмотрены. Для дальнейшего продолжения повествования нет ни смысла, ни базы. Писать больше не о чем. Именно поэтому постить в блог я и перестал. Но тем не менее блог остаётся активен. К нему всегда и для всех есть доступ. Именно это и было моей основной целью. Желаю удачи и спасибо за то, что заходите и читаете мой блог ;)