<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/css" href="http://wiki2.linuxformat.ru/skins/common/feed.css?97"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
	<channel>
		<title>LXF115:FLTK - История изменений</title>
		<link>http://wiki2.linuxformat.ru/index.php?title=LXF115:FLTK&amp;action=history</link>
		<description>История изменений этой страницы в вики</description>
		<language>ru</language>
		<generator>MediaWiki 1.11.1</generator>
		<lastBuildDate>Thu, 14 May 2026 10:51:53 GMT</lastBuildDate>
		<item>
			<title>Crazy Rebel в 11:26, 21 января 2010</title>
			<link>http://wiki2.linuxformat.ru/index.php?title=LXF115:FLTK&amp;diff=9541&amp;oldid=prev</link>
			<description>&lt;p&gt;&lt;/p&gt;
&lt;a href=&quot;http://wiki2.linuxformat.ru/index.php?title=LXF115:FLTK&amp;amp;diff=9541&amp;amp;oldid=9538&quot;&gt;(Различия между версиями)&lt;/a&gt;</description>
			<pubDate>Thu, 21 Jan 2010 11:26:54 GMT</pubDate>			<dc:creator>Crazy Rebel</dc:creator>			<comments>http://wiki2.linuxformat.ru/index.php/%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5:LXF115:FLTK</comments>		</item>
		<item>
			<title>Crazy Rebel: Новая: : '''Программируем с ''FLTK''''' Быстрый, легкий, поддерживающий OpenGL: выберите любые три!  {{Цикл/FLTK}}  ==Сверхск...</title>
			<link>http://wiki2.linuxformat.ru/index.php?title=LXF115:FLTK&amp;diff=9538&amp;oldid=prev</link>
			<description>&lt;p&gt;Новая: : '''Программируем с ''FLTK''''' Быстрый, легкий, поддерживающий OpenGL: выберите любые три!  {{Цикл/FLTK}}  ==Сверхск...&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Новая статья&lt;/b&gt;&lt;/p&gt;&lt;div&gt;: '''Программируем с ''FLTK''''' Быстрый, легкий, поддерживающий OpenGL: выберите любые три!&lt;br /&gt;
&lt;br /&gt;
{{Цикл/FLTK}}&lt;br /&gt;
&lt;br /&gt;
==Сверхскоростная графика==&lt;br /&gt;
&lt;br /&gt;
: '''ЧАСТЬ 2''' Пусть ''Qt'' и ''GTK+'' лучше подходят для сложных приложений – ''FLTK'' блистает там, где интерфейс должен быть незаметным: например, в «демках» OpenGL. '''Андрей Боровский''' напишет одну такую.&lt;br /&gt;
&lt;br /&gt;
Какое звено является ведущим в связке потребностей и технологий? Я думаю, что все-таки потребности. Развитие графических адаптеров с миллионами поддерживаемых цветов и пикселей стимулировалось парадигмой WYSIWYG, а не наоборот, а ускорители 3D-графики для ПК появились благодаря трехмерным играм (первые из которых обходились вовсе без ускорителей). А вот внедрение в работающую схему новых технологий по принципу «зачем добру пропадать» редко приносит хорошие результаты. Вот, например, все современные рабочие столы обзавелись трехмерными «примочками» – а часто ли мы ими пользуемся? Тем не менее, раз уж OpenGL распространяется повсюду, то и обзор библиотеки виджетов не может без него обойтись.&lt;br /&gt;
&lt;br /&gt;
===OpenGL в ''FLTK''===&lt;br /&gt;
&lt;br /&gt;
Как уже отмечалось, поддержка OpenGL была в свое время уникальной и крайне привлекательной чертой ''FLTK'', и даже сейчас с некоторыми проблемами вывода трехмерной графики эта библиотека справляется лучше, нежели другие наборы виджетов. Для работы с OpenGL ''FLTK'' предлагает нам два класса: '''GlWindow''' и&lt;br /&gt;
'''GlutWindow'''. Как нетрудно догадаться, они наследуют Window и реализуют специальные типы окон, у которых рабочая поверхность подготовлена для вывода графики OpenGL. В остальном, окна '''GlWindow''' и '''GlutWindow''' подобны окну Window – они могут содержать дочерние виджеты и обрабатывать сообщения, адресованные главному окну программы. Окно '''GlWindow''' предоставляет базовую функциональность, необходимую для работы с OpenGL, а окно '''GlutWindow''' вдобавок эмулирует функции библиотеки ''GLUT''.&lt;br /&gt;
    Если вы интересуетесь программированием с OpenGL, то&lt;br /&gt;
