Лекция 10.

Графика

Основные объекты в графических библиотеках — это окно и графический контекст.

Окно привязано к конкретной программе и отвечает за пользовательский интерфейс. Окно можно двигать по экрану, менять его размеры, закрывать его другими окнами или выводить поверх других окон. При этом изображение в окне должно корректироваться соответственно этим операциям.

Графический контекст привязан к окну и позволяет выводить в нем изображения.

К одному окну может быть привязано несколько графических контекстов и в каждом из них можно создавать изображения. В каждый момент времени у окна активен только один графический контекст и именно его содержимое отображается в окне. Это позволяет мгновенно менять изображение в окне простым переключением графических контекстов. Данная возможность используется, например, в компьютерных играх: новое изображение сначала подготавливается в неактивном графическом контексте, затем этот контекс делается активным и готовое изображение «заливает» окно.

Графическая библиотека X11

В графической библиотеке X11 к понятиям окна и графического контекста добавляются понятия дисплей и экран.

Дисплеи отличаются своим именам. Начать работу с дисплеем можно при помощи функции XopenDisplay(), которая в качестве параметра получает имя дисплея и возвращает указатель на дисплей. При вызове этой функции с параметром 0 она возвращает указатель на основной (то есть используемый по умолчанию) дисплей.

Полезная информация. Имя основного дисплея содержится в переменной среды DISPLAY. Значение этой переменной можно узнать, используя следующую команду echo. Например, имя дисплея по умолчанию может быть «:0.0»:

$ echo $DISPLAY

:0.0

$

Дисплей может иметь несколько окон, которые отличаются своими номерами. Номер основного окна можно узнать при помощи функции DefaultScreen(), получающей в качестве параметра указатель на дисплей.

В библиотеке X11 реализованы функции для рисования простых геометрических форм: XDrawLine(), XDrawArc(), XdrawRectangle(), XFillArc(), XFillRectangle().


Для более плавного вывода изображения можно подготавливать его заранее в так называемом PixMap, а затем мгновенно выводить в окно при помощи функции XCopyArea().

События, связанные с окном, например, клик мышкой по окну, изменение его размеров и т. д., надо отрабатывать. Например, при изменении размера окна нужно соответствующим образом скорретировать изображение в окне: вытянуть или сжать. Эти события могут происходить настолько быстро, что следующее событие наступает во время обработки предыдущего. Для того, чтобы события не потерялись, нужно при их наступлении сохранять их в каком-то контейнере, чтобы затем обрабатывать. Поскольку события надо обрабатывать в том временнОм порядке, в котором они происходили, то удобно хранить их в контейнере типа очередь.

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

События можно извлекать из очереди при помощи функций XNextEvent(), XСheckTypedEvent () и XCheckMaskEvent(). Первая функция извлекает из очереди все события подряд, причем функция всегда возвращает событие (если очередь пуста, она ждет, когда в ней появится событие). Вторая функция извлекает из очереди событие определенного типа, если оно там есть, тип события указывается в параметре функции. Третья функция извлекает из очереди событие из определенного набора событий, если оно там есть, набор событий задается также в параметре функции при помощи битовой маски.

При использовании библиотеки X11 нужно реализовать процедуру, которая будет постоянно извлекать и обрабатывать события из очереди.

Пример простой программы, которая, используя библиотеку X11, создает окно и меняет его цвет при клике на нем мышкой: hi.c.

Проект «Графическое окно»

Проект «Графическое окно» (GWindow.zip, разработан В.В.Борисенко) — пример библиотеки классов для поддержки программирования в среде X-Windows (Unix).

Класс GWindow реализует работу с графическим окном, причем все созданные объекты этого класса провязываются в список за счет того, что этот класс реализован на базе элемента L2-списка (члены класса next и prev указывают на следующий и предыдущий элементы L2-списка соответственно). Первый элемент списка окон находится в статической переменной класса GWindow::m_WindowList.

В классе имеется ряд виртуальных функций. Например, функция onExpose(), вызываемая для отрисовки окна, имеет пустую реализацию. Следовательно, при вызове этой функции в окне ничего нарисовано не будет. Программы, которые используют класс GWindow (grtst, cursTst, func, clock, react, mondrian), реализуют свой вариант функции onExpose(), который зависит от назначения этих программ. Например, программа func рисует в окне график функции, заданной в этой программе.

Процедура, которая извлекает и обрабатывает события из очереди, в классе GWindow называется messageLoop(). Она реализована очень просто: в бесконечном цикле вызывается метод класса GWindow getNextEvent(), который пытается извлечь событие из очереди. Если событий в очереди не оказалось, функция засыпает на 0.01 секунды. Если же событие извлечь удалось, то оно передается методу класса GWindow dispatchEvent().