GTK+ 2.0 Tutorial

<<< Previous

Scribble, A Simple Example Drawing Program

Next >>>


Виджет DrawingArea и рисование

Теперь мы приступаем к процессу рисования на экране. Виджет, который мы используем для этого, называется DrawingArea (область рисования). Виджет области рисования - по существу простое окно X. Это чистый холст в котором мы можем рисовать то, что мы хотим. Область рисования создаётся вызовом:

GtkWidget* gtk_drawing_area_new (void);

Размер виджета по умолчанию может быть определён вызовом:

void gtk_drawing_area_size (GtkDrawingArea *darea, gint width, gint height);

Этот размер может быть изменён вызовом функции gtk_widget_set_size_request(), а размер определённый с помощью этой функции может быть изменен пользователем с помощью простого увеличения или уменьшения окна содержащего область рисования.

Должно быть отмечено, что, когда мы создаем виджет DrawingArea, мы полностью ответственны за отрисовку содержимого. Если наше окно скрыто, то при открытии мы получаем событие экспозиции и должны перерисовать то, что было предварительно скрыто.

Необходимо помнить все, что было нарисовано на экране, чтобы можно было должным образом перерисовать. Кроме того, может быть визуально неприятно, если части окна очищаются и перерисовываются шаг за шагом. Решение этой проблемы заключается в использовании закадрового backing pixmap. Вместо того, чтобы рисовать непосредственно на экране, мы рисуем на изображении сохраненном в памяти сервера, но не отображенном на экране, затем когда изменения изображения или новые части изображения отображены, мы копируем необходимые части на экран.

Создание закадрового pixmap, выполняется функцией:

GdkPixmap* gdk_pixmap_new (GdkWindow *window, gint width, gint height, gint depth);

Параметр window определяет окно GDK, от которого этот pixmap берет некоторые из его свойств. width и height определяет размер pixmap. depth определяет глубину цвета (color depth) - число битов в пикселах, для нового окна. Если глубина будет определена как -1, то будет соответствовать глубине window.

Мы создаем pixmap в нашем "configure_event" обработчике. Это событие производится всякий раз, когда окно изменяет размер, включая первоначальное создание.

/* Резервирование pixmap для области рисования */ static GdkPixmap *pixmap = NULL; /* Создание нового backing pixmap соответствующего размера */ static gint configure_event (GtkWidget *widget, GdkEventConfigure *event) { if (pixmap) gdk_pixmap_unref(pixmap); pixmap = gdk_pixmap_new(widget->window, widget->allocation.width, widget->allocation.height, -1); gdk_draw_rectangle (pixmap, widget->style->white_gc, TRUE, 0, 0, widget->allocation.width, widget->allocation.height); return TRUE; }

Функция gdk_draw_rectangle() очищает pixmap инициализируя белым. Подробней об этом чуть ниже.

Наш обработчик события экспонирования просто копирует необходимую часть pixmap на дисплей (мы определяем область, которую должны перерисовать при использовании события->площадь области для события экспонирования):

/* Перерисовываем экран используя backing pixmap */ static gint expose_event (GtkWidget *widget, GdkEventExpose *event) { gdk_draw_pixmap(widget->window, widget->style->fg_gc[GTK_WIDGET_STATE (widget)], pixmap, event->area.x, event->area.y, event->area.x, event->area.y, event->area.width, event->area.height); return FALSE; }

Теперь мы знаем как применить обновление экрана используя нашу карту пикселей (pixmap), но как фактически рисовать необходимый нам материал на нашей карте (pixmap)? Есть большое количество вызовов в библиотеках GTK's GDK для рисования drawables. drawable - это просто что то, что может быть нарисовано. Это может быть окно, карта пикселей, или точечный рисунок (черно-белое изображение). Мы уже видели два таких вызова выше gdk_draw_rectangle() и gdk_draw_pixmap(). Вот полный список:

gdk_draw_line () gdk_draw_rectangle () gdk_draw_arc () gdk_draw_polygon () gdk_draw_string () gdk_draw_text () gdk_draw_pixmap () gdk_draw_bitmap () gdk_draw_image () gdk_draw_points () gdk_draw_segments ()

См. справочную документацию или файл заголовка <gdk/gdk.h> для получения детальной информации относительно этих функций. Все эти функции имеют те же самые два аргумента. Первый параметр - drawable, второй параметр - graphics context (GC).

Графический контекст инкапсулирует информацию о цвете переднего и заднего фона, а также о толщине линии. GDK имеет полный набор функций для того, чтобы создавать и изменять графические контексты , но сохраняя простоту, мы будем использовать только предопределенные графические контексты. Каждый виджет имеет связанный стиль. (Который может быть изменен в gtkrc файле, см. раздел GTK's rc file.) Он, между прочим, хранит множество графического контекста. Некоторые примеры доступа к этим графическим контекстам:

widget->style->white_gc widget->style->black_gc widget->style->fg_gc[GTK_STATE_NORMAL] widget->style->bg_gc[GTK_WIDGET_STATE(widget)]

Поля fg_gc, bg_gc, dark_gc, и light_gc индексированы параметром типа GtkStateType, который может принимать значения:

GTK_STATE_NORMAL, GTK_STATE_ACTIVE, GTK_STATE_PRELIGHT, GTK_STATE_SELECTED, GTK_STATE_INSENSITIVE

Например, для GTK_STATE_SELECTED цвет символа имеет значение по умолчанию - белый, а цвет фона - темно-синий.

Наша функция draw_brush(), для фактической отрисовки на дисплей:

/* Рисуем прямоугольник на экране */ static void draw_brush (GtkWidget *widget, gdouble x, gdouble y) { GdkRectangle update_rect; update_rect.x = x - 5; update_rect.y = y - 5; update_rect.width = 10; update_rect.height = 10; gdk_draw_rectangle (pixmap, widget->style->black_gc, TRUE, update_rect.x, update_rect.y, update_rect.width, update_rect.height); gtk_widget_draw (widget, &update_rect); }

После того, как мы нарисовали прямоугольник перенесенный на pixmap, вызываем функцию:

void gtk_widget_draw(GtkWidget *widget, GdkRectangle *area);

которая сообщает X, что область полученная параметром area должна быть обновлена. X в конечном счете генерирует событие экспонирования (возможно объединение областей, которые передаются в нескольких вызовах gtk_widget_draw()) которое вызовет наш обработчик событий экспонирования, чтобы скопировать необходимые участки на экран.

Вот мы и рассмотрели всю программу для рисования, за исключением простых деталей, таких как создание основного окна.


<<< Previous

Home

Next >>>

Event Handling

Up

Adding XInput support