наверняка уже знаете, что такое GLUT, и тем не менее я это&lt;br /&gt;
поясню. Интерфейс OpenGL разрабатывался как максимально&lt;br /&gt;
платформо-независимый. Выразилось это, например, в том, что&lt;br /&gt;
в OpenGL не были включены функции для обработки сообщений&lt;br /&gt;
системы и взаимодействия с окнами. Вместе с тем, на практике&lt;br /&gt;
OpenGL-программы разрабатываются, в основном, в графических&lt;br /&gt;
многооконных средах, а значит, всем программистам нужен некий&lt;br /&gt;
минимум средств для взаимодействия между OpenGL и оконной&lt;br /&gt;
системой. Конечно, разработчики последних тоже не остались&lt;br /&gt;
в стороне. Для X Window была разработана система GLX, а для&lt;br /&gt;
Windows GDI – WGL (Wiggle), но эти расширения были довольно&lt;br /&gt;
сложны и несовместимы друг с другом. Свободную нишу запол-&lt;br /&gt;
нила разработанная Марком Килгардом [Mark J. Kilgard] библио-&lt;br /&gt;
тека GLUT, которая отличалась от GLX/WGL простотой использо-&lt;br /&gt;
вания и кроссплатформенностью (фактически, GLUT на каждой&lt;br /&gt;
платформе представляет собой надстройку над расширениями&lt;br /&gt;
конкретной системы). Неудивительно, что в то время многие про-&lt;br /&gt;
граммисты предпочитали GLUT для разработки надежным кросс-&lt;br /&gt;
платформенных программ.&lt;br /&gt;
     Учитывая популярность GLUT, разработчик FLTK Билл Спитцак&lt;br /&gt;
[Bill Spitzak] принял мудрое решение – добавить поддержку интер-&lt;br /&gt;
фейса GLUT в свой набор виджетов. В результате авторы про-&lt;br /&gt;
грамм, использовавшие GLUT, смогли без труда портировать свой&lt;br /&gt;
код на FLTK (отметим в скобках, что если вы начинаете писать&lt;br /&gt;
новую программу, нет никакого смысла использовать класс&lt;br /&gt;
GlutWindow, так как все то хорошее, что может дать вам библиоте-&lt;br /&gt;
ка GLUT, реализовано в классе GlWindow). Поскольку библиотека&lt;br /&gt;
GLUT не является открытым ПО (хотя исходные тексты доступны),&lt;br /&gt;
Спитцак создал модуль поддержки GLUT с нуля, сохранив совме-&lt;br /&gt;
стимость на уровне интерфейса. Но так как особенности GLUT нас&lt;br /&gt;
не интересуют, мы остановимся на работе с окном GlWindow.&lt;br /&gt;
     Мы напишем минимальную программу, использующую OpenGL&lt;br /&gt;
и FLTK, в которой окно-потомок GlWindow будет главным и един-&lt;br /&gt;
ственным окном приложения (исходный текст программы вы най-&lt;br /&gt;
дете на диске в архиве ogldemo1).&lt;br /&gt;
 #include &amp;lt;fltk/GlWindow.h&amp;gt;&lt;br /&gt;
 using namespace fltk;&lt;br /&gt;
 class MyGLWindow : public GlWindow {&lt;br /&gt;
 public:&lt;br /&gt;
     MyGLWindow(int X, int Y, int W,int H, const char* L=0);&lt;br /&gt;
 private:&lt;br /&gt;
     void draw();&lt;br /&gt;
 };&lt;br /&gt;
     В объявлении класса окна мы переопределяем конструктор и&lt;br /&gt;
