http://wiki.linuxformat.ru/wiki/index.php?title=LXF91:GTK%2B&feed=atom&action=historyLXF91:GTK+ - История изменений2024-03-29T12:45:48ZИстория изменений этой страницы в викиMediaWiki 1.19.20+dfsg-0+deb7u3http://wiki.linuxformat.ru/wiki/index.php?title=LXF91:GTK%2B&diff=12093&oldid=prevEwgen: Исправлена ошибка в тексте2011-06-11T14:31:15Z<p>Исправлена ошибка в тексте</p>
<table class='diff diff-contentalign-left'>
<col class='diff-marker' />
<col class='diff-content' />
<col class='diff-marker' />
<col class='diff-content' />
<tr valign='top'>
<td colspan='2' style="background-color: white; color:black;">← Предыдущая</td>
<td colspan='2' style="background-color: white; color:black;">Версия 14:31, 11 июня 2011</td>
</tr><tr><td colspan="2" class="diff-lineno">Строка 39:</td>
<td colspan="2" class="diff-lineno">Строка 39:</td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"></td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>Для того, чтобы понять, как работает библиотека ''libglade'', необходимо сначала разобраться, что представляет собой проект ''Glade.''</div></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>Для того, чтобы понять, как работает библиотека ''libglade'', необходимо сначала разобраться, что представляет собой проект ''Glade.''</div></td></tr>
<tr><td class='diff-marker'>−</td><td style="background: #ffa; color:black; font-size: smaller;"><div>Разбираться, как вы уже поняли, мы будем на примере <del class="diffchange diffchange-inline">программымикрокалькулятора </del>(Рис. 1).</div></td><td class='diff-marker'>+</td><td style="background: #cfc; color:black; font-size: smaller;"><div>Разбираться, как вы уже поняли, мы будем на примере <ins class="diffchange diffchange-inline">программы микрокалькулятора </ins>(Рис. 1).</div></td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"></td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>[[Изображение:LXF91_GTK1.png|Рис. 1]]</div></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>[[Изображение:LXF91_GTK1.png|Рис. 1]]</div></td></tr>
</table>Ewgenhttp://wiki.linuxformat.ru/wiki/index.php?title=LXF91:GTK%2B&diff=5718&oldid=prevCrazy Rebel: /* Приступим к проектированию */2008-12-01T08:48:03Z<p><span dir="auto"><span class="autocomment">Приступим к проектированию</span></span></p>
<table class='diff diff-contentalign-left'>
<col class='diff-marker' />
<col class='diff-content' />
<col class='diff-marker' />
<col class='diff-content' />
<tr valign='top'>
<td colspan='2' style="background-color: white; color:black;">← Предыдущая</td>
<td colspan='2' style="background-color: white; color:black;">Версия 08:48, 1 декабря 2008</td>
</tr><tr><td colspan="2" class="diff-lineno">Строка 65:</td>
<td colspan="2" class="diff-lineno">Строка 65:</td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>[[Изображение:LXF91_GTK2.png|Рис. 2]]</div></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>[[Изображение:LXF91_GTK2.png|Рис. 2]]</div></td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"></td></tr>
<tr><td class='diff-marker'>−</td><td style="background: #ffa; color:black; font-size: smaller;"><div>Окно просмотра структуры элементов интерфейса.</div></td><td class='diff-marker'>+</td><td style="background: #cfc; color:black; font-size: smaller;"><div><ins class="diffchange diffchange-inline">'''</ins>Окно просмотра структуры элементов интерфейса.<ins class="diffchange diffchange-inline">'''</ins></div></td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"></td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>Объекты-контейнеры являются внутренними узлами дерева, а элементы управления – его «листьями». Если мы теперь сохраним проект</div></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>Объекты-контейнеры являются внутренними узлами дерева, а элементы управления – его «листьями». Если мы теперь сохраним проект</div></td></tr>
</table>Crazy Rebelhttp://wiki.linuxformat.ru/wiki/index.php?title=LXF91:GTK%2B&diff=5713&oldid=prevCrazy Rebel: викификация, оформление2008-12-01T08:44:09Z<p>викификация, оформление</p>
<a href="http://wiki.linuxformat.ru/wiki/index.php?title=LXF91:GTK%2B&diff=5713&oldid=5712">Внесённые изменения</a>Crazy Rebelhttp://wiki.linuxformat.ru/wiki/index.php?title=LXF91:GTK%2B&diff=5712&oldid=prevCrazy Rebel: викификация, оформление2008-12-01T07:04:13Z<p>викификация, оформление</p>
<p><b>Новая страница</b></p><div>: '''GTK+''' Разработка переносимых приложений с графическим интерфейсом пользователя<br />
[[Категория:Учебники]]<br />
{{Цикл/GTK+}}<br />
<br />
=Glade на новый лад=<br />
<br />
'''ЧАСТЬ 5''' Описать интерфейс программы в XML и подгрузить его на лету? Совершенно необязательно покупать ''Visual Studio'' и устанавливать ''.NET 3.0'' – '''Андрей Боровский''' покажет, как решить задачу средствами ''Glade''!<br />
<br />
:::''Компьютеры бесполезны, ибо они дают только ответы.''<br />
<br />
::::::::'''Сальвадор Дали'''<br />
<br />
Если бы великий художник лучше разбирался в компьютерах, он сумел бы найти в них гораздо больше недостатков. Чем занимаются большую часть времени настольные компьютеры? Они<br />
выполняют работу более примитивных устройств. Компьютер может<br />
быть видеомагнитофоном, радиоприемником, будильником и, конечно,<br />
конечно, пишущей машинкой. Ну а кроме всего прочего, любая операционная система на любой платформе предлагает программу, выполняющую функции простейшего микрокалькулятора. Непреложный<br />
факт – микрокалькулятор обязательно будет сэмулирован на любой<br />
системе, достаточно мощной доля того, чтобы его эмулировать. Нет, я,<br />
конечно, понимаю, что компьютерные проигрыватели, компьютерные<br />
будильники и компьютерные микрокалькуляторы полезны. Я и сам с<br />
удовольствием ими пользуюсь. Я лишь хочу сказать, что компьютеры<br />
все еще по-настоящему не революционизировали нашу жизнь. Ну а в<br />
ожидании революции, после которой все будет не так, как было, мы,<br />
уважаемый читатель, тоже напишем простейшую программу-калькулятор, и воспользуемся для этого, естественно, инструментарием ''GTK+''.<br />
<br />
В предыдущей статье мы научились создавать проекты графических приложений с помощью ''Glade''. Используя ''Glade 2.x'', мы сгенерировали не только описание интерфейса программы, но и заготовку ее<br />
исходного кода, включая вспомогательные функции и обработчики<br />
событий. Сегодня мы рассмотрим другой способ работы с ''Glade''. При<br />
новом подходе ''Glade'' используется исключительно для проектирования интерфейса, а исходный код приложения пишется программистом с помощью других средств (по-видимому, этот способ работы станет<br />
единственно возможным в ''Glade 3.x'').<br />
<br />
Описание интерфейса, созданное ''Glade'' в формате XML, и исходный код программы связываются между собой с помощью функций<br />
библиотеки ''libglade''. Все это немного похоже на систему ''XMLGUI'', реализованную в KDE. Разница заключается в том, что в ''XMLGUI'' внешний<br />
XML-документ описывает лишь отдельные<br />
элементы интерфейса программы, тогда как<br />
при работе с ''libglade'' все описание интерфейса загружается из XML-файла ['''Это не означает, что в ''Qt/KDE'' нет технологии, аналогичной ''libglade''. Интерфейсы, созданные в Qt Designer, также можно загружать и обрабатывать на лету, – прим. ред.'''].<br />
<br />
==Приступим к проектированию==<br />
<br />
Для того, чтобы понять, как работает библиотека ''libglade'', необходимо сначала разобраться, что представляет собой проект ''Glade.''<br />
Разбираться, как вы уже поняли, мы будем на примере программымикрокалькулятора (Рис. 1).<br />
<br />
[[Изображение:LXF91_GTK1.png|Рис. 1]]<br />
<br />
'''Программа-микрокалькулятор.'''<br />
<br />
<br />
Как можно заметить, наш калькулятор довольно примитивен.<br />
Поддерживаются только операции сложения и вычитания, причем над<br />
целыми числами. Отсутствует контроль переполнения при выполнении<br />
арифметических действий. При желании вы можете нарастить функциональность нашего микрокалькулятора сами – добавить поддержку<br />
чисел с плавающей точкой, тригонометрические функции, встроенный<br />
язык программирования... Нет пределов совершенству. Мы же сосредоточимся на программировании интерфейса калькулятора средствами ''GTK+, Glade'' и ''libglade''.<br />
<br />
Как это обычно бывает при работе со средствами визуального<br />
программирования, проектирование программы начинается с пользовательского интерфейса. В главном окне приложения мы размещаем<br />
несколько контейнеров для более удобной упаковки элементов калькулятора – индикаторной панели и кнопок.<br />
<br />
Свойству '''«Имя»''' объекта главного окна мы присваиваем значение<br />
'''rootwnd'''. Это имя нам нужно запомнить, так как оно будет играть важную роль при взаимодействии с библиотекой ''libglade''. В верхней части<br />
главного окна расположено текстовое поле '''GtkEntry''', которое будет служить индикаторной панелью калькулятора. Кнопки калькулятора – это объекты '''GtkButton'''. Вот, собственно, и все, других элементов управления наш виртуальный калькулятор (как и его «железный» собрат) не предполагает.<br />
<br />
Иерархию объектов-контейнеров и элементов управления, из которых состоит калькулятор, проще (и полезнее) показать, нежели описать. Для этого нужно всего лишь открыть окно '''«Дерево эл. управления»''' среды ''Glade'' (Рис. 2). Перед вами появится древовидный список всех визуальных элементов.<br />
<br />
[[Изображение:LXF91_GTK2.png|Рис. 2]]<br />
<br />
Окно просмотра структуры элементов интерфейса.<br />
<br />
Объекты-контейнеры являются внутренними узлами дерева, а элементы управления – его «листьями». Если мы теперь сохраним проект<br />
''Glade'' под именем '''calculator''', на диске появится файл '''calculator.glade'''.<br />
Именно этот файл содержит описание спроектированного нами графического интерфейса программы. Если мы откроем файл '''calculator.glade''' в текстовом редакторе, то увидим примерно следующее:<br />
<br />
<source lang=xml><br />
<?xml version=”1.0” standalone=”no”?> <!--*- mode: xml -*--><br />
<!DOCTYPE glade-interface SYSTEM “http://glade.gnome.org/glade-2.0.dtd”><br />
<glade-interface><br />
<widget class=”GtkWindow” id=”rootwnd”><br />
<property name=”visible”>True</property><br />
<property name=”title” translatable=”yes”>Калькулятор</property><br />
...<br />
<signal name=”destroy” handler=”gtk_main_quit” last_modification_<br />
time=”Tue, 13 Mar 2007 21:18:21 GMT”/><br />
<child><br />
<widget class=”GtkVBox” id=”vbox1”><br />
<property name=”visible”>True</property><br />
...<br />
<child><br />
<widget class=”GtkEntry” id=”entry1”><br />
<property name=”visible”>True</property><br />
...<br />
</child><br />
...<br />
</source><br />
<br />
Таким образом, файл '''*.glade''' представляет собой XML-документ, в<br />
котором содержатся списки значений свойств каждого объекта интерфейса, а иерархия интерфейса реализована при помощи иерархии<br />
вложенных тегов.<br />
<br />
==Немного кода==<br />
<br />
Теперь, когда у нас есть описание графического интерфейса, созданное ''Glade'', нам будет очень просто написать демонстрирующую его<br />
программу. Открою небольшой секрет – функциональность ''libglade''<br />
используется самой средой ''Glade'', которая должна отображать создаваемый интерфейс в отдельном окне. Исходный код программы, загружающей и отображающей графический интерфейс, описанный в файле '''calculator.glade''', состоит примерно из десяти строк (вы найдете его на диске в файле '''calculator-1.c''').<br />
<br />
<source lang=c><br />
#include <stdlib.h><br />
#include <stdio.h><br />
#include <gtk/gtk.h><br />
#include <glade/glade.h><br />
int main (int argc, char **argv)<br />
{<br />
GladeXML *xml;<br />
gtk_init(&argc, &argv);<br />
glade_init();<br />
xml = glade_xml_new(“calculator.glade”, “rootwnd”, NULL);<br />
if (!xml) {<br />
g_warning(“Failed to create the interface”);<br />
return 1;<br />
}<br />
gtk_main();<br />
return 0;<br />
}<br />
</source><br />
<br />
Обратите внимание, что теперь, помимо заголовочного файла '''gtk/gtk.h''' мы включаем в программу файл '''glade/glade.h'''. Он содержит объявления функций и типов данных библиотеки ''libglade'', а именно она<br />
будет служить рабочей лошадкой нашей программы. Собственно программа начинается с вызова знакомой нам функции '''gtk_init()'''. Далее<br />
мы вызываем новую функцию '''glade_init()'''. Ее задача заключается в<br />
том, чтобы инициализировать систему ''libglade''. Связывание программы с XML-файлом, описывающим ее интерфейс, выполняется функцией '''glade_xml_new()'''. Первым аргументом этой функции должен быть<br />
файл, созданный в ''Glade'', вторым – имя корневого элемента иерархии графических объектов интерфейса, определенного в этом файле.<br />
<br />
Третий параметр '''glade_xml_new()''' описывает домен перевода приложения ('''translation domain'''). В качестве значения этого параметра мы можем передать '''NULL'''. Функция '''glade_xml_new()''' возвращает указатель на структуру<br />
'''GladeXML''', который мы сохраняем в переменной '''xml'''. Структура '''GladeXML''' инкапсулирует описание интерфейса, созданного ''Glade''.<br />
Библиотека ''libglade'' экспортирует несколько<br />
функций, имена которых начинаются с префикса '''glade_xml_'''. Эти функции позволяют<br />
управлять элементами интерфейса, созданного с помощью ''Glade'', и каждой из них в<br />
качестве одного из параметров следует передавать указатель на структуру '''GladeXML'''.<br />
<br />
Впрочем, в версии '''calculator-1.c''' значение<br />
переменной '''xml''' еще не востребовано. Вызов<br />
'''glade_xml_new()''' приводит к загрузке файла<br />
описания интерфейса в программу, а библиотека ''libglade'' позаботится о его правильном<br />
отображении. Нам остается только запустить<br />
цикл обработки сообщений с помощью функции '''gtk_main()'''. Скомпилируем нашу программу, используя следующую команду:<br />
<br />
gcc calculator-1.c -o calculator `pkg-config -- cflags --libs libglade-2.0`<br />
<br />
На этот раз в качестве аргумента утилиты ''pkg-config'' мы используем имя пакета ''libglade-2.0''. Теперь можно запустить программу ''calculator''. Вы, конечно, сразу<br />
заметите, что хотя программа правильно отображает все элементы<br />
пользовательского интерфейса, она ничего не делает (даже завершиться как следует не умеет). Это вполне естественно, ведь мы еще не определили ни одного обработчика сигнала.<br />
<br />
Снова откройте (если, вдруг, вы его закрыли) проект '''calculator'''<br />
в среде ''Glade''. Прежде всего, выделим в редакторе свойств объект<br />
'''rootwnd''', перейдем на вкладку '''«Сигналы»''' редактора свойств и создадим обработчик сигнала '''destroy'''. В качестве процедуры обработчика из<br />
раскрывающегося списка «Обработчик» выберем функцию '''gtk_main_quit()'''. Вот так просто можно связать обработчик сигнала закрытия окна<br />
и функцию завершения работы программы. Далее выделим в редакторе форм одну из цифровых кнопок калькулятора (Рис. 3).<br />
<br />
[[Изображение:LXF91_GTK3.png|Рис. 3]]<br />
<br />
'''Окно редактора формы с выделенной кнопкой.'''<br />
<br />
Всем цифровым кнопкам присвоены имена вида '''numeric_button_x''', где '''x''' – число от 0 до 9. Перейдем на вкладку '''«Сигналы»''' редактора свойств и создадим<br />
для выбранной кнопки обработчик сигнала<br />
'''clicked'''. Процедура обработчика получит имя<br />
'''on_numeric_button_x_clicked()'''. Переименуем<br />
обработчик в '''on_numeric_button_clicked()'''. При<br />
назначении обработчика каждой кнопке в поле<br />
ввода '''«Объект»''' укажем значение '''entry1''' (Рис. 4).<br />
<br />
[[Изображение:LXF91_GTK4.png|Рис. 4]]<br />
<br />
'''Окно редактора свойств в режиме создания обработчика сигнала.'''<br />
<br />
Напомню, что поле ввода '''«Объект»''' позволяет задать имя объекта, указатель на который будет передан процедуре обработчика в качестве дополнительного параметра. Объект '''entry1''' – это объект класса '''GtkEntry''' – '''«индикаторная панель»''' нашего калькулятора. Вполне естественно, что обработчики событий '''clicked'''<br />
цифровых кнопок должны иметь доступ к объекту, представляющему индикаторную панель. Мы переименовали обработчик сигнала '''clicked''' в '''on_numeric_button_clicked()''', чтобы подчеркнуть, что у нас будет один<br />
обработчик сигнала '''clicked''' для всех цифровых кнопок.<br />
<br />
Назначим теперь обработчик '''on_numeric_button_clicked()''' сигналам '''clicked''' всех кнопок с цифрами (не забудем указать объект '''entry1''' в качестве дополнительного параметра обработчика каждой кнопки).<br />
Кнопки '''+, –, =''' и '''C''' имеют имена '''operation_button_plus''', '''operation_button_minus''', '''operation_button_equal''' и '''operation_button_cancel''' соответственно.<br />
В среде ''Glade'' создадим для каждой кнопки свой обработчик события<br />
'''clicked''' (соответственно функции '''on_operation_button_plus_clicked()''',<br />
'''on_operation_button_minus_clicked()''', '''on_operation_button_equal_clicked()''' и '''on_operation_button_cancel_clicked()'''). Обработчикам '''on_operation_button_equal_clicked()''' и '''on_operation_button_cancel_clicked()'''<br />
в качестве дополнительного параметра должен быть передан объект<br />
'''entry1'''. Сохраним проект ''Glade''. На этом визуальное программирование<br />
калькулятора закончено, и нам остается довершить воплощение наших<br />
идей в коде. Вариант программы с обработчиками сигналов вы найдете<br />
в файле '''calculator-2.c''', основанном на файле '''calculator-1.c'''.<br />
<br />
==Доведем до совершенства!==<br />
<br />
Прежде всего нам нужно написать функции-обработчики сигналов:<br />
<source lang=c><br />
void on_numeric_button_clicked(gpointer user_data, GtkButton *button)<br />
{<br />
int i = atoi(gtk_button_get_label(button));<br />
if (mode == COPY_MODE) {<br />
bgvalue = fgvalue;<br />
fgvalue = 0;<br />
mode = INPUT_MODE;<br />
}<br />
fgvalue = fgvalue*10 + i;<br />
sprintf(screen, “%li\0”, fgvalue);<br />
gtk_entry_set_text(GTK_ENTRY(user_data), screen);<br />
}<br />
void on_operation_button_plus_clicked(GtkButton *button)<br />
{<br />
mode = COPY_MODE;<br />
op_state = OP_PLUS;<br />
}<br />
void on_operation_button_minus_clicked(GtkButton *button)<br />
{<br />
mode = COPY_MODE;<br />
op_state = OP_MINUS;<br />
}<br />
void on_operation_button_equal_clicked(gpointer user_data, GtkButton *button)<br />
{<br />
switch (op_state) {<br />
case OP_PLUS:<br />
fgvalue += bgvalue;<br />
break;<br />
case OP_MINUS:<br />
fgvalue = bgvalue - fgvalue;<br />
default:;<br />
}<br />
sprintf(screen, “%li\0”, fgvalue);<br />
gtk_entry_set_text(GTK_ENTRY(user_data), screen);<br />
mode = COPY_MODE;<br />
}<br />
void on_operation_button_cancel_clicked(gpointer user_data, GtkButton *button)<br />
{<br />
bgvalue = fgvalue = 0;<br />
mode = COPY_MODE;<br />
op_state = OP_NONE;<br />
sprintf(screen, “%li\0”, fgvalue);<br />
gtk_entry_set_text(GTK_ENTRY(user_data), screen);<br />
}<br />
</source><br />
<br />
Необходимо указать одну особенность взаимодействия программы ''libglade'' с обработчиками сигналов. Если при связывании сигнала с обработчиком указывается дополнительный параметр, этот параметр<br />
будет первым аргументом функции-обработчика. Вторым аргументом<br />
будет указатель на объект-источник сигнала. Например, в обработчике '''on_numeric_button_clicked()''' первый аргумент указывает на объект<br />
'''entry1''', а второй аргумент – на объект '''numeric_button_x''', для которого<br />
вызван обработчик. Если же при связывании обработчика с сигналом<br />
дополнительные параметры не указываются, первым (и единственным)<br />
аргументом функции-обработчика будет указатель на объект-источник<br />
сигнала. Например, в обработчике '''on_operation_button_plus_clicked()'''<br />
первым аргументом является указатель на объект '''operation_button_plus''', для которого вызван обработчик.<br />
<br />
Вдаваться в подробности работы калькулятора мы не будем. Во-первых, они очевидны. Во-вторых, наша статья посвящена не написанию калькуляторов, а использованию ''libglade'', так что мы рассмотрим<br />
лишь некоторые аспекты взаимодействия обработчиков с элементами<br />
интерфейса.<br />
<br />
В обработчике on_numeric_button_clicked() нам необходимо полу-<br />
чить цифру, соответствующую нажатой кнопке. Мы не можем переда-<br />
вать цифру в дополнительном параметре обработчика, поскольку этот<br />
параметр уже занят объектом entry1. Вместо этого мы просто считыва-<br />
ем цифру, являющуюся меткой нажатой кнопки, с помощью функции<br />
gtk_button_get_label(). Текст элемента ввода entry1 устанавливается с<br />
помощью функции gtk_entry_set_text().<br />
Хотя мы и создали обработчики всех сигналов, но если бы мы ском-<br />
пилировали программу на данном этапе, ее элементы управления все<br />
равно ничего бы не делали. Для того чтобы наладить в программе обра-<br />
ботку сигналов, недостаточно написать их обработчики. Необходимо<br />
решить еще одну проблему, которая в явном или неявном виде возни-<br />
кает во всех средах визуального программирования. В описании интер-<br />
фейса программы мы указали, например, что обработчиком события<br />
clicked для кнопки operation_button_minus является нечто по имени<br />
on_operation_button_minus_clicked(). На этапе визуального программи-<br />
рования строка on_operation_button_minus_clicked() не является име-<br />
нем функции, поскольку никакой функции еще нет. Фактически мы<br />
просто добавили в описание интерфейса программы имя обработчика<br />
сигнала. Если бы связывание сигнала и обработчика выполнялось на<br />
этапе компоновки программы (как это происходит в «настоящих» IDE),<br />
компоновщик нашел бы функцию on_operation_button_minus_clicked()<br />
и связал бы ее с сигналом. Но в GTK+ связывание сигналов и обработ-<br />
чиков происходит во время выполнения программы. Каким же образом<br />
программа находит функцию, соответствующую имени обработчика?</div>Crazy Rebel