виртуальный метод draw(). Не спрашивайте меня, что он делает,&lt;br /&gt;
я сам скажу: draw() выполняет отрисовку сцены. Давайте посмот-&lt;br /&gt;
рим на реализацию методов:&lt;br /&gt;
 #include &amp;lt;fltk/gl.h&amp;gt;&lt;br /&gt;
 #include &amp;quot;MyGLWindow.h&amp;quot;&lt;br /&gt;
 MyGLWindow::MyGLWindow(int X,int Y,int W,int H,const char*L) :&lt;br /&gt;
 GlWindow(X,Y,W,H,L) {&lt;br /&gt;
 }&lt;br /&gt;
 void MyGLWindow::draw() {&lt;br /&gt;
      if (!valid()) {&lt;br /&gt;
         glLoadIdentity();&lt;br /&gt;
         glViewport(0,0,w(),h());&lt;br /&gt;
         glOrtho(-w(),w(),-h(),h(),-1,1);&lt;br /&gt;
      }&lt;br /&gt;
     glClear(GL_COLOR_BUFFER_BIT);&lt;br /&gt;
     glBegin(GL_TRIANGLES);&lt;br /&gt;
     glColor3f(1.0f,0.0f,0.0f);&lt;br /&gt;
     glVertex2f(w() - 10, h() - 10);&lt;br /&gt;
     glColor3f(0.0f,1.0f,0.0f);&lt;br /&gt;
     glVertex2f(10 -w() , 10 -h());&lt;br /&gt;
     glColor3f(0.0f,0.0f,1.0f);&lt;br /&gt;
     glVertex2f(10 -w() , h() - 10);&lt;br /&gt;
     glEnd();&lt;br /&gt;
 }&lt;br /&gt;
    Как уже отмечалось, одной из проблем вывода графики OpenGL&lt;br /&gt;
является необходимость изменять параметры матрицы проекти-&lt;br /&gt;
рования при изменении размеров окна. В GlWindow вы можете&lt;br /&gt;
совместить настройку матрицы проектирования и код, формиру-&lt;br /&gt;
ющий изображение, в одном методе draw(), благодаря свойству&lt;br /&gt;
valid() класса GlWindow (о понятии свойства в FLTK говорилось&lt;br /&gt;
в LXF113/114). Свойство valid() принимает значение 0, если окно&lt;br /&gt;
только что создано, если его размеры были изменены или прои-&lt;br /&gt;
зошло переключение графических контекстов. После завершения&lt;br /&gt;
вызова метода draw() свойство valid() принимает ненулевое значе-&lt;br /&gt;
ние. Таким образом, мы можем организовать проверку значения&lt;br /&gt;
valid() в начале метода draw(). Если свойство равно 0, значит, тре-&lt;br /&gt;
буется перенастроить матрицу проектирования, в противном слу-&lt;br /&gt;
чае мы можем сразу приступить к выводу изображения.&lt;br /&gt;
    У класса GlWindow есть метод resize(), объявленный в разделе&lt;br /&gt;
protected, который вызывается при их изменении размеров окна,&lt;br /&gt;
так что у вас может возникнуть соблазн переопределить его и&lt;br /&gt;
разместить в нем код перенастройки проектирования. Не делай-&lt;br /&gt;
те этого! В результате вы получите совсем не то, чего ожидали.&lt;br /&gt;
Переопределение метода resize() может понадобиться только в том&lt;br /&gt;
случае, если окну GlWindow приходится иметь дело с не-OpenGL&lt;br /&gt;
элементами, например, с дочерними виджетами. Не могу не отме-&lt;br /&gt;
тить, что в наборе примеров FLTK Cheats (http://seriss.com/people/&lt;br /&gt;
erco/fltk/#OpenGlSimpleWidgets), которыми часто пользуются для&lt;br /&gt;
изучения FLTK, допущена ошибка – код перенастройки проектиро-&lt;br /&gt;
вания вызывается и в методе draw(), и в методе resize() (и, кроме&lt;br /&gt;
того, добавлен в конструктор окна). Ошибка незаметна, так как&lt;br /&gt;
«правильный» код в методе draw() перекрывает неправильный,&lt;br /&gt;
но повторять эту небрежность не следует.&lt;br /&gt;
    Для компиляции программы воспользуемся командой&lt;br /&gt;
 g++ MyGLWindow.cpp main.cpp -lfltk2 -lfltk2_gl -lGL -o ogldemo&lt;br /&gt;
    Обратите внимание, что кроме стандартной библиотеки&lt;br /&gt;
OpenGL нам требуется подключить к файлу программы библио-&lt;br /&gt;
теку libfltk2_gl. Теперь мы можем наслаждаться зрелищем радуж-&lt;br /&gt;
ного треугольника (рис. 1), который вы, конечно, уже видели бес-&lt;br /&gt;
счетное количество раз.&lt;br /&gt;
     В заключение перечислим несколько полезных функций клас-&lt;br /&gt;
са GlWindow. Свойство context() позволяет управлять контекста-&lt;br /&gt;
ми OpenGL. Оно имеет тип GLContext, который на платформе X&lt;br /&gt;
соответствует типу GLXContext, а в среде GDI – HGLRC. Благодаря&lt;br /&gt;
context() вы можете вызывать напрямую функции оконных рас-&lt;br /&gt;
ширений OpenGL для данной платформы. С помощью метода&lt;br /&gt;
mode() можно указать ряд параметров OpenGL, таких как исполь-&lt;br /&gt;
зование альфа-канала, двойной буферизации, буфера трафарета&lt;br /&gt;
и т.п. Метод ortho() настраивает матрицу проектирования таким&lt;br /&gt;
образом, что начало системы координат OpenGL совпадает с&lt;br /&gt;
нижним левым углом окна, а точка в координатах OpenGL соот-&lt;br /&gt;
ветствует одному пикселю экрана. Этот режим особенно удобен,&lt;br /&gt;
когда OpenGL используется для работы с двумерными изображе-&lt;br /&gt;
ниями. Метод swap_buffers () управляет переключением буферов&lt;br /&gt;
OpenGL.&lt;br /&gt;
Обработка событий&lt;br /&gt;
Вы помните времена, когда программист MS-DOS, желающий&lt;br /&gt;
добавить в свою программу такой простой элемент интерфейса,&lt;br /&gt;
как кнопку, должен был выполнять все операции по ее отрисов-&lt;br /&gt;
ке, используя единый цикл обработки сообщений программы?&lt;br /&gt;
Прелесть концепции виджетов заключается в разделении обязан-&lt;br /&gt;
ностей. Большую часть времени виджеты сами заботятся о себе&lt;br /&gt;
(поддерживают свой внешний вид, изменяют размеры и поло-&lt;br /&gt;
жение в зависимости от геометрии окна) и беспокоят вашу про-&lt;br /&gt;
грамму только тогда, когда им действительно «есть, что сказать».&lt;br /&gt;
Сообщения, которые виджеты посылают программе, можно раз-&lt;br /&gt;
делить на две категории, или, точнее, на два уровня. Сообщения&lt;br /&gt;
низкого уровня обычно связаны с действиями устройств ввода&lt;br /&gt;
(нажата клавиша на клавиатуре, переместился указатель мыши);&lt;br /&gt;
высокоуровневые же сообщения, как правило, отражают логику&lt;br /&gt;
работы виджета. Сообщения высокого уровня часто основаны на&lt;br /&gt;
событиях низкого уровня, но могут и не зависеть от них (виджет&lt;br /&gt;
может сообщать о событии, связанном с внутренней работой про-&lt;br /&gt;
граммы, а не с внешним действием).&lt;br /&gt;
     На первый взгляд может показаться, что система виджетов&lt;br /&gt;
должна предоставлять программисту средства обработки исклю-&lt;br /&gt;
чительно высокоуровневых сообщений, но, поскольку ни один,&lt;br /&gt;
даже самый тщательно продуманный набор виджетов не может&lt;br /&gt;
удовлетворить всех программистских запросов, следует преду-&lt;br /&gt;
смотреть и возможность обработки сообщений низкого уровня.&lt;br /&gt;
Примером двухуровневой системы обработки сообщений может&lt;br /&gt;
служить система событий и сигналов в Qt. События Qt соответ-&lt;br /&gt;
ствуют сообщениям низкого уровня, тогда как сигналы отражают&lt;br /&gt;
функциональность виджетов. В FLTK обработка сообщений низ-&lt;br /&gt;
кого уровня выполняется с помощью механизма событий, а обра-&lt;br /&gt;
ботка сообщений высокого уровня, порожденных виджетами – с&lt;br /&gt;
помощью функций обратного вызова.&lt;br /&gt;
       Для обработки событий FLTK классы-потомки fltk::Widget&lt;br /&gt;
используют метод handle(), объявленный как&lt;br /&gt;
 int Widget::handle( int event)&lt;br /&gt;
     В параметре этого метода передается численный идентифи-&lt;br /&gt;
катор события. Метод должен вернуть ненулевое значение, если&lt;br /&gt;
событие было обработано корректно, и 0 в противном случае.&lt;br /&gt;
Хотя метод handle() вызывается для обработки всех событий,&lt;br /&gt;
связанных с виджетом, мы, как правило, хотим обрабатывать&lt;br /&gt;
самостоятельно только некоторые события, возложив все про-&lt;br /&gt;
чее на систему. Шаблон перегруженного метода handle() можно&lt;br /&gt;
представить так:&lt;br /&gt;
 int MyWidget::handle(int event) {&lt;br /&gt;
   switch(event) {&lt;br /&gt;
   ...&lt;br /&gt;
   default:&lt;br /&gt;
     return BaseWidget::handle(event);&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
    Интересующие нас события перехватываются в теле оператора&lt;br /&gt;
switch(), а для обработки остальных событий мы вызываем метод&lt;br /&gt;
handle() базового класса. Каким образом с помощью одного чис-&lt;br /&gt;
лового параметра метода handle() программе передается инфор-&lt;br /&gt;
мация обо всем многообразии событий, на которые должен реа-&lt;br /&gt;
гировать виджет? На самом деле параметр event содержит инфор-&lt;br /&gt;
мацию только о типе события – остальные сведения обработчик&lt;br /&gt;
получает с помощью вспомогательных функций. Объявления&lt;br /&gt;
различных констант и функций, необходимых для обработки&lt;br /&gt;
событий, содержатся в заголовочном файле fltk/events.h. Давайте&lt;br /&gt;
рассмотрим механизмы обработки некоторых распространенных&lt;br /&gt;
типов событий более подробно.&lt;br /&gt;
   Манипуляции с мышью порождают одно из пяти событий:&lt;br /&gt;
ENTER – указатель мыши вошел в область виджета, LEAVE – ука-&lt;br /&gt;
затель покинул область виджета, PUSH – нажата одна из кнопок&lt;br /&gt;
мыши, DRAG – указатель мыши перетаскивается при нажатой&lt;br /&gt;
кнопке (это событие генерируется периодически, до тех пор, пока&lt;br /&gt;
кнопка не будет отпущена), RELEASE – кнопка отпущена. Код&lt;br /&gt;
кнопки мыши, вызвавшей событие, можно получить с помощью&lt;br /&gt;
функции event_key(): значения 1, 2, 3 обозначают левую, среднюю&lt;br /&gt;
и правую кнопки, соответственно. Положение указателя в момент&lt;br /&gt;
возникновения события можно выяснить с помощью функций&lt;br /&gt;
event_x() и event_y(). Любопытно отметить, как FLTK сигнализи-&lt;br /&gt;
рует о прокрутке колесика мыши. Прокрутка колесика порождает&lt;br /&gt;
серию событий MOUSEWHEEL. Функция event_dy() возвращает&lt;br /&gt;
количество единиц прокрутки (положительное значение для про-&lt;br /&gt;
крутки вверх и отрицательное – для прокрутки вниз). Если про-&lt;br /&gt;
крутка сопровождается удерживанием средней кнопки мыши,&lt;br /&gt;
помимо события MOUSEWHEEL генерируется серия событий&lt;br /&gt;
RELEASE (без парных им сообщений PUSH). Функция event_key()&lt;br /&gt;
при этом возвращает значение 4 (прокрутка вверх) или 5 (про-&lt;br /&gt;
крутка вниз).&lt;br /&gt;
   Нажатие клавиши на клавиатуре порождает события KEY (кла-&lt;br /&gt;
виша нажата) и KEYUP (клавиша отпущена). Функция event_key()&lt;br /&gt;
позволяет получить код клавиши (она работает для любой клави-&lt;br /&gt;
ши клавиатуры), а функция event_text() – код символа (для сим-&lt;br /&gt;
вольной клавиши). Значение, возвращаемое event_text(), зави-&lt;br /&gt;
сит от настроек локали и выбранной раскладки клавиатуры.&lt;br /&gt;
С помощью функции event_key() можно связывать специальные&lt;br /&gt;
действия с несимвольными клавишами. Кроме того, эта функ-&lt;br /&gt;
ция удобна, когда некоторое действие должно выполняться при&lt;br /&gt;
нажатии на символьную клавишу независимо от выбранной рас-&lt;br /&gt;
кладки клавиатуры (меня, например, бесят программы, в которых&lt;br /&gt;
сочетания клавиш Ctrl+C, Ctrl+V и Ctrl+Z перестают работать при&lt;br /&gt;
переключении на русскую раскладку). Для многих кодов клавиш,&lt;br /&gt;
возвращаемых функцией event_key(), определены константы-&lt;br /&gt;
мнемоники, например, EscapeKey, HomeKey, LeftKey, UpKey,&lt;br /&gt;
RightKey, DownKey, PageUpKey, PageDownKey, EndKey, PrintKey.&lt;br /&gt;
    Если нажать и удерживать клавишу на клавиатуре, генериру-&lt;br /&gt;
ется серия событий KEY без соответствующих им событий KEYUP.&lt;br /&gt;
В ходе своих экспериментов с обработкой событий FLTK я обнару-&lt;br /&gt;
жил одну странность: событие KEYUP генерируется не тогда, ког-&lt;br /&gt;
да ранее нажатая клавиша отпущена, а в момент нажатия следую-&lt;br /&gt;
щей клавиши (сразу за событием KEYUP генерируется событие&lt;br /&gt;
KEY, соответствующее нажатию новой клавиши). Не думаю, что&lt;br /&gt;
разработчикам следует полагаться на своевременность события&lt;br /&gt;
KEYUP в FLTK (в некоторых ситуациях это событие вообще может&lt;br /&gt;
не случиться).&lt;br /&gt;
    Любопытно отметить, что функции event_key(), event_x() и им&lt;br /&gt;
подобные не являются методами классов виджетов. Это само-&lt;br /&gt;
стоятельные функции, которые получают информацию о пара-&lt;br /&gt;
метрах события из статических переменных, спрятанных в недрах&lt;br /&gt;
FLTK. Такой подход нельзя назвать особо элегантным с точки зре-&lt;br /&gt;
ния объектно-ориентированного программирования. Кроме того,&lt;br /&gt;
поскольку функции «не знают», для какого события они вызваны,&lt;br /&gt;
обработка событий возможна строго в порядке их поступления.&lt;br /&gt;
      Хотя обычно источником событий являются устройства ввода,&lt;br /&gt;
их можно генерировать и программно. Для этого служит метод&lt;br /&gt;
send() класса fltk::Widget. Единственным аргументом метода дол-&lt;br /&gt;
жен быть численный идентификатор события. Метод send() пред-&lt;br /&gt;
ставляет собой, по сути, обертку вокруг метода handle(), однако&lt;br /&gt;
перед тем как вызвать обработчик событий, send() выполняет&lt;br /&gt;
некоторые полезные действия, например, сохраняет координаты x&lt;br /&gt;
и y для событий, связанных с мышью. А что делать, если вы хоти-&lt;br /&gt;
те эмулировать не только событие, но и его параметры, например,&lt;br /&gt;
указать собственные координаты мыши? Для этого придется вос-&lt;br /&gt;
пользоваться недокументированной возможностью – напрямую&lt;br /&gt;
обратиться к тем самым статическим переменным, в которых&lt;br /&gt;
сохраняются параметры события. Имена переменных начинаются&lt;br /&gt;
с префикса e_, и их можно найти в файле fltk/events.h. Например,&lt;br /&gt;
координаты указателя мыши хранятся в переменных e_x и e_y.&lt;br /&gt;
      Вы можете установить глобальный обработчик для всех собы-&lt;br /&gt;
тий, которые не смогли обработать виджеты FLTK (необработан-&lt;br /&gt;
ными считаются события, для которых метод handle() вернул зна-&lt;br /&gt;
чение 0). Заголовок функции обработчика должен иметь вид&lt;br /&gt;
 int handler_name(int event, fltk::Window * window).&lt;br /&gt;
      В параметре event обработчику передается идентификатор&lt;br /&gt;
события, а в параметре window – указатель на объект-окно,&lt;br /&gt;
которому оно предназначалось (поскольку речь идет о необра-&lt;br /&gt;
ботанных событиях, система не всегда может определить окно-&lt;br /&gt;
получателя). Установка обработчика выполняется с помощью&lt;br /&gt;
функции add_event_handler().&lt;br /&gt;
Живой OpenGL&lt;br /&gt;
Чтобы продемонстрировать обработку событий FLTK на прак-&lt;br /&gt;
тике, мы добавим в нашу программу элемент интерактивности&lt;br /&gt;
(новый вариант вы найдете в архиве ogdemo2). Пользователь&lt;br /&gt;
сможет перетаскивать треугольник в окне, «ухватившись» за него&lt;br /&gt;
мышью. Для этого добавим в класс MyGLWindow метод handle() и&lt;br /&gt;
несколько вспомогательных полей:&lt;br /&gt;
  class MyGLWindow : public GlWindow {&lt;br /&gt;
  public:&lt;br /&gt;
      MyGLWindow(int X, int Y, int W,int H, const char* L=0);&lt;br /&gt;
  private:&lt;br /&gt;
      int x1, y1, x2, y2, x3,&lt;br /&gt;
  y3, oldX, oldY;&lt;br /&gt;
      bool moving, isFullScreen;&lt;br /&gt;
      void draw();&lt;br /&gt;
      int handle(int event);&lt;br /&gt;
  };&lt;br /&gt;
      Реализация метода handle() следует описанной выше схеме:&lt;br /&gt;
  int MyGLWindow::handle(int event) {&lt;br /&gt;
     switch(event) {&lt;br /&gt;
     case PUSH:&lt;br /&gt;
      if (event_key() == 1) {&lt;br /&gt;
           unsigned int pixel[3] = {0,0,0};&lt;br /&gt;
           glReadPixels(event_x(), h() - event_y(), 1, 1, GL_RGB, GL_&lt;br /&gt;
 UNSIGNED_INT, &amp;amp;pixel);&lt;br /&gt;
           if ((pixel[0] + pixel[1] + pixel[2]) != 0) {&lt;br /&gt;
             moving = true;&lt;br /&gt;
             oldX = event_x();&lt;br /&gt;
             oldY = event_y();&lt;br /&gt;
         }&lt;br /&gt;
      }&lt;br /&gt;
      return 1;&lt;br /&gt;
     case DRAG:&lt;br /&gt;
      if (moving) {&lt;br /&gt;
       x1 += (event_x() - oldX)*2;&lt;br /&gt;
       x2 += (event_x() - oldX)*2;&lt;br /&gt;
       x3 += (event_x() - oldX)*2;&lt;br /&gt;
       y1 -= (event_y() - oldY)*2;&lt;br /&gt;
       y2 -= (event_y() - oldY)*2;&lt;br /&gt;
       y3 -= (event_y() - oldY)*2;&lt;br /&gt;
       oldX = event_x();&lt;br /&gt;
       oldY = event_y();&lt;br /&gt;
       redraw();&lt;br /&gt;
    }&lt;br /&gt;
    return 1;&lt;br /&gt;
   case RELEASE:&lt;br /&gt;
      moving = false;&lt;br /&gt;
      return 1;&lt;br /&gt;
   case KEY:&lt;br /&gt;
    switch (event_key()) {&lt;br /&gt;
    case EscapeKey:&lt;br /&gt;
        destroy();&lt;br /&gt;
    case 102:&lt;br /&gt;
        isFullScreen ? fullscreen_off(0, 0, 500, 300) : fullscreen();&lt;br /&gt;
        isFullScreen = !isFullScreen;&lt;br /&gt;
        break;&lt;br /&gt;
    default: ;&lt;br /&gt;
    }&lt;br /&gt;
    return 1;&lt;br /&gt;
   default:&lt;br /&gt;
   return GlWindow::handle(event);&lt;br /&gt;
 }&lt;br /&gt;
    Я намеренно не останавливаюсь на особенностях работы&lt;br /&gt;
OpenGL в данной программе – на эту тему можно было бы напи-&lt;br /&gt;
сать отдельную статью. Мы обрабатываем события мыши PUSH,&lt;br /&gt;
DRAG и RELEASE. Кроме них, в нашем методе handle() обрабаты-&lt;br /&gt;
ваются события клавиатуры: нажатие на клавишу Esc приводит к&lt;br /&gt;
завершению работы программы, а кнопка F переключает ее между&lt;br /&gt;
полноэкранным и оконным режимами, для чего используются&lt;br /&gt;
методы fullscreen() и fullscreen_off(). Они реализованы в классе&lt;br /&gt;
Window, а не GlWindow, но, как вы понимаете, при работе с трех-&lt;br /&gt;
мерной графикой они особенно полезны. Обратите внимание, что&lt;br /&gt;
для идентификации клавиши F мы пользуемся значением функ-&lt;br /&gt;
ции event_key(), то есть эта клавиша будет работать независимо&lt;br /&gt;
от раскладки клавиатуры и состояния CapsLock.&lt;br /&gt;
Функции обратного вызова&lt;br /&gt;
Рассмотрим теперь механизм обработки событий высокого уров-&lt;br /&gt;
ня. Как было сказано выше, для передачи сообщений программе&lt;br /&gt;
виджеты FLTK используют функции обратного вызова. Попросту&lt;br /&gt;
говоря, вы можете указать виджету FLTK функцию, которую сле-&lt;br /&gt;
дует вызвать тогда, когда с ним произойдет нечто, достойное&lt;br /&gt;
внимания программы. Для каждого виджета можно зарегистри-&lt;br /&gt;
ровать только одну такую функцию. Это связано с убеждением&lt;br /&gt;
разработчика FLTK в том, что каждый виджет может создавать&lt;br /&gt;
только одно «интересное» событие. Интерфейс функций обрат-&lt;br /&gt;
ного вызова FLTK прост настолько, насколько это возможно: все&lt;br /&gt;
функции обратного вызова имеют заголовок вида&lt;br /&gt;
 void callback_fn(Widget *, void *)&lt;br /&gt;
В первом параметре функции передается указатель на объект-&lt;br /&gt;
виджет, породивший событие, второй параметр представляет&lt;br /&gt;
собой указатель на произвольный блок данных, определен-&lt;br /&gt;
ный программистом. Установить его можно с помощью метода&lt;br /&gt;
user_data(), которым обладает каждый класс-потомок fltk::Widget.&lt;br /&gt;
Для регистрации функции обратного вызова используется метод&lt;br /&gt;
callback(), который, опять же, есть у каждого класса, реализую-&lt;br /&gt;
щего виджет.&lt;br /&gt;
     Вот, собственно, и все. Как вы можете видеть, функция обрат-&lt;br /&gt;
ного вызова не возвращает никаких значений. Дополнительные&lt;br /&gt;
сведения, необходимые для обработки события, можно получить&lt;br /&gt;
с помощью свойств виджета, вызвавшего функцию, а также с&lt;br /&gt;
помощью тех функций, которыми мы пользовались для обработ-&lt;br /&gt;
ки событий низкого уровня. В частности, функция event(), объ-&lt;br /&gt;
явленная в файле fltk/events.h, позволяет узнать, какое именно&lt;br /&gt;
низкоуровневое событие заставило виджет сделать обратный&lt;br /&gt;
вызов. В интерактивной программе OpenGL я добавил функцию&lt;br /&gt;
обратного вызова для главного окна программы. Оно вызывает&lt;br /&gt;
ее в одном-единственном случае – когда пользователь пытается&lt;br /&gt;
закрыть это окно с помощью кнопки [x] в его заголовке. Сама&lt;br /&gt;
функция обратного вызова выглядит просто:&lt;br /&gt;
 void exit_callback(Widget* widget, void*) {&lt;br /&gt;
   if (ask(&amp;quot;Вы действительно хотите выйти?&amp;quot;))&lt;br /&gt;
     ((MyGLWindow*)widget)-&amp;gt;hide();&lt;br /&gt;
 }&lt;br /&gt;
     Функция ask() выводит на экран модальное диалоговое окно с&lt;br /&gt;
кнопками Yes и No (рис. 2).&lt;br /&gt;
     Возвращаемое функцией значение соответствует нажатой&lt;br /&gt;
кнопке. Если пользователь нажал Yes, мы закрываем главное&lt;br /&gt;
окно программы с помощью его метода hide(), что приводит к&lt;br /&gt;
завершению работы всей программы.&lt;br /&gt;
     Последнее, что нам осталось сделать – зарегистрировать&lt;br /&gt;
функции обратного вызова в функции main():&lt;br /&gt;
 MyGLWindow win(0, 0, 500, 300, &amp;quot;OpenGL Test App&amp;quot;);&lt;br /&gt;
 win.callback(exit_callback);&lt;br /&gt;
     Возможно, библиотека FLTK – не лучший выбор для соз-&lt;br /&gt;
дания больших и сложных приложений, но она хорошо под-&lt;br /&gt;
ходит для создания небольших программ, например, «демок»&lt;br /&gt;
OpenGL. Возможно также, что опыт FLTK пригодится вам, если&lt;br /&gt;
когда-нибудь вы захотите написать собственный набор вид-&lt;br /&gt;
жетов. LXF&lt;/div&gt;</description>
			<pubDate>Thu, 21 Jan 2010 10:59:34 GMT</pubDate>			<dc:creator>Crazy Rebel</dc:creator>			<comments>http://wiki2.linuxformat.ru/index.php/%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5:LXF115:FLTK</comments>		</item>
	</channel>
</rss>