Книга
Книга
ПрограммированиеGNOME/GTK+
Артур Гриффитс
ЭНЦИКЛОПЕДИЯ
ББК 32.973
Г 25
Гриффитс Артур•
Г 25 Программирование GNOME/GTK+. Энциклопедия программиста: Пер. с англ./Артур Гриффитс - К.: Издательство «ДиаСофт», 2001.- 720 с.
ISBN 966-7393-94-1
Это издание для тех, кто хочет написать приложение графического интерфейса на языке С в среде GNOME под операционной системой Linux. Десятки стандартных функций GNOME и GTK+ помогают вам в этом, так как могут быть включены в ваше приложение и берут на себя большую часть низкоуровневых и рутинных операций по реализации графического интерфейса пользователя. Ваше приложение выглядит как набор обращений к функциям GNOME и GTK+, между которыми располагаются операторы языка С: в основном, декларирующие, логические или организации циклов. Здесь подробным образом описаны эти стандартные функции и их аргументы, приведены десятки превосходно комментируемых примеров (в том числе и на компактдиске) создания всевозможных окон, контейнеров, всякого рода панелей, полос прокрутки, растровых графических объектов и т.п. Немало места уделено вопросам трансляции прикладных программ, стандартным системным вызовам и связям ваших приложений друг с другом и с операционной системой.
.Научное издание
•Гриффитс Артур
ПРОГРАММИРОВАНИЕ GNOME/GTK+. ЭНЦИКЛОПЕДИЯ ПРОГРАММИСТА
Заведующий редакцией С. Н.Козлов•
Главный редактор Ю.Н.АртеменкоНаучный редактор С.Л.СкловскаяЛитературный редактор Г.Б.ХмыроваВерстка И.В.ХмыроваГлавный дизайнер О.А. ШадринН/К
Сдано в набор 13.07.2001. Подписано в печать 16.08.2001. Формат 70x100/16.
; Бумага газетная. Гарнитура Таймс. Печать офсетная. Усл.печ.л. 54,00 Усл.кр.отт. 54,00 Тираж 3000 экз. Заказ № у ^^'
Издательство «ДиаСофт», 04053, Киев-53, а/я 100, тел./факс (044) 212-1254.e-mail: books@diasoft.kiev.ua, http://Ww.diasoft.kiev.ua.
Отпечатано с готовых диапозитивов -
•в ФГУП ордена Трудового Красного Знамени «Техническая книга»
"Министерства Российской Федерации по делам печати,
телерадиовещания и средств массовых коммуникаций
’ -198005, Санкт-Петербург, Измайловский пр., 29.
Original English language edition Copyright © 2000 by IDG Books Worldwide, Inc.
All rights reserved including the right of reproduction in whole or in part in any form. Ibis translation published by arrangement with IDG Books Worldwide, Inc.
Лицензия предоставлена издательством IDG Books Worldwide, Inc.'
Все права зарезервированы, включая право на полное или частичное воспроизведение в какой бы то ни было форме.
ISBN 966-7393-94-1 (рус.) © Перевод на русский язык. Издательство «ДиаСофт», 2001
ISBN 0-7645-4640-6 (англ.) © IDG Books Worldwide, Inc, 2001
© Оформление. Издательство «ДиаСофт», 2001
Свидетельство о регистрации 24729912 от 11.03.97.
Гигиеническое заключение № 77.99.6.953.П.438.2.99 от 04.02.1999
Содержание
Об авторе14
Предисловие15
В этой книге 15
Что вам потребуется15
Объект для изменения15
Как пользоваться этой книгой16
Примеры кодов18
Благодарности автора издания18
ЧАСТЬ I. С самого начала.19
ГЛАВА 1. Что такое GNOME20
Обо всем понемногу 20
Уровни программного обеспечения21
С,21
glib:21
X21
GDK21
GTK+22
. GNOME22
Приложение~22
Соглашения по наименованию22
Как лучше23
Код объектно-ориентированного Сё23
Инкапсуляция24
Наследование-.24
Методы 25
Что же делают виджеты 26
Сигналы и обратные вызовы 26
Представляем библиотеку glib от GIMP".27
Фундаментальные типы данных 27
Полезные функции glib.'.29
Чтение первоисточника31
Выводы32
ГЛАВА 2. Отображение окна 33
Настройкач33
Программа "Привет мир"33
Окно от GTK+ 37
Закрывающееся окно40
Обратные вызовы и события42
Окно с кнопкой?42
Окно от GNOME44
Начало GNOME-приложения46
Выводы49
ГЛАВА 3. Отображение всплывающего диалогового окна50
Всплывающее окно, диалоговое окно и виджет50
Диалоговые окна51
Диалоговые окна, определенные в GNOME51
Создание простого оператора51
Как задать вопрос54
Вы уверены?56
Ввод с клавиатурыi58
Данные для функции обратного вызова61
Строка отражения динамики процесса63
. Создание всплывающих и диалоговых окон 65
Разрушение окна после его закрытия66
Как прятать окна69
Ввод и вывод данных 72
Выводы75
ГЛАВА 4. Расположение виджетов в окне76
Упаковка ящиков76
Вертикальный ящик77
Горизонтальный ящик.79
Опции горизонтального ящика80
Опции вертикального ящика83
* Задание интервалов между виджетами в ящиках86
Ящики внутри других ящиков89
Упаковка с помощью таблиц1....92
Упаковка маленькой таблицы92
Три кнопки в таблице 95
Необязательные установки97
Перекрывающиеся виджеты101
Совместное использование ящиков и таблиц103
Выводы 106
ГЛАВА 5. Виджеты в качестве контейнеров других виджетов108
Фиксированный контейнер108
Настроенный контейнер 111
Обрамляющий контейнер 114
Аспектный обрамляющий контейнер118
Контейнер с панелями120
Слоистый контейнер123
Скроллинговый оконный контейнер127
Записная книжка:129
Ящик с кнопками133
Выводы•.139
ГЛАВА 6. События, сигналы, обратные вызовы 140
Чтение очереди событий140
Последовательность диспетчеризации событий1^1
Выдача ваших собственных сигналов142
Наименования и идентификаторы сигналов144
Форматы функций обратного вызова145
Фоновая обработка в течение периода простоя153
Таймеры....................................................................................................................... 155
Чтение данных из файла или сокета158
Выводы160
ГЛАВА 7. Монохромные и цветные растровые изображения, курсоры162
Два вида графики162
Формат ХРМ*.163
Отображение изображения в формате ХРМ изданных, вставленных в код программы 166
Отображение из файла изображения в формате ХРМ167
Использование формата ХРМ для оформления кнопки168
Формат ХВМ169
Утилита для работы с монохромными растровыми изображениями170
Отображение курсора в формате ХВМ171
Создание курсора176
Создание курсора из данных формата ХРМ:178
Выводы182
ГЛАВА 8. Меню и панели инструментов 183
Способы создания меню183
Типы меню и макросы188
Формат меню по стандарту GNOME192
Файлы подсказки197
Всплывающее меню 198
Создание панели инструментов200
Семейство пиктограмм-202
Нестандартные пиктограммы207
Запрещение и разрешение доступа к пунктам меню209
Запрещение и разрешение доступа к элементам панели инструментов211
Сокрытие и отображение пунктов меню213
Сокрытие и отображение элементов панели инструментов215
Радиокнопки в меню,217
Радиокнопки на панели инструментов219
Переключатели в меню;222
Переключатели на панели инструментов224
Выводы226
ЧАСТЬ II. Шаг за шагом227
ГЛАВА 9. Виджет GnomeCanvas 228
Виджет GnomeCanvas228
Мышь, событие и порядок в стеке232
События, передаваемые компонентам виджета Canvas235
Перемещение компонентов внутри виджета Canvas241
Изображения на канве244
Текст на канве?247
Группирование компонентов на канве250
Добавление виджетов на канву253
Рисование полигонов на канве255
Аффинные преобразования на канве257
GdkEvent 260
Некоторые общие поля262
GdkEvent263
GdkEventAny 264
GdkEventButton264
GdkEventClient265
GdkEventConfigure 265
GdkEventCrossing265
GdkEventDND„266
GdkEventExpose:Л267
-GdkEventFocus,267
GdkEventKey267
GdkEventMotion 268
GdkEventNoExpose268
GdkEventProperty268
GdkEventProximity269
GdkEventSelection269
GdkEventVisibility 269
Выводы 270
ГЛАбА 10. Область для рисования и графические примитивы271
Основы рисования 271
Рисование по отдельным пикселам273
Рисование и заливка прямоугольников276
Рисование и заливка полигонов>278
Рисование окружностей, эллипсов и дуг281
Рисовайие текста;285
Рисование цветных растровых изображений287
Изменение размеров области для рисования291
Занесение изображения в память и анимация293
Выводы 297
ГЛАВА 11. Цвет и графический контекст298
~Архитектура цвета..... 298
Графический контекст 302
Установка цвета виджета 308
Стили линий в графическом контексте 311
Гравировка пунктиром318
Функции, которые устанавливают значения в GdkGC322
Диалоговое окно для выбора цветов 326
О структуре GtkStyle329
Выводы331
ГЛАВА 12. Мышь и клавиатура332
Реагирование на события мыши332
Захват и освобождение мыши337
Чтение символов с клавиатуры341
Опции командной строки GNOME346
Добавление опций командной строки348
Выводы352
ГЛАВА 13. Шрифты353
Анатомия шрифта.353
Наименования шрифтов 355
Виджет-указатель шрифта357
Метрики и размещение шрифтов360
Выводы 366
ГЛАВА 14. Приемы работы с виджетамиL367
Изучение виджета367
Обращение с виджетом*371
Прислушайтесь к виджету374
Создание, реализация, преобразование и показ377
Создание и разрушение378
Показ и сокрытие378
Установка преобразования и отказ от него378
Реализация и деактивизация379
Показ и сокрытие кнопки379
Стили виджета381
Настройка стилей виджета384
Выводы387
ГЛАВА 15. Апплеты388
Упрощенный апплет 388
Апплет, который запускает приложение390
Отображение меняющейся информации 391
Меню апплета393
Ориентация панели395
Выводы 397
ГЛАВА 16. Перетащить, бросить, копировать, вырезать и вставить398
Операция drag-and-drop над простым текстом398
Графические данные, перемещаемые между приложениями401
Вырезать и вставить408
Выводы 410
ГЛАВА 17. Интерфейс для работы с несколькими документами (MDI)412
Простое окно MDI412
Меню MDI и режимы отображения415
Окно MDI с панелью инструментов420
Выводы424
ГЛАВА 18. Создание вашего собственного виджета425
Виджет-граф в виде полос\425
Использование виджета AgBargraph426
Заголовочный файл виджета AgBargraph427
Виджет AgBargraph430
Изменения и обновления виджета444
Выводы445
ГЛАВА 19. Конфигурация и интернационализация446
Управление окружением 446
Формат файла конфигурации447
Расположение файла конфигурации447
Считывание и запись в файл конфигурации448
Сохранение и выборка вектора450
Типы данных в файле конфигурации451
Интернационализация 454
Выводы456
ЧАСТЬ III. Ссылки и механизмы 227
ГЛАВА 20. Конфигурация и компиляция458
Инсталляция исходного кода GNOME.458
' Установка каталога для разработки 459
Макросы459
Файл configure.in460
Текстовые файлы*.462
Файл acconfig.h463
Сценарий autogen.sh463
Главный файл Makefile.am464
Каталог исходного кода 465
Подчиненный файл Makefile.am 465
Запуск сценария autogen.sh466
Выводы 467
ГЛАВА 21. Виджеты GTK+468
GtkAccelLabel469
GtkAdjustment470
GtkAlignment470
GtkArrow471
GtkAspectFrame472
GtkBin473
GtkBox473
GtkButton 474
GtkButtonBox:474
GtkCalendar475
GtkCheckButton476
GtkCheckMenultem476
GtkCList477
GtkClock 480.
GtkColorSelection 481
GtkColorSelectionDialog482
GtkCombo482
GtkContainer483
GtkCTree..485
GtkCurve489
GtkData490
GtkDial:490
GtkDialog491
GtkDrawingArea492
GtkEditable492
GtkEntry493
GtkEventBox494
GtkFileSelection495
GtkFixed496
GtkFontSelection497
GtkFontSelectionDialog498
GtkFrame500
GtkGammaCurve500
GtkHandleBox501
GtkHBox;502
GtkHButtonBox502
GtkHPaned503
GtkHRuler503
GtkHScale504
GtkHScrollbar504
GtkHSeparator.505
Gtklmage505
GtklnputDialog506
Gtklnvisible507
Gtkltem507
GtkltemFactory508
GtkLabel509
GtkLayout510
GtkList510
GtkListltem512
GtkMenu512
GtkMenuBar514
GtkMenu Item515
GtkMenuShell;515
GtkMisc516
GtkNotebook;516
GtkObject518
GtkOptionMenu519
GtkPacker520
GtkPaned522
GtkPixmap 522
GtkPixmapMenultem 523
GtkPlug523
GtkPreview 523
GtkProgress 525
GtkProgressBar525
GtkRadioButton,526
GtkRadioMenultem527
GtkRange528
GtkRuler529
GtkScale530
GtkScrollbar530
GtkScrolledWindow530
GtkSeparator 531
GtkSocket531
GtkSpinButton 531
GtkStatusbar 533
GtkTable533
GtkTearoffMenultem534
GtkTed535
GtkText535
GtkTipsQuery536
GtkToggleButton536
' GtkToolbar537
GtkTooltips538
GtkTree539
GtkTreeltem541
GtkVBox 541
GtkVButtonBox541
GtkViewport".542
GtkVPaned542
GtkVRuler543
GtkVScale543
GtkVScrollbar.:.544
GtkVSeparator544
GtkWidget545
GtkWindow548
Выводы549
ГЛАВА 22. Виджеты Gnome550
„ GnomeAbout550
GnomeAnimator551
GnomeApp553
GnomeAppBar554
GnomeCalculator....555
GnomeCanvas555
GnomeCanvasEllipse556
GnomeCanvasGroup*556
GnomeCanvasImage557
GnomeCanvasItem:557
GnomeCanvasLine558
GnomeCanvasPolygon558
GnomeCanvasRE558
GnomeCanvasRect559
GnomeCanvasText559
GnomeCanvasWidget559
GnomeClient559
GnomeColorPicker563
GnomeDEntryEdit564
GnomeDialog". 565
GnomeDock567
GnomeDockBand570
GnomeDockitem571
GnomeDockLayout572
GnomeEntry573
GnomeFileEntry.;. 574
GnomeFontPicker575
GnomeFontSelector;575
GnomeGuru576
GnomeHRef.577
GnomelconEntry,577
GnomelconSelection580
GnomeLess 580
GnomeMDI581
GnomeMDIChild582
GnomeMDIGenericChild582
GnomeMessageBox583
GnomeNumberEntry585
GnomePaperSelector.585
GnomePixmap586
GnomePixmapEntry588
GnomeProcBar589
GnomePropertyBox 591
GnomeScores 594
GnomeSpell.595
GnomeStoc^595
GnomeStockPixmapWidget;597
Выводы597
ГЛАВА 23. Некоторые механизмы Linux•598
Коды ошибок в Linux598
Порождение процессов599
Выполнение командной строки602
Конвейерыt602
Время604
Информация о файлах.<..... 606
Системная информация;608
Выводы 611
ГЛАВА 24. Сравнительная анатомия: Win32 и GNOME612
Программа в Win32 612
Программа в GNOME 614
Пошаговое сравнение 616
Инициализация:616
' Главное окно617
Реакция на события617
Главный цикл*617
Закрытие программы618
Глобальные данные618
Выводы619
ПРИЛОЖЕНИЕ А. Что на компакт-диске620
Содержимое компакт-диска 620
Примеры 620
GNOME621
Инструментарий622
ПРИЛОЖЕНИЕ В. Настройка системы для разработки программного обеспечения623
Linux623
gcc (egcs)624
XFree86 624
autoconf и automake624
GNOME, glib, GDK и GTK+624
Инсталляция GTK+ на основе исходных кодовt626
. Получение файлов GTK+ и GNOME с исходным кодом626
Обновление исходного кода627
Отслеживание изменений627
Просмотр исходного кода в оперативном режиме627
ПРИЛОЖЕНИЕ С. Наследование628
ПРИЛОЖЕНИЕ О. Установка и получение arg'633
ПРИЛОЖЕНИЕ Е. Энумераторы640
ПРИЛОЖЕНИЕ Е Сигналы 650
ПРИЛОЖЕНИЕ G. Функции по типу возвращаемого значения657
Глоссарий679
Предметный указатель‘683
Общедоступная лицензия GNU700
Инструкция по инсталляции с компакт-диска'706
ио орв•
Артур Гриффитс (Arthur Griffith) программирует свыше 25 лет, из них несколько посвящено программированию графического интерфейса, включая XII и Motif.
К сфере его деятельности относится мониторинг нефти и газа, системы спутниковой связи, базы данных страховых компаний, системы управления в режиме реального времени, системы диагностики аппаратных средств. Он специализируется в написании интерпретаторов и компиляторов языков программирования и разработал несколько языков специального назначения. Среди книг, которые он написал, — Java Master Reference (Java для профессионалов) и Cobol For Dummies (Cobol для чайников). Он автор совместно с Питером Нортоном Complete Guide to Linux (Полного руководства по Linux). Артур Гриффитс живет в Хомере на Аляске и полностью посвятил себя писательскому труду. Вы можете установить с ним контакт по адресу arthur@belugalake.com.
Предисловие
В этой книге
Если хотите написать GNOME-приложенце, то вы приобрели нужную книгу.
В этой книге один образец программы следует после другого и каждый сопровождается объяснением. Каждый образец — это полностью работоспособная программа, разработанная для демонстрации только чего-нибудь одного.
При изучении или исследовании какого-нибудь нового программного обеспечения всегда желательно иметь простые примеры. Программное обеспечение достаточно сложная штука, подчас невозможно объяснить все нюансы без демонстрации примеров, которые, в свою очередь, могут быть достаточно запутанцыми, если не объяснены ключевые части программы.
Программная документация может быть включена как в виде комментариев к кодам, так и в виде отдельного текста. Примеры в этой книге не имеют встроенных комментариев, каждый из них сопровождается текстом, который объясняет эти коды. Отсутствие комментариев делает содержание книги более четким, и читатель может легко и свободно просматривать структуру программы. Большинство кодов напечатано в книге со строчной нумерацией, таким образом, разъяснения могут относиться только к определенной строке.
Что вам потребуется
Если вы знаете, как программировать в С, имеете доступ к компьютеру с операционной системой Linux и имеете возможность загружать файлы из Internet, то эта книга обеспечит вас необходимыми ноу-хау для написания программ в среде GNOME.
На прилагаемом компакт-диске имеется версия для разработки программного обеспечения, которая описана в приложении А. В качестве альтернативы просмотрите его для того, чтобы получить последнюю версию всего программного обеспечения. Приложение В содержит список всего необходимого вам программного обеспечения и адреса его местонахождения. '
Объект для изменения
GNOME — серьезное, мощное и быстроработающее приложение. К счастью, оно также довольно легкое для понимания. GNOME это постоянно продолжающийся проект. Новшества появляются постоянно. Из-за этого "открытого состояния” рост будет, скорее всего, продолжаться В течение всего существования GNOME и GTK+.
Время от времени будут добавляться новые методы получения программного обеспечения и, возможно, будут обновляться некоторые технологии, описанные в этой книге. Но все приведенные здесь примеры должны продолжать работать. Быть не одобрен-
4
ным — это не то же самое, что быть устарелым, ибо устаревшая функция будет все равно вызываться, и будет добавлен не только новый, а, следует надеяться, лучший вызов.
Как пользоваться этой книгой
Книга разделена на три части. Первая часть — это единое учебное пособие, раскрывающее основы программирования в GNOME и GTK+. Вторая часть также содержит учебные пособия, но они составлены таким образом, чтобы к ним можно было обращаться лишь в случае необходимости. Третья часть не предназначена для последовательного чтения — на большинство разделов имеются ссылки так же, как и на все приложения от С доО.
Приложение А или В: инсталляция программного обеспечения
Если вы счастливый обладатель последней версии Linux, то у вас уже есть основное программное обеспечение и вы можете работать. В противном случае существуют две возможности: вы можете установить программное обеспечение с компакт-диска, прилагаемого к этой книге, или найти его в Internet. Приложение А разъясняет работу с компакт-диском, а приложение В — в Internet.
Глава 24: от Win32 к GNOME
Если вы умеете программировать в Win32, то начинайте читать с главы 24. Эта глава — пошаговое сравнение двух программ, одна из которых написана в Win32, а другая — в GNOME. Существует несколько основных различий. Однако общие концепции написания программ в GNOME очень похожи на правила написанния в Win32.
Часть I: с самого начала
Эта часть книги начинается с описания основ и составлена таким образом, чтобы научить вас создавать приложения, демонстрирующие кнопки, надписи и другие виджеты такого размера, формы и расположения, какие требуются. В главе 1 рассматривается определенная вспомогательная информация, в основном относящаяся к доступным библиотекам и структурам кодов GNOME и GTK+. Само программирование начинается с главы 2, где описываются доступные опции для демонстрации основных окон, позволяющие их конфигурировать и закрывать. Материалы главы 3 дополнительно информируют о возникающих окнах и диалоговых панелях. В главах 4 и 5 рассматриваются вопросы управления окнами, их размерами, контроля в них действий. Как работают команды основных сообщений и как они будут использоваться в процессе работы в приоритетном и фоновом режимах, вы сможете ознакомиться в главе 6, где также рассказывается об именах и идентификаторах. Поскольку GUI — главная тема этого издания, в главе 7 будет показано, как добавлять графику в окна. Глава 8 посвящена примерам, которые показывают, как создавать меню и панели инструментов, а также добавлять в них специальные кнопки вроде переключателей и пиктограмм.
Часть II: шаг за шагом
Эту часть можно изучать от начала до конца, а можно перепрыгивать с одного места на другое. И хотя существует несколько ссылок из одной главы на другую, но в основном главы взаимно независимы.
Глава 9 посвящена специальному окну-канве, которое используется для поддержания других виджетов, рисования линий, заполненных полигонов, текста и т.п. Если окно-кан- ва предоставляет больше возможностей, чем бывает действительно необходимо, то в гла-
ве 10 рассказывается о простых окнах, которые раскрывают область для рисования при установке примитивных функций рисования. Как GNOME управляет цветом и как этим можно управлять в вашей программе, вы узнаете из главы 11. Глава 12 позволяет углубиться в детали реагирования на мышь и клавиатуру. Существует множество доступных шрифтов, которые можно использовать в своей программе, а как это сделать, станет понятно после ознакомления с материалами, предложенными в главе 13. Поскольку каждое окно построено на основе изначального элемента программного обеспечения, известного как виджет, главу 14 следует обязательно прочесть. В ней рассказывается, что такое виджет, показаны элементарные приемы работы с виджетами, установка специальных стилей, отправление сообщений виджету и контроль за его жизненным циклом.
В главе 15 рассматривается, как написать апплет — программу, которая появляется на панели инструментов снизу окна рабочего стола GNOME. Примеры перемещения и сброса между парами приложений приведены в главе 16. Интерфейс GTK+ под названием MDI описан в главе 17. Глава 18 содержит пример написания виджета, а глава 19 имеет дело с интернационализацией и конфигурацией.
Часть III: ссылки и механизмы
Главы в этой части книги в основном описывают ссылки. В главе 20 содержатся примеры установок для автоматической компиляции. Приложения GNOME и GTK+ состоят в основном из собранных вместе виджетов. Глава 21 — список в алфавитном порядке виджетов GTK+. Глава 22 — список в алфавитном порядке виджетов GNOME. Глава 23 раскрывает несколько основных операций Linux, таких, как запуск нового процесса и получение системного времени. В главе 24 проводится сравнение аналогичных программ для Win32 и GNOME.
Ссылки на приложения
Для освоения приведенного программного обеспечения читателю часто требуется подсказка, ее могут оказать приложения, содержащие описательную информацию, которая может помочь в нахождений требуемого.
Приложение
Списки
Содержание
С
Наследование
При работе с объектом существует возможность получить доступ к данным и функциям всех его основных классов. В
' этом приложении приведены все основные классы для
каждого объекта.
К~
Аргумент
Вы можете сконфигурировать ряд значений внутри виджета, передавая значения и имена аргументов. Это
приложение содержит список всех доступных аргументов.
Е
Энумераторы
В GNkME и GTK4- перечислимые типы данных используются как значения. Это приложение содержит таблицу
типов и всех доступных имен констант.
F
Сигналы
Ваша программа получает информацию от виджета посредством подключения к сигналам виджетов. Это
приложение содержит список сигналов, доступных в
каждом виджете
G
Возврат
Каждый объект и тип данных в GNkME и GTK+ описаны с именами функций, которые их возвращают.
Примеры кодов
Большинство примеров программ, описанных в этой книге, содержат актуальные примеры кодов. Насколько возможно, эти примеры совершенно самостоятельные программы. Каждый пример предназначен для демонстрации одной или максимум двух специфических возможностей.
Примеры на самом деле не являются демонстрацией ’’правильной” практики кодирования или даже ’’правильного” пути выполнения специальной программы. Правильного пути не существует, потому что в GNOME и GTK+ обычно имеется несколько путей создания программы. И стиль, и, дизайн программы обычно определяет программист.
Все примеры кодов вместе с make-файлами могут быть получены со следующего сайта:
http://www.belugalake.сот/book/gnomebible-
Благодарности автора издания
Я хочу поблагодарить всех разработчиков программного обеспечения GNOME. Они создали великолепный графический интерфейс пользователя и могут гордиться тем, что создали. Я в долгу перед членами группы разработчиков GNOME, которые потратили немало времени, чтобы ответить на мой вопросы, и наставляли меня на правильный путь.
Джон Осборн (John Osborn) пришел ко мне с оригинальной концепцией этой книги. Он определил ее направление и затем, когда я запутывался, направлял меня в нужное русло. Также хочу поблагодарить Елин Воленски (Elyn Wollensky) за то, что поддерживала меня во время написания этой книги.
Выражаю свою благодарность Лауре Левин (Laura Lewin), сумевшей соединить все таким образом, что эта книга стала реальностью. Кати Дуган (Kathi Duggan) постоянно заставляла всех работать над книгой. Она следила за созданием каждой главы и графического интерфейса при переходе от одной стадии производства к другой и от одного человека к другому. Я чувствую себя более спокойно и уверенно, поместив мое имя на обложку книги, так как Джейсон Ластер (Jason Luster) проверил все и исправил мои технические ошибки и упущения. Виктория Ли (Victoria Lee) показала, как конвертировать мои непонятные словосочетания, встречающиеся в предложениях, таким образом, чтобы каждый мог прочитать и понять их. Благодарю Эми Баркат (Amy Barkat) за очень качественную графику и за то, что освободила меня от множества лишней работы.
И, как всегда, благодарность особой женщине, благодаря которой все это стало возможным — Марго Мейли (Margot Maley) из Вотерсайда.
ЧАСТЬ
■ С самого начала
■w********-^^В этой части
Глава 1: Что такое GNkME
Глава 2:
Отображение
окна
Глава 3:
Отображение
всплывающего диалогового окна
Глава 4:
Расположение
виджетов в окне
Глава 5:
Виджеты в качестве контейнеров других виджетов
Глава 6:
События, сигналы, обратные вызовы
Глава 7:
Монохромные и цветные растровые изображения, курсоры
Глава 8:
Меню и панели инструментов
ГЛАВАГЛАВАЧто такое GNOMEЧто такое GNOME
ГЛАВА
ГЛАВА
Что такое GNOME
Что такое GNOME
В этой главе
^ Разъяснение работы GNkME
Л Уровни программного обеспечения-
W^ Принятые условные обозначения.
^ Язык программирования С и объектно-ориентированный дизайн
:/ Отображение на экране окон и виджетов
Сигналы и обратные вызовы
^ Фундаментальные утилиты
Эта глава представляет основные концепции написания программ в среде GNkME. Думаю, вы быстро поймете, что написать GNKME-приложение удивительно легко. Описание этого процесса начинается в главе 2, однако сначала вы должны кое-что узнать. Прежде всего у вас должна возникнуть идея структуры программы, понимание принятых условных обозначений, затем станет намного легче читать приведенный код и вы быстро начнете профессионально программировать GNKME-приложения. Если вам уже приходилось писать какую-либо программу GUI, то вы наверняка знакомы с большинством концепций, представленных в этой главе, тем не менее, все равно можете ее просмотреть.
Обо всем понемногу
GNOME обладает тем преимуществом, что его среда базируется на программном обеспечении, часть из которого используется сравнительно недолго, а часть — работала ряд лет. Библиотеки программного обеспечения составлены из нескольких источников. Было затрачено много человеко-лет для доведения программного обеспечения до такого состояния, которое мы сейчас имеем. Рис. 1.1 показывает взаимоотношения между различными элементами программного обеспечения, используемого в GNOME-приложении. Однако помимо показанных на рис. 1.1 существуют другие элементы: многие приложения включают другие библиотеки, выполняющие операции с изображениями, а также базы данных, средства безопасности или специальное коммуникационное программное обеспечение, которые в ряде случаев делают диаграмму для специального приложения куда больше.
ApplicationGnome. GTK* •. ,;., gdk glib | x • cApplicationGnome. GTK* •. ,;., gdk glib | x • c
ApplicationGnome. GTK* •
. ,;., gdk glib | x • c
ApplicationGnome. GTK* •
. ,;., gdk glib | x • c
Рисунок 1.1.
Уровни программного обеспечения для GNOME-приложения в Linux
На рисунке все уровни представлены изолированно и жестко один над или под другим, что не совсем верно. Все функции нижних уровней доступны и для программного обеспечения верхних уровней. Например, функция GTK+ может напрямую вызывать X- функцию, а GNOME-приложение — функцию библиотеки С.
Уровни программного обеспечения
Ниже представлено краткое описание каждого из уровней, представленных на рис. 1.1.
С
На самом деле, существуют две группы вызовов функций языка С: для функций из стандартной библиотеки С, таких, как printf () и memcpy(), и для системных вызовов Linux, таких, как open () и inkdir (). Так как язык программирования С появился и разрабатывался в среде UNIX, не всегда удается легко распознать каждую категорию функций.
glib
Это библиотека функций С, макросов и структур, которые используются GDK, GTK+, GNOME, а т^кже в приложениях. Она содержит функции распределения памяти, форматирования строк, даты и времени, ввода/вывода, для работы с таймерами. Библиотека1 также содержит полезные функции для взаимосвязанных списков, массивов, таблиц хеширования, деревьев, кварков и кэшей. Одна из ключевых функций, поддерживаемых glib, — главный цикл, который позволяет GNOME одновременно управлять множеством ресурсов и в то же время работать с функциями в приложениях.
X
Это графическая библиотека, содержащая низкоуровневые функции, используемые для управления дисплеем. Сюда включаются все фундаментальные функции работы с окнами: функции, отображающие окна и отвечающие за управления мышью. Эта библиотека стала стабильной лишь спустя много лет после ее возникновения, и номера версий меняются редко. Точнее — это 11 версия, 6 издание, также известное как XI1R6.
GDK
GIMP Drawing Kit — речь пойдет о средствах рисования пакета GIMP. Инструментарий реализован в виде библиотеки функций, которые упрощают доступ программиста к функциям самой системы X. Библиотека X относится к низкоуровневым, т.е. состоит из огромного количества функций, каждая из которых предназначена для решения специфических и относительно простых задач. GDK создает структуру данных для поддержки информации о конфигурации окон и функций, которые упрощают выполняемые задачи. Например, цвет хранится в структуре GdkColor. Существуют функции, использующие эту структуру для автоматического добавления цвета в палитру. Если в цветовой палитре нет места, то подбирается наиболее подходящий из существующих цветов.
GTK+ .
GIMP Toolkit — инструментарий GIMP. Библиотека GTK+ организует объекты из доступных функций GDK. Большинство этих объектов — отображаемые элементы типа кнопок, ярлыков, окошек ввода текста и т.п. Такого рода объекты известны как виджеты, которые могут быть очень простыми или довольно сложными, если содержать определенное количество других виджетов. Эти объекты упрощают такие процедуры, как воплощение цвета и размера, позиционирование виджетов, работу с мышью, клавиатурой, шрифтами и другими необходимыми элементами в одиночных пакетах со стандартными интерфейсами.
GNOME
В определенном смысле библиотека GNOME — это специализированное расширение библиотеки GTK+. Среда рабочего стола GNOME была разработана для управления всем рабочим столом и GNOME-приложением, часто использующим некоторые объекты и функции через интерфейс к отдельным виджетам рабочего стола. GNOME оставляет основные виджеты для GTK+ и также добавляет некоторые собственные специализированные и более сложные виджеты. Например, виджет GnomeAbout включает в себя всплывающееся окно About (О программе) со списком имен, описательным текстом, пиктограммой и стандартными цветами. Вы также можете создать меню из относительно простых таблиц, выполнив один вызов функции.
Приложение
Прикладная программа, или приложение GNOME, — это программа, вызываемая для инициализации функцией gnome_init(), с возможностями создания одного или нескольких отображаемых окон, которая затем переходит в цикл ожидания сигналов от клавиатуры или мыши.
Соглашения по наименованию
Существует узаконенное соглашение по наименованию, которое помогает поддерживать работу приложения. Практически в каждом случае вы можете увидеть имя чего-то — функции, объекта или чего-нибудь еще — и немедленно узнать, какой библиотеке этот компонент принадлежит. В табл. 1.1 описаны префиксы и типы обычно представляемых элементов. Конечно, существуют исключения, однако это случается редко, так как большинство опытный программистов осознает их важность. Плохо или хорошо, но принятые обозначения дают вам свободу выбора собственных простых названий, позволяя при этом избегать известных префиксов. Основной подход заключается в создании собственного префикса и его использовании для различных целей в приложении.
Таблица 1.1. Принятые соглашения о наименованиях префикса
Префикс
Указывает
G
За исключением одного из других G-префиксов в этой таблице структуру
9 _„
данных, определенных в glib.
Тип данных из glib.
9-.
Gdk
Функцию glib.
Объект или структуру данных из библиотеки GKK.
Таблица 1.1. (продолжение)
Префикс
Указывает
gdk__
GKK_
Функцию GKK.
Постоянную или макрос, определенные в GKK. Большинство констант определено в качестве энумераторов.
Gnome
Объект или структуру данных из библиотеки GNkME.
GNkME_
Постоянную или макрос, определенные в GNkME. Большинство констант определено в качестве энумераторов.
gnome_ Gtk
Функцию GNkME.-.
Объект или структуру данных из библиотеки GTK+.
gtk_ " GTK_
Функцию GTK+.
Постоянную или макрос, определенные в библиотеке GTK+. Большинство констант определено в качестве энумераторов.
Как лучше
В любой системе разработки программного обеспечения существует несколько способов написания кода, который позволит работать программе, что тем более верно для открытых систем программного обеспечения, таких, как GNOME, где очень много программистов участвуют в разработке. Все хакеры GNOME имеют свои собственные представления о том, как это должно работать, а также обо всем другом при написании кодов в GNOME. Что само по себе не так уж и плохо, ибо разнообразие — основа гибкости системы.
Не существует какого-то одногд стандартного способа написания кодов в среде GNOME. Например, существуют, по крайней мере, пять различных вызовов функций, которые могут использоваться для показа обычной панели сообщений с кнопкой ОК. Также имеется несколько функций, которые могут изменить уже созданную панель сообщений.
Мораль всего этого следующая: если вы получили что-нибудь, с чем можно работать, а некоторая программа не работает так, как надо, просмотрите ее еще раз и, возможно, найдете то, что мешает программе работать правильно. Если нет, считайте это приглашением стать хакером и можете модифицировать или добавлять функции, сколь вашей душе будет угодно, а затем возвращать программное изделие в место его рождения или предоставлять всем желающим с ним поработать.
Код объектно-ориентированного С
Объектно-ориентированное программирование — это всего лишь метод организации данных и кодов. Не более и не менее. Такой тип организации работает очень хорошо. Существуют объектно-ориентированные языки, например C++ и Java, которые автоматизируют большинство процессов, необходимых для создания объектов программы. Язык программирования С даже отдаленно не похож на объектно-ориентированный. Библиотеки GTK+ и GNOME написаны на С, и API состоит только из вызовов функций С. Тем не менее, код написан в объектно-ориентированном стиле.
Обычно часть объектно-ориентированных структур представляет примеры вызовов функций, а часть — принятые условные обозначения.
Существуют преимущества и недостатки такой формы организации кодов. Исходный код, написанный на языке С, намного проще и легче для прочтения, чем, скажем, написанный на C++, вдобавок и более мобильный, так как практически для компьютеров любой архитектуры существует компилятор языка С. Поскольку объектная ориентация не является частью собственно языка С, ее пришлось имитировать. Существует несколько мест, где нарушена объектная структура из-за невнимательности или по какой-нибудь другой причине. В приложении можно очень легко поломать структуру объекта.
Имеется несколько характеристик объектов, относящихся к GTK+ и GNOME, самыми важными из которых следует считать инкапсуляцию (encapsulation), наследование (inheritance) и методы (methods).
Инкапсуляция
Характеристика объекта — это то, что инкапсулирует (содержит) информацию о нем. А доступ к этой информации может быть получен только посредством обращений к функциям, специально разработанным для этих целей. Применительно к объектной ориентации эти функции называются методами. '
Так как объекты заданы в виде структур языка С, то отсутствует надежная защита вашей программы от прочтения или внесения изменений. Но это небезопасно, ибо вы можете пропустить определенное действие, связанное с изменением значения. Предположим, в структуре объекта существует поле width и надо увеличить его для того, чтобы сделать окно шире. Для этого следует вызвать функцию, которая устанавливает ширину, вместо того, чтобы просто менять значение в самом поле. В действительности, скорее всего, существуют другие действия, и они должны стать известными для увеличения ширины окна. Вызванная функция установки значенйя автоматически позаботится об этом. Взглянув на исходный текст программы, вы поймете, что функция ничего не делает кроме установки значения и вам по-прежнему необходимо следовать этому правилу. Ибо в дальнейшем вам понадобится поменять эту функцию или сделать что-либо еще, а приложение должно работать.
Существует несколько исключений, но их не так уж и много. Они в основном относятся к очень простым объектам. Некоторые объекты не имеют функций, позволяющих непосредственно читать и записывать значения полей. Большинство этих исключений приходит из GDK, так как это приложение не было разработано в качестве объектно-ориентированного. '
Наследование
Когда бы ни был написан код нового объекта, он всегда основывается на существующих объектах. Код, описывающий объект, — план или проект объекта, — называется классом (class). Причем класс, из которого образуется другой класс, называется базовым. При нажатии кнопки класса GtkButton используется другой класс, GtkBin, как базовый. В свою очередь GtkBin возникает из другого класса, этот класс из следующего и так далее вплоть до базового класса GtkOb ject — единственного класса, не происходящего из какого-либо другого. Все классы изначально происходят из GtkOb ject. Ниже представлена цепочка наследования GtkButton:
GtkButton => GtkBin =^GtkContainer =^GtkWidget => GtkOb ject
ПРИМЕЧАНИЕ:.
Виджеты и операции с ними очень важны в приложениях GNkME и GTK+. Каждый класс, имеющий где-нибудь в генеалогическом древе GtkWidget, тоже является виджетом.
Эта наследственность создается взаимоотношениями в самой структуре. Каждая структура включает в виде первого пункта полную структуру своего основного класса. Например, цепочка начал структур, определяющих GtkButton, выглядит следующим образом:
struct GtkButton {
GtkBin bin;
struct GtkBin {
GtkContainer;
struct GtkContainer { GtkWidget widget;
struct GtkWidget {
GtkObject object;
Как можно видеть, каждый класс включает все данные ото всех базовых классов. Из- за того, что данные базового класса находятся на вершине структуры, всегда можно унаследовать любой класс к одному из базовых классов, что позволяет вызывать методы любого класса по иерархии, как показано в следующем разделе.
ПРИМЕЧАНИЕ_
Здесь следует остановиться и последовательно объяснить смысл терминов класс и объект. Короче говоря, класс — это код определения, который используется для построения объекта, а объект — это определенный образец класса. Процесс создания объекта называется реализацией. Это, однако, только определение класса GtkButton, а ваша программа может иметь дюжины объектов GtkButton. Вы увидите и услышите термин GtkButton при обращении к классу или объекту.
Методы 6
Метод используется для создания нового объекта из класса. Например, GtkButton может быть создан при помощи вызова функции:
GtkWidget *button;
■ button = gtk_button_new_with_label("Label");
Все создающие объект функции имеют в своем имени слово new. Функция gtk_button_new_with_label () создает кнопку, показывающую текст ’’Label". Созданная кнопка является также объектом GtkButton, и его адрес сохраняется в указателе GtkWidget. Это стало возможным из-за объектно-ориентированной возможности, которая называется полиморфизмом. Полиморфизм (pdlimorphism) означает, что любой объект может рассматриваться в качестве одного из базовых классов. Использование указателя GtkWidget создает неоспоримые преимущества при программировании, так как существует множество функций интерфейса GUI, которые работают с объектами GtkWidget.
Когда вызывается метод для работы с существующим объектом, адрес указанного объекта передается как первый аргумент. Например, если кнопке присвоено точное положение в контейнере, она отображается при помощи следующей функции:
gtk_widget_show(button);
Указатель типа данных кнопки — GtkWidget, следовательно, функция работает так же, как и любой другой виджет. Методы всех классов в иерархии вызываются при использовании специальных макросов приведения типов данных. Например, для изменения окружения вокруг кнопки — от появления по умолчанию скошенных кромок к простой неукрашенной кнопке — используется следующий вызов:
gtk_button_set_relief(GTK_BUTTON(button),GTK_RELIEF_NONE);
Можно также хранить ключевые данные в объекте при помощи обращения к следующей функции:
gtk_object_set_data(GTK_OBJECT(button),"key",data);
Существуют макросы приведения типов данных GTK_BIN() и GTK_CONTAINER(). Для каждого виджета в GNOME и GTK+ имеется макрос приведения типов данных. Эти макросы делают несколько больше, чем просто приведение типов: во время работы приложения удостоверяют правильность приведения типов. Эта проверка может сохранить много вашего времени, которое вы потратили бы на поиск таинственных ошибок.
Что же делают виджеты
Виджеты могут работать совместно с другими виджетами и с другими составляющими вашей программы, но в то же время виджет очень важен как автономный объект, который для получения информации или установки данных в нем требует вызова функции. Большинство виджетов имеют окна, появляющиеся на экране дисплея, но некоторые виджеты, предназначенные для специальных целей, обходятся без окон.
Среди таких виджетов наиболее известны контейнеры. Виджет-контейнер — единственный, отвечающий за управление размером и положением одного или нескольких виджетов. Например, если у вас есть диалоговое окно с кнопками OK, Cancel и выведенной строкой текста, то это и будет виджет-контейнер.
Существует много видов виджетов-контейнеров. Одни преобразует свои дочерние виджеты в строки, столбцы, таблицы, а другие распределяют их вверху или в любое другое место окна и поддерживают таким образом, чтобы пользователь мог переключиться с одного на другой. И так как контейнер является виджетом и может сам содержать виджеты, то он может использоваться как дочерний в другом виджете. Вы можете, например, иметь контейнер, который преобразовывает свои дочерние виджеты в столбцы, а каждый элемент столбца может, в свою очередь, быть другим контейнером, преобразующим свои компоненты в строку, таблицу и т.п. .
Сигналы и обратные вызовы
Связь с периферией (мышью и клавиатурой) — это очень ответственный момент для каждого виджета. Ваша программы не может постоянно проверять, какая кнопка нажата. Вместо этого вы инструктируете виджет вызвать функцию в вашей программе после того, как будет нажата кнопка.
Любое действие со стороны технических средств — нажатие клавиши, передвижение мыши или нажатие кнопки мыши — и событие посылается в вашу программу. Это событие трансформируется в сигнал. В то время как событие общается с "железом”, сигнал не возникает. Например, нажатие кнопки мыши — одиночное событие, и оно трансформируется в сигнал, а две нажатые вместе кнопки вызывают сигнал двойного щелчка. В этом случае два события генерируют три сигнала.
События также приходят от менеджера окон системы X, когда бы ни произошли изменения на экране компьютера. Событие возникает, когда окно появляется впервые, становится невидимым, изменяет размер, вновь появляется, закрывается или перемещается. Все это преобразуется в сигналы и становится доступным вашему приложению.
Некоторые сигналы возникают внутри виджетов. Полоса прокрутки сигнализирует о своем новом положении. Сигнал возникает после выбора с помощью мыши пунктов списка, если изменилась ориентация полосы прокрутки с горизонтальной на вертикальную.
Все эти сигналы доступны вашей программе. Все, что вам надо сделать, — это сообщить виджету, какой сигнал вы хотите получить и какую функцию следует вызвать, чтобы получить его. Так как виджет вызывает вас, функция называется функцией обратного вызова (callback function).
Представляем библиотеку glib от GIMP
Существует полезная программа работы с графикой, которая называется GIMP (GNU Image Manipulation Program — программа обработки изображений GNU), которая представлена в большинстве, если не во всех системах Linux. Разработчики GIMP создали glib такой, чтобы она упрощала и стандартизировала разработку программного обеспечения. Эта библиотека содержит определения типов данных, макросы, структуры данных и большую коллекцию полезных вызовов функций. Эти компоненты glib используются для создания библиотек GDK, GTK+ и GNOME. Пользователям очень удобно использовать glib при создании своих приложений. А некоторые вызовы функций GTK+ и GNOME требуют в качестве аргумента тип данных glib.
ПРИМЕЧАНИЕ НАУЧНОГО РЕДАКТОРА
GIMP — известнейший инструмент в стиле Adobe Photoshop, содержащий множество дополнительных модулей. v
Фундаментальные типы данных
В glib определено множество типов данных. Это дань стандартизации и мобильности. Что касается типа int (целое число), то его размер может быть равен 16 бит на одном компьютере и 32 бит на другом. Тип char может не использовать знаковый разряд в одной системе и использовать в другой. Например, если вы используете gint 32 вместо int и gchar вместо char, то ваш исходный код имеет больше шансов стать мобильным при переносе на другую платформу.
ПРИМЕЧАНИЕ
Далее вы обнаружите противоречия в приводимых кодах. Например, есть места, где kit используется поочередно с gint. С тех пор как у каждого программиста появился свой собственный стиль, а в разработку открытого программного обеспечения вовлечено множество программистов, вполне можно наткнуться на подобные различия. Это малая цена, которую мы платим за идею открытого программного обеспечения.
Все определители элементарных типов начинаются с префикса д. Целые числа без знака всегда начинаются с префикса gu. В этом программном фрагменте перечислены все элементарные типы и их размеры:
/*♦ gshow.с ♦*/ #include <gnome.h>
int main(int argc,char *argv[]) { g_print ("gchar:%d\n", sizeof (gchar).);
g_print("guchar:%d\n",sizeof(guchar));
gprint("gint8:%d\n",sizeof(gint8));
g_print("guintS:%d\n",sizeof(guint8));
g_print("gshort:%d\n",sizeof (gshort));
g_print("gushort:%d\n",sizeof(gushort));
‘ gprint("gint!6:%d\n",sizeof(gint!6));
gprint("guintl6:%d\n",sizeof(guint!6));•
g_print("gints%d\n",sizeof(gint));
g_print("guint:%d\n",sizeof(guint));
gprint("gint32:%d\n",sizeof(gint32));
g_print("guint32:%d\n",sizeof(guint32));
g_print ("glong:%d\n", sizeof (glong));
g_print("gulong:%d\n",sizeof(gulong));
g_print("gint64:* %d\n",sizeof(gint64));
g_print("guint64:%d\n",sizeof(guint64));
g_print("gfloat:%d\n",sizeof(gfloat));
gprint("gdouble:%d\n",sizeof(gdouble));
g_print("gpointer:%d\n",sizeof(gpointer));
g_print("gconstpointer: %d\n",sizeof(gconstpointer)); g_print("gboоlean:%d\n",sizeof(gboolean));
exit(O); z
}
Далее следует makefile, который используется для компиляции этой программы. Для установки окружения, необходимого для компиляции и компоновки программ в среде GNOME, используется специальная утилита конфигурирования. В деталях этот процесс описан в главе 2.
СС=дсс
LDLIBS='gnome-config —libs gnomeui' CFLAGS=-Wall -g 'gnome-config —cflags gnomeui' gshow: gshow.о
Определители типов с именами, заканчивающимися числами 8, 16,32 и 64, имеют ту длину, что назначают эти числа, независимо от используемой платформы.
Другие определители могут иметь различную длину, как это установлено языком С. 64-битные целые числа gint6 4 и guint6 4 — единственные, которые объявляются в С как long long. Когда программа работает на версии Linux для х586, вывод выглядит следующим образом:
gchar:1
guchar:1
gint8:1
guintS:1
gshort:2
gushort:2
gint!6: 2 guintl6: 2 gint: 4 guint: 4
gint32: 4 guint32: 4 glong: 4 gulong: 4
gint64: 8 guint64: 8 gfloat: 4 gdouble: 8 gpointer: 4 gconstpointer: 4 gboolean: 4
В табл. 1.2 описываются имена-определители минимальных и максимальных значений, присущие некоторым типам данных. Как показано в табл. 1.3, существует также несколько определенных макросов.
Таблица 1.2. Наименования экстремальных значений данных
МинимальныеМаксимальные,
gshort
G_
_MINSHkRTG_MAXSHkRT
gint
G.
_MININTG_MAXINT.
glong
G.
.MINLkNGG_MAXLkNG
gfloat
G.
_MINFLkATG_MAXFLkAT
gdouble
G_
_MINKkUBLEG_MAXKkUBLE
Таблица 1.3
. Некоторые полезные макросы
/
xxxx
xxxx
ABS (a)
Возвращается положительное значение a.
MAX (a, b)
Числовые значения а и b имеют одинаковый тип данных, ет большее из двух.
и макрос возвраща-
MN (a, b)
Числовые значения а и b имеют одинаковый тип данных,
и макрос возвраща-
ет меньшее из двух.
NULL
Это значение адреса записывается в указателе, который
ни на что не указы-
вает.
TRUE и FALSE
Существует много функций, которые требуют аргумент
типа gboolean. Одно
из этих имен используется для передачи константы, представляющей условие true или false (истинно или ложно). В случае, если вы напишете функцию, которая возвращает тип gboolean, то она может возвратить одно из этих
имен.
Полезные функции glib
В этом разделе представлены некоторые функции, которые далее встретятся в кодах программ и, возможно, будут использоваться в вашем приложении. Существует множество других, кроме представленных здесь, функций, но именно эти вы встретите в исход-
ном коде GDK, GTK+ и GNOME. В этой книге вы найдете несколько примеров таких функций. Так как они очень легки в использовании, вы сможете применять их в вашей программе.'
Представленные здесь функции можно разделить на три категории: для управления памятью, манипуляций со строками и вывода текста. Среди них имеются функции, которые можно отнести сразу к нескольким категориям: например, функции дублирования строк может потребоваться выделение памяти.
g_free(gpointer mem).
Предварительно выделенный блок памяти mem возвращается в систему.
g_print(gchar *format,...)
Эта функция — аналог стандартной функции printf () языка С. Она отправляет строку format на стандартный вывод после включения в нее других значений, передаваемых в качестве аргументов.
g_printerг(gchar *format,...)
Она отправляет строку format в стандартный файл ошибок после включения в нее других значений, передаваемых в качестве аргументов.
gchar *g_strconcat(gchar *,..•)
Для поддержки всех строк, передаваемых в качестве аргументов, выделяется память, в которой строки соединяются, а ее адрес возвращается.
gchar *g_strdup(gchar *str)
Эта функция выделяет память, необходимую для поддержки строки, копирует строку в новую память и возвращает ее адрес.
gchar *g_strdup_printf(gchar ♦format,..•)
Память выделяется для поддержки новой строки, которая создается в соответствии с форматом (вместе с необязательными компонентами), и указатель ее адреса возвращается.
gchar *g_strerror(gint errnumber)
Когда системный вызов С или вызов стандартной библиотеки С встречает ошибочное условие, он сохраняет код ошибки в глобальной переменной errno. Эта функция конвертирует номер ошибки в строку описания.
gchar *g_strndup(gchar *str,gint num)
Выделяется достаточно большая память для поддержки строки, состоящей из num символов, str копируется в нее, и ее адрес возвращается.
gint g_str_equal(gchar *si,gchar *s2)
Эта функция возвращает TRUE, если si совпадает c s2.
gint g_strcasecmp(gchar *strl,gchar *str2)
Эта функция выполняет сравнение без учета регистра (если А равно я) и возвращает
TRUE, если строки идентичны..
gpointer g_malloc(gulong size)
Эта функция выделяет новый блок памяти размером в size байт и возвращает его адрес.
gpointer g_mallocO(gulong size)
Эта функция выделяет новый блок памяти размером в size байт, заполняет нулями и возвращает его адрес.
gpointer g_memdup(gpointer mem,guint size)
Выделяет новый блок памяти размером в size байт, копирует в нее содержимое mem ' и возвращает адрес памяти.
gpointer g__realloc(gpointer mem,gulong size)
Эта функция изменяет размер предварительно выделенного блока памяти. Если функция считает необходимым выделить память размером в size байт, данные из mem копируются в новое место, mem удаляется и возвращается новый адрес.
gpointer memmove(gpointer dest,gpointer src,guint size)
Содержимое src копируется в dest. Так как копируется size байт, предполагается, что src и dest достаточно большого размера. Возвращаемое значение — указатель dest.
void g_strdown(gchar *str)
Все прописные буквы в str конвертируются в строчные.
void g_strup(gchar *str)
Все строчные буквы в str конвертируются в прописные.
Чтение первоисточника
GNOME постоянно меняется. На самом деле все*в Linux постоянно меняется. Разработка программного обеспечения опережает выпуск документации, поэтому время от времени необходимо просмотреть исходный код, чтобы увидеть, как он работает. Доходчивость кодов варьируется от простой и очевидной до совершенно невразумительной и непонятной. Ниже описан один из путей для быстрого нахождения и просмотра части кода. Если загрузить все исходные коды программ в подкаталоги единого каталога, то можно запустить этот сценарий и создать полный индекс всего имеющегося в исходном коде:
find . -name "♦.с" -print >/tmp/clist .,
find . -name "♦.h" -print >/tmp/hlist
cat /tmp/clist /tmp/hlist >/tmp/taglist
rm -f /tmp/clist*
rm -f /tmp/hlist-
ctags -L /tmp/taglist
rm -f /tmp/taglist*
В результате в локальном каталоге возникнет файл по имени tags. Этот файл — база данных имен и местоположений всех общедоступных функций, определенных констант, структур, энумераторов и т.п., находящихся в исходных файлах на языке С во всех подкаталогах. Формат файла тегов такой же, как для редактора vi. Так например, для обнаружения функции gnome_app_new() наберите в командной строке:
vi -t gnome_app_new
Тот же сценарий может быть модифицирован для создания тег-файла для редактора emacs в случае добавления опции -е к ctags или путем использования etags следующим образом:
etags -L /tmp/taglist
Выводы
Развитие программного обеспечения GNOME не стоит на месте. Оно построено на основе GTK+, GDK, glib и X. Большая часть этого программного обеспечения проработала годами, а некоторые компоненты — совершенно новые. Получили распространение другие библиотеки программного обеспечения, используемые в GNOME-приложениях для коммуникаций и доступа к базам данных. Когда вы пишете свое GNOME-приложение, то получаете преимущество, измеряемое в сотнях человеко-лет, в процессе разработки программного обеспечения. Вот некоторые основные темы, раскрытые в этой главе:
® Как и все написанное в С, библиотеки GTK+ и GNOME организованы в коллекцию объектов таким образом, что программа может предсказывать и контролировать их действия
& Создание и использование объектов С требует организации и дисциплины от программиста, но награда того стоит'
> Основной отображаемый объект называется виджетом. Существуют дюжины виджетов и в зависимости от структуры объекта с ними можно работать в стандартной манере
^ GNOME-приложение управляется событиями. А это означает, что тратится много времени на отображение виджетов и ожидание, пока пользователь не сделает что-нибудь с мышкой или клавиатурой. Когда пользователь не работает, сигнал вынуждает функцию обратного вызова передать информацию в приложение
> Были времена, когда ничего не оставалось делать, как переходить к исходному коду используемых библиотек. Иметь доступный исходный код — огромное преимущество, когда вы нуждаетесь в детальной информации
В следующей главе вы узнаете, как написать простую программу в среде GNkME..
ГЛАВА
&*&' Отображение окна
!в этой главе
© Компиляция простых неграфических программ
® Создание make-файлов, с помощью которых будут компилироваться приложения в среде GNOME
© Отображение окна из программы, созданной на основе GTK
® Отображение окна из программы, созданной в среде GNOME
© Присоединение строки меню к окну в среде GNOME
Начало может быть трудным, особенно когда вы работаете с новой системой или новым программным обеспечением. Эта глава демонстрирует создание некоторых весьма простых программ.
Настройка
Эта глава содержит всю основную информацию, необходимую для написания программы, которая отображает окно.
Перед тем как вы начнете программировать, нужно проинсталлировать и сконфигурировать специальное программное обеспечение. Чтобы написать программу в GNOME, надо запустить среду GNOME, получить доступ к компилятору языка С и установить библиотеки GNOME и GTK+. Приложение А содержит полный список всего, что потребуется, и описание, как это установить.
Если хотите скопировать весь исходный код, приведенный в этой книге, то вы найдете его по следующему адресу:
http://www.belugalake.com/book/gnomebible
Программа "Привет мир"
Сначала необходимо убедиться, что все установлено и можно компилировать и компоновать программы. В пустом каталоге создайте файл по имени helloworld.с, который содержит традиционную программу ’’Привет мир”:
/** helloworld.с **/
♦include <stdio.h>
int main(int argc,char *argv[J) {
printf("hello, world\n");
exit(O);
}
Программу можно скомпилировать из командной строки следующим образом:
gcc helloworld.с -о helloworld
Программа дсс компилирует программу на языке С, распознавая расширение ,с. Она компилирует и компонует программу в соответствии со стандартными библиотеками и благодаря опции -о записывает полученный исполняемый файл в файл helloworld. Если опция -о отсутствует, исполняемый файл будет назван a .out. Наберите . /helloworld и программа выведет на экран:
hello, world
ПРИМЕЧАНИЕ
Можно использовать или сс, или дсс. Файл /usr/bin/cc — символическая ссылка на /usr/ bin/gcc. Есть похожая программа /usr/bin/g++, которая содержит некоторые дополнительные особенности для C++.
Программа дсс — это своеобразный мастер на все руки в мире компиляции и компоновки. В командной строке дсс предполагает расширение .с для исходной программы на языке С. Есть несколько других расширений, распознаваемых дсс, что показано в табл. 2.1.
Таблица 2.1. Расширения, распознаваемые дсс
Суффикс Описание файла
.а Библиотечный файл, содержащий один или более объектных файлов (часто называемый архивный файл)
.сИсходныйкод программы на языке С
.СИсходныйкод программы на языке C++
.ссИсходныйкод программы на языке C++
.сххИсходныйкод программы на языке C++
.КФайл для препроцессора
JПредварительно обработанный препроцессором исходный код программы на
языке С
.ii Предварительно обработанный препроцессором исходный код программы на языке C++
.т Исходный код программы на Objective-C
.о Объектный файл, созданный после компиляции или ассемблирования исходного кода
.s Исходный код программы на Ассемблере
.5 Исходный код программы на Ассемблере, который необходимо предварительно обработать
ПРИМЕЧАНИЕ НАУЧНОГО РЕДАКТОРА.
Objective-C — это объектно-ориентированная версия языка С, была разработана для систем NeXT. Компиляция программ на этом языке также выполняется с помощью дсс.
Компилировать и компоновать с использованием дсс достаточно просто. Для больших программ с многочисленными модулями приходится указывать исходные модули и библиотеки в командной строке. В этом случае намного проще использовать таке-файл. Создайте файл по имени makefile (или Makefile, если хотите), содержащий такую строку:'
helloworld: helloworld.с
Слева от двоеточия находится имя исполняемого файла. Справа — файл, от которого зависит исполняемый файл. Введите команду:
make
Случится одно из двух. Или программа будет скомпилирована и сохранена на диске или вообще ничего не случится. Если в каталоге уже есть программа helloworld и она старше, чем helloworld.с, файл не компилируется, так как нет необходимости, другими словами, в исходном коде не происходило изменений. Смысл компилировать без специального использования команды дсс состоит в том, что существуют правила, встроенные в make, которые определяют, как создать один тип файла из другого. Это правило действует не только для языков С и C++, но и для многих других языков программирования. Если вы очень любопытны и хотите получить их список, а это довольно большой список, можете ввести эту команду:
make -р -f /dev/null >makelist
Опция -р вызывает вывод списка всех внутренних установок. Опция -f необходима для указания /dev/null в качестве make-файла; обычно make считывает make-файл из текущего каталога, после чего информация из makefile смешивается с предопределенной информацией.
ПРИМЕЧАНИЕ НАУЧНОГО РЕДАКТОРА
/dev/null — псевдофайл нулевого (несуществующего) устройства.
Команда make имеет слишком много опций, их описание могло бы занять большую часть этой книги. Используемые в этом издании make-файлы не так уж сложны, но они требуют компиляции и компоновки многочисленных модулей программы, используют специальные библиотеки для разрешения внешних ссылок. Например, вот другая программа-приветствие с двумя исходными файлами, первый из которых назван helloworld2.с:
/** helloworld2.c **/
♦include <stdio.h>
void hellomath(double);
int main(int argc,char *argv[J) {
printf("hello, worldXn");
hellomath(2.45);
exit(O);
}
А вот стержневая часть новой программы-приветствия. Она очень похожа на предыдущую программу, хотя в отличие от нее содержит вызов функции hellomath(). Эта функция определена в файле hellomath.с:
/** hellomath.с **/
♦include <math.h>
Iinclude <stdio.h> void hellomath(double value) { 'printf("sine: %g\n",sin(value));
}
Предназначение этой программы — вывод значения синуса, make-файл для компиляции и компоновки программы представлен ниже: LDLIBS=-lm " helloworld2: helloworld2.о hellomath.о helloworld2.os helloworld2.с hellomath.о: hellomath.с clean: rm -f helloworld2 rm -f *.o
Первая строка make-файла указывает, что при компоновке включается библиотека математических функций. Переменная LDLIBS хранит информацию для компоновщика. Раз используется функция sin(), значит для создания программы требуется библиотека математических функций.Опция -1 именует библиотеку в виде сокращения реального имени файла. Компоновщик автоматически предваряет это имя выражением /usr/lib/lib, а затем ставит в конце суффикс . а. Таким образом, опция -1m указывает библиотеку математических функций по имени /usr/lib/libm.a.
Исполняемый файл helloworld2 создается путем компоновки объектных файлов helloworld2 .о с hellomath.о и любой из указанных библиотек. Перед тем как компоновщик начнет работать, проверяются зависимости, указанные в следующих двух строках. Это делается для определения того, какой исходный код следует перекомпилировать. Исходный файл компилируется, если отсутствует объектный файл или исходный код новее существующего объектного файла.
Обычно в конце make-файла присутствует специальная команда, которая не имеет зависимостей, а значит выполняется всегда и используется для удаления выходных файлов — таким образом готовится ’’почва” для полной компиляции и компоновки с помощью следующей команды make. Это может быть выполнено следующим образом: make clean Список команд для clean может быть любым, его даже можно ввести из командной строки. В make-файлах рекомендуется иметь специальные метки для таких команд, как make install (копирование файлов в другое место) или make force (очистка с последующей компиляцией).
ПРИМЕЧАНИЕ
Утилита make появилась на заре возникновения UNIX, а некоторые ее особенности остались с того времени. Первое, на чем можно споткнуться, что табуляция — это часть синтаксиса. Положение операторов rm в предыдущем примере не случайное, оно получено при помощи табуляции, а не обычных пробелов. Если вы получили от make странные сообщения об ошибке, то проверьте табуляцию. Пропуск символов табуляции может привести к тому, что make неверно истолкует оператор и выдаст сообщение об ошибке.
Вот другой make-файл, который делает то же самое, что и предыдущий, но более точно:
СС=дсс
LDLIBS=-lm
CFLAGS=-Wall -д
helloworld2: helloworld2.о hellomath.о
$(СС) $(LDLIBS) helloworld2.о hellomath.о -о helloworld2
helloworld2.о: helloworld2.с
$(СС) $(CFLAGS) -с helloworld2.c
hellomath.о: hellomath.с
$(СС) $(CFLAGS) -с hellomath.с
clean: rm -f helloworld2 rm -f *.o
Здесь так же, как и в предыдущем примере, установлена LDLIBS, но еще указаны, а не берутся по умолчанию, аргументы для компоновщика. Кроме того, указаны команды, применяемые для компиляции двух исходных модулей, и они используют переменную CFLAGS, чтобы передать аргументы дсс. Опция -Wall требует от компилятора выдачи предупреждения обо всем найденном — даже о том, что работает, но не совсем корректно написано. Эта опция используется во всех примерах в этой книге, чтобы вы могли убедиться, что коды корректны настолько, насколько это возможно. При компиляции опция -д инициирует включение отладочной информации, и поэтому для своей программы вы можете использовать отладчик. Но в любом случае на конечном этапе вы захотите удалить из программы отладочную информацию, ибо из-за нее существенно увеличиваются объектные файлы. Можно отбросить отладочную информацию из объектного файла при помощи команды strip или убрать опцию -д из CFLAGS и все перекомпилировать снова.
О make можно говорить очень много, помимо описанного здесь, но даже этого вполне достаточно, чтобы начать компиляцию и компоновку программ. Некоторые другие тонкости, например компоновка с библиотеками третьей стороны и установка зависимостей через заголовочные файлы, выплывут то здесь, то там. В разумных пределах make-файлы в этой книге просты настолько, насколько это возможно.
Окно от GTK+
Программное обеспечение GNOME действительно возведено над GTK+, поэтому вам придется компилировать и компоновать с GTK+ перед компиляцией и компоновкой в GNOME. Программа на основе GTK+ дает возможность управлять окнами, мышью и клавиатурой. Действительно, несколько графических программ в этой книге не требуют обращений к GNOME, так как GTK+ — это полный GUI-пакет.
Эта программа выводит простое окно:
/** gtkwin.c **/
Hnclude <gtk/gtk.h>
int main(int argc,char *argv[]) {
GtkWidget *topLevelWindow;
gtk_init(&argc,6argv);
topLevelwindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_widget_show(topLevelWindow);
gtk_main();
exit(O);
Все включаемые файлы GTK+ находятся в каталоге /usr/include/gtk. Каталог /usr/include — стандартный для включаемых файлов, чтобы уточнить расположение gtk.h нужно будет сообщить компилятору имя каталога относительно /usr/include. Существуют дюжины включаемых файлов для GTK+, но надо назвать только этот один, так как он включает в себя все остальные.
Все программы GTK+ начинаются с обращения к gtk_init(). Эта функция располагает и открывает экран дисплея, а также инициализирует такие элементы, как цвета и обработку сигналов. Аргументы командной строки, переданные в программу, перенаправляются gtk__init(), где будут считаны и отобраны любые аргументы, предназначенные для нее, а все остальные аргументы оставлены на месте. Эта же технология позволяет переадресовать аргументы командной строки GTK+ и вашему приложению. Любые непонятые GTK+ аргументы будут оставлены в массиве argv для передачи вашему приложению. Если, невзирая на приложенные усилия разобраться с аргументами, GTK+ не сможет их использовать, она спустит аргументы GDK, которая по очереди передаст их в систему X Window. Если аргумент используется на каком-либо из уровней, он уда
ляется из argv.
Функция gtk_window_new() вызвана для создания окна верхнего уровня. Главное окно любой программы — это окно верхнего уровня. Программа может иметь больше
одного такого окна. Чаще всего создают одно окно верхнего уровня, а другие окна присоединяют к нему. Вышеуказанный пример имеет только одно окно — окно верхнего уровня.
Функция gtk_widget_show() выводит окно верхнего уровня со всеми его замечательными параметрами, заданными по умолчанию. Размер окна по умолчанию — 200x200 (размер в пикселах), оно имеет серый фон и использует имя программы как за
головок окна. Декорации вокруг окна варьируются в зависимости от менеджера дисплея,
а на рис. 2.1 показано, как это выглядит при работе в GNOME.
Рисунок 2.1.Окно, взятое по умолчаниюРисунок 2.1.Окно, взятое по умолчаниюЭто приложение лишь отображает пустое окно; оно полностью игнорирует мышь и клавиатуру и не прекращает работу, даже когда окно закрыто. Чтобы его остановить, необходимо нажать Ctrl+C из терминального окна, которое вы использовали для инициирования всего этого. Если приложение работает как фоновый процесс, то вам придется набрать команду kill.
Рисунок 2.1.
Окно, взятое по умолчанию
Рисунок 2.1.
Окно, взятое по умолчанию
Для вызова gtk_main() используется блокирующий вызов, ожидающий инструкции для прохождения сквозь очередь событий в то время, как отображается окно. Поскольку в этом примере не предусматривается какая-либо реакция на мышь и клавиатуру, поступление ввода полностью игнорируется. В обычной программе к gtk_main () прилагается список функций, вызываемых при наступлении специальных событий.
Существует много путей создания make-файла, который компилирует эту программу. Именно этот формат выбран для простоты, чтобы легче было вносить изменения и рас
ширять его для других задач.
СС=дсс
LDLIBS='gtk-conf ig —libs'
CFLAGS=-Wall -g 'gtk-config —cflags'
gtkwin: gtkwin.o
$(CC) $(LDLIBS) gtkwin.o -o gtkwin
gtkwin.o: gtkwin.o
$(CC) $(CFLAGS) —c gtkwin.o
clean:
rm -f gtkwin
rm -f *.o
ПРИМЕЧАНИЕ
Существуют лучшие пути создания make-файлов. По мере роста проекта программного обеспечения, оно содержит все больше и больше файлов, а make-файлы становятся все более и более громоздкими. Возникает вопрос об автоматизации определенных аспектов создания make-файлов. Об автоматическом создании make-файлов можно прочитать в главе 20.
В этом make-файле две переменные — CFLAGS и LDLIBS — содержат информацию для процессов компиляции и компоновки. Переменная CFLAGS содержит список аргументов дсс, необходимых для компиляции, а переменная LDLIBS — список аргументов дсс, необходимых для компоновки. Обычно это весьма затруднительная задача, но GTK+ делает ее намного проще, обеспечивая программу (вообще-то сценарий), которая автоматически генерирует аргументы. Это уменьшает возможность ошибки и в качестве бонуса автоматически обновляет наши make-файлы, чтобы приспособить их к новым релизам GTK+. Набрав следующие команды, можно просмотреть сгенерированные аргументы:
gtk-config —cflags
gtk-config --libs
Примечание научного редактора
gtk-config — это сценарий, применяемый для установки опций, которые необходимы для компиляции и компоновки программ, использующих GTK+.
Заметьте, каким образом gtk-config используется в make-файле. Команда должна быть заключена в одинарные обратные, а не в прямые кавычки. Это позволит make исполнить команду, считать ее вывод и сохранить его в виде строки в переменной. Сгенерированные установки — это все, что необходимо для переменой LDLIBS. А на примере переменной CFLAGS этого make-файла видно, что в строку можно добавлять другие аргументы. Опция -Wall предполагает наивысший уровень предупреждающих сообщений, а опция -д вызывает включение отладочной информации.
ПРИМЕЧАНИЕ НАУЧНОГО РЕДАКТОРА,
Ищите одинарную обратную кавычку на той самой клавише, где расположена -(тильда), и никогда не путайте ее с одинарной прямой кавычкой, расположенной на одной клавише с двойной кавычкой. В Unix применяются три разновидности кавычек.
Закрывающееся окно
Большинство программ имеют встроенную опцию ’’Close” в основном меню или панели инструментов. Пользователь, применяя мышь, также может выбрать крестик в верхнем правом углу окна для его закрытия. Выбрать ’’Close” из меню, которое разворачивается из верхнего левого угла, — это то же самое, что выбрать крестик в верхнем правом углу окна. Другими словами, возникающее событие посылает программе информацию о том, что окно закрывается. Для точной работы программа должна перехватить событие и принять решение о том, что же делать дальше. Программа может даже отказаться закрыть окно. Главным образом механизм событий дает программе возможность сбрасывать буфера, закрывать файлы, прекращать коммуникационные связи и делать многое другое, что хорошая программа выполняет, завершая свою работу.
Следующая программа выводит принятое по умолчанию окно и устанавливает пару функций, которые позволяют ей произвести корректный останов:
/** closewin.с ♦*/
♦include <gtk/gtk.h>
gint downCount = 0;
gint eventDelete(GtkWidget *widget,GdkEvent *event, gpointer data);
gint eventDestroy(GtkWidget *widget,GdkEvent *event, gpointer data);
int main(int argc,char *argv[])
{
GtkWidget ♦topLevelWindow;
gtk_init(&argc,&argv);
topLevelWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_signal_connect(GTK_OBJECT(topLevelWindow),
"deleteevent",
GTK_SIGNAL_FUNC(eventDelete),
NULL);
gtk_signal_connect(GTK_OBJECT(topLevelWindow),
"destroy",
GTK_SIGNAL_FUNC(eventDestroy),
NULL);
gtk_widget_show(topLevelWindow);
gtk_main();
g_print("Done!\n");
exit(0);
}
gint eventDelete(GtkWidget *widget,GdkEvent *event, gpointer data) {
g_print("Attempt number %d\n",++downCount);
if(downCount > 2)
return(FALSE);
return(TRUE);
}
gint eventDestroy(GtkWidget *widget,GdkEvent *event, gpointer data) {
g_print("Shutting down\n");
gtk_main_quit(); return!О);
}
Эта программа выводит то же окно, что и в предыдущем примере, но она содержит код, который позволяет управлять ее завершением. Программа начинается с вызова функций gtk_init() и gtk_window_new(), как и в предыдущей программе. После вызова этих двух функций следует вызов функции gtk_signal_connect().
Функция gtk_signal_connect() соотносит событие с указанной функцией. Ей передаются четыре аргумента. Каждое событие относится к определенному окну, таким образом, первый аргумент — это окно, из которого ожидается событие. Второй аргумент — это имя события. Третий — название функции, которая вызывается всякий раз, когда происходит событие. Макрос GTK_SIGNAL_FUNC () просто приводит функцию к типу GtkSignalFunc (). Последний аргумент — это необязательный указатель, который вы можете использовать для того, чтобы передать данные к вашей функции управления событием.
Когда эта программа работает, функция gtk_widget_show() отображает окно, а gtk_main () переходит в режим ожидания до поступления в это окно входной информации. Вводимая в окно информация может иметь любое содержание кроме "delete_eventп (удалить событие) или "destroy" (разрушить), так как это единственное, что регистрируют обработчики событий (особой ситуации). Когда вы используете мышь, пытаясь закрыть окно, gtk_main() получает "delete_event", и это событие используется как аргумент при вызове eventDelete( ). Значение счетчика downCount получает приращение и, если оно меньше 2, функция eventDelete() возвращает FALSE для предотвращения любых дальнейших действий. Окно не закрывается, и программа продолжает работать. С другой стороны, если значение downCount достигло 3 и больше, функция eventDelete() возвращает TRUE, в этом случае окно немедленно классифицируется как закрывающееся, возникает событие "destroy", вызывающее функцию eventDestroy (). Затем следует вызов функции gtk_main_quit(), которая выполняет блокирующий вызов функции gtk_main для освобождения и возврата. Программа выполняет корректное завершение. Запущенная программа создает следующий вывод:
Attempt number 1
Attempt number 2
Attempt number 3
Shutting down
Done!
Как вы видите, существуют три места, где программа может контролировать и выполнять необходимые очистки перед закрытием программы. Иногда не представляется возможным воспользоваться для очистки сигналом "delete_event", поэтому для этой цели можно воспользоваться событием "destroy", размещенным в каком-нибудь другом источнике. Возможно, лучше надеяться только на "delete^event", если вы только хотите получить опцию для отказа закрыть окно. Иначе, создайте просто холостую (фиктивную) функцию, которая всегда возвращает TRUE. Если вам надо что-то сделать во время закрытия, то делайте это или в функции обратного вызова "destroy", или в стержневой части программы, следующей за обращением к функции gtk_main.
Обращение к gtk_main_quit () обязательно. Без этого gtk_main продолжает оставаться в режиме ожидания события для несуществующего окна. Именно это произошло
в предыдущем примере, и вот причина, по которой вы были вынуждены удалить программу после закрытия окна.
Обратные вызовы и события
Все программы в GNOME и GTK+, основываются на получаемых событиях и их обработке. Как мы только что видели, стержневая часть программы ожидает поступления во входную очередь очередного события, а после получения события вызывается некая функция. Эта функция называется функцией обратного вызова, так как система GTK+ вызывает подобные функции в вашей программе.
События обрабатываются в указанном порядке и по одному за один раз. Когда бы функция gtk_main () ни прочитывала событие из очереди, она проверяет, существуют ли какие-нибудь функции обратного вызова, приписанные к нему (их может быть больше одной), и, если существуют, эти функции вызываются. Когда последняя из этих функций будет завершена, gtk_main() просматривает очередь в поисках следующего события.
Существуют события, возникающие вне окна. Ваша программа может поставить события в очередь. Например, можно назначить период времени для задержки события в очереди и установить таймеры, которые затем заставят осуществить вызовы функций. Очередь также используется для взаимодействия между процессами, потому что другие программы, знающие ID (идентификатор) вашего окна, также могут помещать события в вашу очередь.
Окно с кнопкой
Графические элементы — это тоже виджеты. Существуют виджеты, воплощающие меню, метки, панель прокрутки и, как в этом примере, кнопку. В данном примере демонстрируется простое окно с кнопкой для нажатия и, когда с помощью мыши выбирается кнопка (щелчок на кнопке), сообщается, что кнопка была нажата:
/♦* buttonwin.с **/
Iinclude <gtk/gtk.h>
gint eventDelete(GtkWidget *widget, GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget, GdkEvent *event,gpointer data);
void eventButton(GtkWidget *widget, GdkEvent ♦event,gpointer data);
int main(int argc,char *argv[])
{
GtkWidget *topLevelWindow;
GtkWidget *pushMeButton;
gtk_init(&argc,&argv);
topLevelWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_signal_connect(GTK_OBJECT(topLevelWindow),
"delete_event",
GTK_SIGNAL_FUNC(eventDelete), NULL);
gtk_signal_connect(GTK_OBJECT(topLevelWindow),
"destroy",
. GTKSIGNALFUNC(eventDestroy),
NULL);
pushMeButton = gtk_button_new_with_label("Push me!");
gtk_s ignal_connect(GTKOBJECT(pushMeButton),
"clicked",
GTK_SIGNAL_FUNC(eventButton),
NULL);
gtk_container_add(GTK_CONTAINER(topLevelwindow),
pushMeButton);
gtk_container_set_border_width(
GTK_CONTAINER(topLevelWindow), 30);
gtk_widget_show(topLevelwindow);
gtk_widget_show(pushMeButton);
gtk_main();
exit(0);
}
void eventButton(GtkWidget *widget,
GdkEvent *event,gpointer data) { g_print("The button was pushed!\n");
}
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data) {
return(FALSE);
}
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data) {
gtk_main_quit();
return(O);
}
Это пример построен на основе предыдущего. В него просто добавили кнопку для нажатия и функцию, которая вызывается всякий раз, когда кнопка нажата. Это сделано с применением той же процедуры обратного вызова, которую мы использовали для закрытия окна и программы. Кнопка, которая тоже виджет, создается путем вызова функции gtk_button_new_with_label () и указания текста для обозначения кнопки. Эта кнопка работает прекрасно даже без назначенной для нее функции обратного вызова, но в этом случае ваша программа никогда не узнает, когда нажата кнопка. Обращение к gtk_signal_connect () указывает, что функция eventButton() будет вызываться всякий раз, когда нажата кнопка. Программа демонстрирует окно, изображенное на рис. 2.2.
Рисунок 2.2.Обычная кнопка для нажатияРисунок 2.2.Обычная кнопка для нажатияЩелчок не будет воспринят до тех пор, пока вы не освободите кнопку мыши. Когда указатель мыши помещен на кнопку и нажата левая клавиша мыши, кнопка изменяет цвет, тем самым показывая реакцию на выбор. Для выполнения фактического нажатия рассматриваемой кнопки нужно нажать и освободить левую кнопку мыши, пока указатель находится на этой кнопке. Но если после нажатия левой кнопки мыши вы перетащите ее указатель за границы прямоугольника нашей кнопки, не освободив кнопку мыши, щелчок не возникнет и обратный вызов не произойдет.
Рисунок 2.2.
Обычная кнопка для нажатия
Рисунок 2.2.
Обычная кнопка для нажатия
Как только кнопка создана и ей назначен обратный вызов, необходимо подключить ее к окну. Это происходит при помощи функции gtk_container__add(). Размещение виджетов в окне может быть сложным и продолжительным по времени, и упомянутый процесс будет раскрыт в главах 4 и 5. Чтобы это было проще сделать сейчас, поместите кноп-
ку в центр окна при помощи вызова функции gtk_container_set_border_width() для указания размера рамки вокруг окна верхнего уровня. Эта рамка остается фиксированной независимо от размера окна. Единственное, что присутствует в окне — это кнопка, поэтому, когда программа работает и меняются размеры окна верхнего уровня, кнопка пытается подстроиться под изменение его размера, так как границы вокруг нее остаются прежними.
Окно от GNOME
Код, необходимый для создания окна в среде GNOME, очень похож на код для создания окна на основе GTK. GNOME — это набор дополнительных компонентов, воздвигнутых над GTK, и в большинстве случаев функционирование GTK не нарушается. GNOME имеет полное преимущество в этой ситуации, что и демонстрирует следующий далее образец программы:
/** gnomewin.с **/
♦include <gnome.h>
int main(int argc,char *argv[]) {
GtkWidget *topLevelWindow;
gnome_init("gnomewin" , " 1.0 " rargc,argv);
topLevelWindow = gnome_app_new("gnomewin*,"Gnome Window"); gtk_widget_show(topLevelwindow);
gtk_main(); exit(O);
}
Это программа очень похожа на программу, представленную ранее, с названием gtkwin. Есть только два отличия. Рассматриваемая программа вызывает gnome_init () вместо gtk_init() для инициализации системы, и уже функция gnome_init() вызывает gtk_init() для инициализации графики, а также выполняет ряд специфичных для среды GNOME инициализаций. Второе отличие — программа для создания окна обращается к функции gnome_app_new (), тогда как предыдущая программа обращалась к gtk_window_new().
У функции gnome_init() имеются четыре аргумента. Первый аргумент — строка с ID (с идентификатором) приложения, а второй — номер версии. Последние два — это
аргументы, обнаруженные во входной командной строке. Заметьте, что в качестве аргу
Обычное окно GNOMEОбычное окно GNOMEмента argc передается собственно его значение (вместо передачи адреса, как было раньше), а это означает, что никакие аргументы не могут быть удалены из массива argv, потому что любые изменения, внесенные функцией в argc, будут утрачены.
Обычное окно GNOME
Обычное окно GNOME
Функция gnome_app_new() создает в приложении окно верхнего уровня путем обращения к gtk_window_new(). Окно возвращается как GtkWidget так же, как и в предыдущей программе. Первый аргумент — имя прикладной программы. Это имя используется внутри GNOME для идентификации программы. Второй аргумент — это заголовок, который отображается в верхней части окна, как показано на рис. 2.3.
Как и в случае с make-файлами GTK в примерах раньше, существует сценарий, который помогает их создавать. А make-файл для компиляции gnomewin выглядит следующим образом:
CC=gcc'
LDLIBS='gnome-config —libs gnomeui' CFLAGS=-Wall -g 'gnome-config —cflags gnomeui' gnomewin: gnomewin.о $(CC) $(LDLIBS) gnomewin.о -о gnomewin
gnomewin.о: gnomewin.c $(CC) $(CFLAGS) -c gnomewin.c
clean: rm -f gnomewin rm -f *.o
Сценарий, названный gnome-config, используется для объявления опций, которые передаются дсс для компиляции и компоновки программ. Использование обратных кавычек, окружающих оператор (команду), заставляет сценарий исполнить его, а результат работы (собственно вывод) поместить в переменную. Это то же самое, что было сделано ранее с gtk-config, с той лишь разницей, что gnome-config имеет несколько больше опций.
ПРИМЕЧАНИЕ
Это не единственное преимущество gnome-config. Он значительно упрощает написание make-файлов, потому что не требуется помнить имя каждой включаемой библиотеки и проверять, что каждая опция компилятора установлена правильно. К тому же, это очень удобно, когда обновляется версия GNOME, так как вам не требуется изменять свои make- файлы. Новая версия gnome-config автоматически выполняет все обновления.
В этом make-файле переменная CFLAGS установлена для поддержки опций, необходимых для компиляции, a LDLIBS — для компоновки. Вы видите, что их значения берутся gnome-config из командной строки. Реальные значения изменяются от одной версии программного обеспечения к другой, но, чтобы навести вас на мысль, что следует включать, наберите команду: gnome-config —cflags gnomeui
В результате получим:
-I/usr/include -DNEEDGNOMESUPPORTH -I/usr/lib/gnome-libs/include -I/usr/ XI1R6/include -IZusr/lib/glib/include
Как можно видеть, строка опций компиляции в основном состоит из списка каталогов, содержащих включаемые файлы. Это все — одно единое определение переменной. Единственное, что надо добавить, — это каталоги для включения к вашему собственному приложению и любые, какие пожелаете, установки для компиляции: вроде опций -Wall и -д, как в этом примере. Чтобы получить список требуемых библиотек, введите следующее:
gnome-config —libs gnomeui
Результат выглядит следующим образом:
-rdynamic -L/usr/lib -L/usr/XllR6/lib -Ignomeui -lart_lgpl -lgdk_imlib -ISM -1ICE -Igtk -Igdk -Igmodule -IXext -1X11 -Ignome -Ignomesupport -lesd -laudiofile -lm -Idb -Iglib -Idl
Как видите, существует много библиотек. Без сценария gnome-config поддержка этого списка была бы очень обременительной.
Существуют проверяемые имена, отличные от gnomeui. Например, чтобы скомпилировать некий applet (апплет), LDLIBS может быть установлена при помощи такой команды:
gnome-config —libs applets
Результат выглядит следующим образом:
-rdynamic -L/usr/lib -L/usr/XllR6/lib -lpanel_applet -Ignorba -lORBitCosNaming -lORBit -1II0P -lORBitutil -Ignomeui -lart_lgpl -lgdk_imlib -ISM -1ICE -Igtk -Igdk -Igmodule -IXext -1X11 -Ignome -Ignomesupport -lesd -laudiofile -lm -Idb -Iglib -Idl
Существует немало других проверяемых имен. Так имя gtk используется для вызова сценария gtk-conf ig, описанного ранее. Имя glib может быть использовано для вызова сценария glib-config. Для просмотра всех доступных имен наберите:
gnome-config —help
Информация приходит из двух источников. Одни имена, такие, как gnomeui, находятся в самом сценарии. Другие, вроде applets, хранятся на диске в каталоге /usr/lib. Имена файлов начинаются с имен, используемых в командной строке, и заканчиваются на Config . sh. Например, файл, содержащий установки applets, именуется так:
/usr/lib/appletsConfig.sh
Как бы то ни было, сценарий уже не знает имя из командной строки и просматривает каталог /usr/lib в поисках файла с правильным именем. При этом вы можете создать ваши собственные установки окружения. Например, если в ваш проект включаются библиотеки и собственные файлы, то можно установить все это в вйде файлов конфигурации (config-файлы). Содержимое config-файлов очень непосредственное. Вот пример для проекта по имени fred. Файл, названный /usr/lib/fredConf. sh, содержит:
FRED_LIBDIR=’*-L/home/f red/lib”
FRED_LIBS=W-Ifredout -Imrk*
FRED_INCLUDEDIR="-I/home/fred/include",
Когда этот файл на месте, он используется в вашем make-файле подобно другим:
CFLAGS='gnome-config —cflags fred'
LDFLAGS='gnome-config —libs fred'
Начало GNOME-приложения
Этот пример объединяет в себе составляющие из предыдущих примеров и создает маленькое главное окно приложения с меню. Это ничего не делающее приложение GNOME просто отображает свое окно и ожидает инструкций для корректного завершения. Оно написано в качестве образца исходного кода для запуска нового приложения.
1 /♦♦ gnomebase.с **/
2 linclude <gnome.h>
3 4
5 б
7
8
9
10
11
12 13
14
15
16
17
18 19 20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
static void shutdown(); static void showhelp(); gint eventDelete(GtkWidget *widget, GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
GnomeUIInfo fileMenu[] = { { GNOME_APP__UI_ITEM, N_("Exit"), N_("Close all files and exit"), shutdown,NULL,NULL, GNOME APP PIXMAP STOCK,GNOME STOCK MENU ABOUT, 0,0,NULL b GNOMEUIINFOSEPARATOR, GNOMEUIINFO_END
};
GnomeUIInfo helpMenu[] = {
{ GNOME_APP_UI_ITEM,
N_("Help"),N_("Display help information"), showhelp,NULL,NULL, GNOME_APP_PIXMAP_STOCK,GNOMESTOCK_MENU_ABOUT, 0,0,NULL }r GNOMEUIINFOSEPARATOR, GNOMEUIINFO_END
};
GnomeUIInfo mainMenu[] = {
GNOMEUIINFO_SUBTREE(N_("File"),fileMenu), GNOMEUIINFO_SUBTREE(N_("Help"),helpMenu), GNOMEUIINFO_END
};
int main(int argc,char *argv[))
GtkWidget *appWindow;
gnome_init("gnomebase","1.0",argc,argv); appWindow = gnome_app_new("gnomebase","Gnome Base"); gtk_widgetshow(appWindow);
gnome_app_create_menus(GNOME_APP(appWindow),mainMenu);
gtk_signal_connect(GTK_OBJECT(appWindow), "delete_event", GTK_SIGNAL_FUNC(eventDelete), NULL);
gtk_signal_connect(GTK_OBJECT(appWindow), "destroy", GTKSIGNALFUNC(eventDestroy), NULL);
gtk_main();
exit(0);
} void showhelp() {
61 g_print("Show the help windowXn*);
62 }
63 gint eventDelete(GtkWidget *widget,
64GdkEvent *event,gpointer data) {
65 return(FALSE);
66 }
67 gint eventDestroy(GtkWidget *widget,
68GdkEvent *event,gpointer data) {
69shutdown();
70return(O);
71 }
72 void shutdown() {
73 gtk_main_quit();
74 }
Меню определены как массивы структур. Каждый элемент меню (кнопка, разделитель и т.п.) - это один элемент массива. Строка меню сверху — это один массив. Каждый новый уровень меню хранится в своем собственном массиве. В приведенном примере строка меню задается в программной строке 33 как массив mainMenu. Она содержит два подменю, которые определяются макросом GNOMEUIINFO_SUBTREE, при этом задаются имя подменю и имя массива, определяющего подменю. Конец массива отмечен элементом GNOMEUIINFOJEND.
Каждое из двух подменю в строках 11 и 22 имеет по одному входу. Каждый член массива имеет специальный тип. Это означает, что он выполняет определенную работу для системы меню. Оба подменю относятся к типу GNOME_APP_UI_ITEM — это означает, что при их выборе будет происходить вызов функции. Первая строка — это имя, которое появляется в меню, а вторая — это всплывающая подсказка, появляющаяся, когда пункт меню выбирается на панели инструментов. Далее следует имя функции, которая вызывается при выборе пункта меню. Существует множество других опций и установок; все они разъясняются в главе 6.
Рисунок 2.4.Простое приложение co строкой менюРисунок 2.4.Простое приложение co строкой менюКод, который действительно создает меню и устанавливает управление ими, состоит из единственного вызова функции gnome_app_create_menus (). В качестве первого аргумента функция требует указатель на структуру GnomeApp, а макрос GNOME_APP применяется для получения этой структуры из GtkWidget, который, в свою очередь, используется для определения окна верхнего уровня. Окно этой программы показано на рис. 2.4. Строка меню, пересекающая окно сверху, отражает два выбора, определенных в программе.
Рисунок 2.4.
Простое приложение co строкой меню
Рисунок 2.4.
Простое приложение co строкой меню
Здесь показан новый способ выхода из программы. Как и в предшествующих примерах, сигналы на закрытие от менеджера окон могут быть перехвачены по причине выхода из программы. Но теперь это также и выбор меню, как определено в
строке 14, где происходит вызов функции shutdown () для выхода из программы, что определено в строке 72. А поскольку лучше всего иметь единственную точку выхода, функция eventDestroy() вызывает shutdown( ).
В используемом make-файле нет ничего нового. Он выглядит следующим образом:
СС=дсс'
LDLIBS='gnome-config —libs gnomeui'
CFLAGS=-Wall -g 'gnome-config —cflags gnomeui'
gnomebase: gnomebase.о
$(СС) $(LDLIBS) gnomebase.о -о gnomebase
gnomebase.о: gnomebase.с
$(СС) $(CFLAGS) -с gnomebase.с
clean:
rm -f gnomebase
rm -f *.o
Выводы
C GNOME на вершине GTK и c GTK на вершине Xlib можно многого достичь, выполнив лишь один вызов функции. GNOME-приложение не тратит время на низкоуровневую конфигурацию — оно работает непосредственно с окном. Если вы удачно скомпилировали и запустили на выполнение примеры из этой главы, то теперь имеете установленное окружение для разработки программного обеспечения в GNOME и GTK, а также знаете:
О Утилиту make, которая запускает и генерирует исполняемые файлы из исходных
* Сценарий конфигурации gnome-config, который генерирует опции для make-файла
е Отношение между GNOME и GTK
* Формат приложения GNOME
В следующей главе будут представлены другие окна. Приложение обычно имеет одно главное окно и другие окна, которые появляются и исчезают в специальных целях. Вы познакомитесь с событиями, которые должны быть получены из окон, а также с разнообразными способами поддержки мыши в среде GNOME.
50
главаОтображение
3
всплывающего
диалогового окна
В этой главе
Ш Отображение диалогового окна как одиночного окна, которое появляется и исчезает под управлением вашей программы
# Образцы предопределенного набора диалоговых окон в среде GNkME
$ Динамическое создание и разрушение диалоговых окон
^ Временное сокрытие диалоговых окон вместо их постоянного создания и уничтожения
Обычно программа имеет одно главное окно и несколько других окон, которые всплывают и исчезают под управлением мыши. В этой главе разъясняется механизм создания, отображения и разрушения таких преходящих окон.
Некоторые преходящиее окна попадаются так часто, что они поддерживаются даже стандартной частью GNkME. Например, окошко с текстом, закрывающееся при помощи кнопки ОК. Большинство приложений также требует наличия собственных специальных окон. Первая часть этой главы демонстрирует пользу предопределенных преходящих окон, вторая — механизм создания и вывода ваших собственных временных окон.■
Всплывающее окно, диалоговое окно и виджет
Термины всплывающее (popup) окно и диалоговое (dialog) окно — основные компьютерные термины и имеют тенденцию использоваться взаимозаменяемо. Они имеют различные значения, но достаточно похожи, поэтому во многих случаях уместно использование одного из этих терминов. Всплывающее окно — это окно, которое появляется внезапно, чтобы проинформировать пользователя, принять от него входные данные или одновременно для того и другого. Когда всплывающее окно больше не нужно, оно исчезает. Диалоговое окно — это любое окно, содержащее виджеты, которые отображают данные и/или принимают ввод данных от пользователя.
Инструментальные средства GTK+ присваивают специальные значения этим терминам. Всплывающее окно — это отображаемое окно без декораций: менеджер окон не поместит строку заголовка с системными меню на самый его верх. Диалоговое окно — это отображаемое окно, в которое менеджер окон добавляет строку заголовка и системные меню.
Всплывающее или диалоговое окно комплектуется из одного или нескольких виджетов. А виджет — это одноплановый объект программного обеспечения, который обычно
отображает окно. Это окно используется для ввода/вывода информации. Виджет может быть довольно простым (например, кнопка для нажатия) или сложным (динамически меняющий размеры, спускающий список для выбора). И хотя существуют исключения, но большинство виджетов предназначено для включения в окно вместе с другими виджетами, чтобы определить интерфейс для всплывающего или диалогового окна.
Диалоговые окна
Среди них встречаются все виды всплывающих окон: простые, имеющие единственный оператор и кнопку ОК, и сложные, включающие многочисленные метки и другие виджеты для ввода данных. Обычно программа имеет одно главное окно, а все остальное — это диалоговые окна, появлением и исчезновением которых пользователь управляет с помощью мыши.'
Когда ваша программа создает и отображает диалоговое окно, то оно немедленно начинает работать самостоятельно, что свойственно для X Window. Если запущено диалоговое окно, то функция, создавшая его, таким образом выполняет возврат, что ваша программа может продолжать работать. Единственное, что может потребоваться диалоговому окну от вашей программы, — это обращение к функции обратного вызова, если вы таковую указали. Конечно, эта функция может перехватить сигнал мыши, чтобы предотвратить доступ к любому другому окну в вашем приложении, но программа об этом ничего не знает. Она просто терпеливо ожидает ввода от мыши или клавиатуры.
Каждая программа использует одну и ту же функцию для основного цикла:
gtk_main()
Эта функция ждет приходящих событий от мыши или клавиатуры. Когда прибывает событие, информация отправляется в соответствующее окно, которое, в свою очередь, может активизировать функцию обратного вызова. Если вы пишете функцию обратного вызова, использование которой занимает много времени (например, для сортировки большого файла), то фактически все время будет работать функция, а мышь при этом бездействовать, так как никакое событие не будет восприниматься. Существуют способы, позволяющие работать ресурсоемким по времени заданиям да так, чтобы мышь при этом оставалась активной, как описано в главе 5. Но здесь лучше поступить по-другому: отсоединить диалоговое окно от вашей программы, чтобы цикл перехвата событий в gtk_main () мог продолжать функционировать.
Диалоговые окна, определенные в GNOME
Далее представлен набор диалоговых окон, предопределенных и подготовленных для показа. Это традиционные информационные и вопрошающие окна, которые информируют пользователя о таких вещах, как "File not found!” (файл не найден), и спрашивают: "Аге you sure?" (Вы уверены?).
Создание простого оператора
Эта программа демонстрирует, как можно выводить диалоговые окна с использованием минимального кода:
/** okdialog.c **/
♦include <gnome.h>
int main(int argc,char *argv[]) {
gnome_init("okdialog","1.0",argc,argv);
gnome_ok_dialog("A simple information window"); gtk_main();
exit(0);
}
Перед тем как диалоговое окно может быть отображено, необходимо вызвать функцию gnome_init(). Это функция обращается к gnome_ok_dialog(), создающей и демонстрирующей диалоговое окно, как показано на рис. 3.1. Вызванная gtk__main() ожидает щелчка на кнопке ОК; когда это происходит, окно закрывается.
Рисунок 3.1.Простое всплывающее окно с посланиемРисунок 3.1.Простое всплывающее окно с посланиемНикакая информация из этого окна не возвращается в программу. На самом деле программа продолжает работу, как и до этого, она остается на экране, пока не будет выполнен щелчок на кнопке ок, а затем молча исчезает.
Рисунок 3.1.
Простое всплывающее окно с посланием
Рисунок 3.1.
Простое всплывающее окно с посланием
Диалоговое окно автоматически подстраивает свой размер в соответствии с размером текста. Если текст слишком длинный и не помещается на одной строке, он может быть продолжен на следующей строке путем включения символа newline (новой строки), как показано в следующем примере:
/** okmultiple.c **/
Iinclude <gnome.h>
gchar message[] =
"То display a message on\nmore than one line\n"
"it is only necessary to insertXna newline character\n" "wherever you would like the line to break.";
int main(int argc,char *argv[J) {
gnome_init("okmultiple"r"1.0",argc,argv); gnome_ok_dialog(message);
gtkmain();
exit(0);
}
Диалоговое окно, созданное в этом примере, с несколькими строками текста показано на рис. 3.2. В тексте вам предложено вставить newline в том месте, где вы пожелаете выполнить разбивку строки.
Диалоговое окно может быть модальным (modal). Это означает, что никакое другое окно в приложении не примет ввод от мыши или клавиатуры. Следующая программа демонстрирует, как это работает:
/** okmdialog.c **/
Iinclude <gnome.h>
3
int main(int argc,char *argv[])
{
GtkWidget *app;
GtkWidget *dialog;
To display a message on more than one line it is only necessary to insert a newline character
wherever you would like the line to break.
^ OK |
Рисунок 3.2.
Обычное всплывающее окно с текстом в несколько строк
GtkWidget *button;
9
10gnome_init("okmdialog","1.0",argc,argv);
app * gnome_app_new("okmdialog","Okay Dialog");
button = gtk_button_new_with_label("Button");
13gtk_container_set_border_width(GTK_CONTAINER(app),30);
gnome_app_set_contents(GNOMEAPP(app),button);
gtk_widget_show(button);
gtk_widget_show(app);
17
dialog * gnome_ok_dialog(
"A simple information window");•
gtkwindowsetmodal(GTK_WINDOW(dialog),TRUE);
21
gtk_main();
exit(0);
}
Рисунок 3.3.Кнопка главного окнаРисунок 3.3.Кнопка главного окнаЭта программа отображает диалоговое окно, прежде изображенное на рис. 3.1, и также отображает окно, показанное на рис. 3.3. Строки с 10 по 20 создают и выводят главное окно и его кнопку. В то время как отображаются главное и диалоговое окна, только кнопка в диалоговом окне отвечает за сигнал мыши путем обращения к функции gtk_window_set_modal () в строке 20. Кнопка главного окна игнорирует мышь до тех пор, пока не будет выполнен щелчок на кнопке ок диалогового окна, затем диалоговое окно закрывается. После чего кнопка главного окна работает нормально.
Рисунок 3.3.
Кнопка главного окна
Рисунок 3.3.
Кнопка главного окна
Строки 15 и 16 отображают виджеты button и арр. В этом примере дочерний виджет button отображается перед своим родительским виджетом арр. Если поменять местами порядок обращений к gtk_widget_show(), то конечный результат будет тот же, но процесс изображения виджетов на экране будет отличаться. Более подробно это будет обсуждаться далее в этой главе.
Код в строках с 18 по 20 создает и отображает диалоговое окно, не требуя в качестве аргумента окно арр. Это означает, что диалоговое окно легко может быть создано в любом месте вашей программы и можно поддерживать все окна приложения активными, пока идет диалог.
Обращение к gtk_widget_show() в строках с 15 по 16 может происходить в любом порядке. Дело в том, что виджет button вообще не будет отображаться, если также не отображается виджет арр. Это происходит потому, что в обращении к gnome_app_set_contents () из строки 14 виджет button размещен внутри арр, что очень разумно, так как полное окно со всеми его виджетами появится сразу же. В случае большого окна, содержащего множество виджетов, если внешнее окно отображается первым, сразу после этого по одному могут возникнуть все включенные в него виджеты.
До сих пор рассматривались диалоговые окна сами по себе и с помощью мыши их можно было размещать перед или после любого другого окна на дисплее. Новый пример демонстрирует, что диалоговое окно, имеющее родительское окно, должно всегда оставаться перед ним. Это существенно при использовании модальных диалоговых окон, так как родительское окно в любом случае неактивно, а сокрытие диалогового окна может привести к самым неожиданным последствиям. Вы можете изменить программу в строках 18 и 19:
Рисунок 3.4.Всплывающее окно с сообщением об ошибкеРисунок 3.4.Всплывающее окно с сообщением об ошибкеРисунок 3.5.Всплывающее окно с предупреждениемРисунок 3.5.Всплывающее окно с предупреждением
Рисунок 3.4.
Всплывающее окно с сообщением об ошибке
Рисунок 3.4.
Всплывающее окно с сообщением об ошибке
Рисунок 3.5.
Всплывающее окно с предупреждением
Рисунок 3.5.
Всплывающее окно с предупреждением
dialog = gnome_ok_dialog_parented(
"A simple information window", GTKWINDOW(app));
Это позволяет окну арр стать родительским по отношению к диалоговому. Любое окно может быть родительским для одного или нескольких дочерних окон, поэтому вы можете использовать технологию, применяющуюся для всплывающих диалоговых окон, для любого окна приложения.
Существуют два других диалоговых окна, которые работают так же, как диалоговое окно с кнопкой ОК. Оба диалоговых окна — с предупреждениями и сообщениями об ошибках — могут находиться в режиме родительского и не родительского окна, а также могут быть модальными и не модальными. Чтобы вывести окно с сообщением об ошибке, представленное на рис. 3.4, измените строки 18 и 19:
dialog = gnome_error_dialog_parented( "A simple error window", GTKWINDOW(app));
Третий тип обычных всплывающих окон с кнопкой ОК— это окна с предупреждением, как на рис. 3.5. Демонстрируемый код аналогичен вышеприведенным кодам:
dialog = gnome_warning_dialog_parented( "A simple warning window", GTKWINDOW(app));
Как задать вопрос
Чтобы получить из диалогового окна ответ "Да" или ’’Нет", необходимо выяснить, какой из двух ответов выбрал пользователь. Ответ перехватывается при помощи функции обратного вызова. Вот пример программы, которая выводит диалоговое окно с вопросом и перехватывает ответ:
/*♦ questiondialog.с ♦♦/
tinclude <gnome.h>
3
void cbfunction(gint reply,gpointer data);
5
int main(int argc,char.*argv[])
{
gnome_init("questiondialog","1.0",argc,argv);
9
gnome_question_dialog("A simple question window",
(GnomeReplyCallback)cbfunction,
NULL);
13
gtk_main();
exit(0);
}
void cbfunction(gint reply,gpointer data) {
if(reply == GNOMEYES)
g_print("The answer is YES\n");
else
Рисунок 3.6.Всплывающее окно с вопросомРисунок 3.6.Всплывающее окно с вопросом21g_print("The answer is NO\n");
Рисунок 3.6.
Всплывающее окно с вопросом
Рисунок 3.6.
Всплывающее окно с вопросом
22 }
В результате ее работы мы получим окно, показанное на рисунке 3.6. Функция, вызванная в строке 10, создает и отображает диалоговое окно. Имя cbfunction () функции обратного вызова передается диалоговому окну таким образом, что, когда пользователь выбирает кнопку "YES" (Да) или "No" (Нет), будет вызвана функция для регистрации сделанного в программе выбора. Функция cbf unction () из строки 17 вызывается из диалогового окна с целым значением, хранящим ответ и копию указателя данных, который был передан в стро-
ке 12. Вот вам и причина для применения указателя: иногда функция обратного вызова выполняет действие, которое требует доступа к данным, и вместо того, чтобы делать данные глобальными, может быть передан указатель на них.
Когда получен ответ на вопрос, значение аргумента reply или равно GNOME_YES, что означает Да, или GNOME_NO, что означает Нет. И еще один важный момент: вы должны использовать именованные константы для проверки значения reply, так как в стандартном языке С действительные значения числовых тестов "true-false" (истинно-ложно) противоположны. Следующий оператор даст вам неожиданный ответ:
if(reply).../** wrong **/
Существуют четыре значения констант. Значение GNOME_OK — это то же самое, что и GNOME^YES, a GNOME_CANCEL — то же, что и GNOME_NO.
Вот другой пример, отвечающий на те же вопросы, что показаны на рис. 3.6, но в этом случае диалоговое окно является модальным и связано с родительским окном:
/** qmpdialog.c **/
#include <gnome.h>
3
void yes_or_no(gint reply,gpointer data);
int main(int argc,char *argv[])
{
GtkWidget *app;
GtkWidget *dialog;
GtkWidget *button;
11
gnome_init("qmpdialog","1.0",argc,argv);
app = gnome_app_new("qmpdialog","Question Dialog”);
button = gtk_button_new_with_label("Button");
gtk_container_set_border_width(GTK_CONTAINER(app), 30);
gnome_app_set_contents(GNOME_APP(app),button);
gtk_widget_show(button);
gtk_widget_show(app);
19
dialog = gnome_question_dialog_modal_parented(
"A simple questionwindow",
(GnomeReplyCallback)yesorno,
NULL,
GTK_WINDOW(app));
25
gtk_main();
27 exit(O);
28 }
29 void yes_or_no(gint reply,gpointer data) {
30if(reply == GNOME_YES)
31g_print("The answer is YES\n");
32else
33g_print("The answer is NO\n");
34 }
Эта программа отображает главное окно с кнопкой, и здесь всплывает диалоговое окно с вопросом. Функция, вызванная в строке 20, создает диалог с главным окном приложения как с его родительским и отображает диалоговое окно как модальное. Так как диалоговое окно является родительским, главное окно и его родительские окна, если они существуют, никогда не смогут скрыть диалоговое. Это также означает, что когда главное окно перемещается с одного места на другое, диалоговое перемещается вместе с ним. В силу своей модальности диалоговое окно делает кнопку главного окна приложения невосприимчивой. Другими словами, ответ должен быть получен до того, как пользователь сможет выполнить что-нибудь еще. Модальность прилагается только к одному приложению и не оказывает воздействия на окна параллельно работающих приложений.
Для создания диалогового окна с вопросом можно вызвать две другие функции. В некоторых случаях вы захотите получить модальное окно, но не привязанное к родительскому. Чтобы это сделать, замените строки с 20 по 24 следующим образом:
dialog = gnome_question_dialog_modal(
"A simple question window", (GnomeReplyCallback)yes_or_no, NULL);
В результате остальные окна станут неактивными и вовсе не будут реагировать на мышь. Используйте этот прием с осторожностью, потому что диалоговое окно может исчезать из вида, пока окна приложения неактивны, что приводит часть пользователей в замешательство. Для создания вопрошающего диалогового окна, которое остается над своим родительским окном и не блокирует другие окна в приложении, измените строки с 20 по 24 таким образом:.
dialog = gnome_question_dialog_parented(
"A simple question window",
(GnomeReplyCallback)yesorno,
NULL,
GTK_WINDOW(app)) ;
Вы уверены?
Рисунок 3.7.Последний шанс для отменыРисунок 3.7.Последний шанс для отменыЭто наиболее общий вопрос, задаваемый пользователю программой и требующий один из двух ответов. Этот тип вопроса имеет собственное диалоговое окно с кнопками ОК и CANCEL (отмена), как показано на рис. 3.7.
Рисунок 3.7.
Последний шанс для отмены
Рисунок 3.7.
Последний шанс для отмены
Функция, предназначенная для этого, очень проста по сравнению с функцией вопроса предшествующего примера:
/** canmpdialog.с **/
#include <gnome.h>
3
4 void cancelorok(gint reply,gpointer data);
5
6 int main(int argc,char *argv[])
7 {
GtkWidget*app;
GtkWidget*dialog;
10GtkWidget*button;
11
12gnome__init (" canmpdialog ", " 1.0 ", argc, argv);
13 app = gnome_app_new("canmpdialog*,"Question Dialog");
14 button = gtk_button_new_with_label("Button");
15gtk_container_set_border_width(GTK_CONTAINER(app),30);
16gnome_app_set_contents(GNOMEAPP(app),button);
17gtk_widget_show(button);
18gtk_widget_show(app);
19
20dialog = gnome_ok_cancel_dialog_modal_parented(
21"Do you really wanttodothis?",
22(GnomeReplyCalIback)cancelorok,
23NULL,
24GTK_WINDOW(app));
25
26gtk_main();
27exit(0);
28 }
29 void cancel_or_ok(gint reply,gpointer data) {
30if(reply == GNOME_CANCEL)
31g_print("Action cancelled\n");
32else
33g_print("Action okayedXn");
34 }
Главное окно имеет кнопку, которая недоступна во время отображения диалогового окна, так как вызов функции из строки 20 создает диалоговое окно как модальное. К тому же главное окно не может спрятать диалоговое окно, ибо последнее создано как родительское. Однако есть другие функции, которые можно использовать для создания немодальных и/или неродительских диалоговых окон. Проще всего заменить строки с 20 по 24 одним из приведенных далее вариантов. Для создания диалогового окна, которое является родительским, но не модальным, используйте этот вариант:
dialog = gnome_ok_cancel_dialog_parented(
"Do you really want to do this?",
(GnomeReplyCallback)cancel_or_ok, NULL, GTK_WINDOW(app));
Для создания диалогового окна, которое является модальным, но не родительским, используйте следующее:
dialog = gnome_ok_cancel_dialog_modal( "Do you really want to do this?", (GnomeReplyCallback)cancelorok, NULL,
GTKWINDOW(app));
Для создания диалогового окна, которое не является ни родительским и ни модальным, используйте третий вариант:
dialog = gnome_ok_cancel_dialog(
"Do you really want to do this?", (GnomeReplyCallback)cancel_or_ok, NULL, GTK_WINDOW(app));
Ввод с клавиатуры
Существует диалоговое окно, которое можно использовать для ввода данных прямо с клавиатуры. Оно приглашает к вводу отдельной строки типа имени файла или URL Web-сайта.
ПРИМЕЧАНИЕ НАУЧНОГО РЕДАКТОРА
URL — Uniform Resource Locator — унифицированный локатор ресурсов, указатель на объект в сети Internet.
Ниже приведена программа, демонстрирующая строчный диалог:
/** stringdialog.с **/
#include <gnome.h>
3
void stringcallback(gchar *string,gpointer data);
5
int main(int argc,char *argv[])
{
GtkWidget*app;
GtkWidget*dialog;
10GtkWidget*button;
11
12gnome__ini t("stringdialog","1.0",argc,argv);
13 app = gnome_app_new("stringdialog","String Dialog");
14button = gtk_button_new_with_label("Button");
15gtk_container_set_border_width(GTK_CONTAINER(app),30);
16gnome_app_set_contents(GNOME_APP(app),button);
17gtk_widget_show(button);
18gtk_widget_show(app);
19
20dialog = gnome_request_string_dialog(
21"File name",
22(GnomeStringCallback)stringcallback,
23NULL);
24gtk_window_set_modal(GTK_WINDOW(dialog),TRUE);
25
26gtk_main();,
27exit(0);
28 }
29 void stringcallback(gchar *string,gpointer data)
30 {
31if(string == NULL)
32g_print("Called back with a NULL string\n");
33else if(strlen(string) == 0)
34g_print("Called back with a zero-length stringXn");
Приглашение пользователю для ввода данныхПриглашение пользователю для ввода данных35 else
Приглашение пользователю для ввода данных
Приглашение пользователю для ввода данных
36gjprint("GOT: %s\n",string);
37 }
Обращение к gnome_request_string_dialog() в строке 20 создает и отображает диалоговое окно, которое приведено на рис. 3.8. После создания к диалоговому окну приписывается функция обратного вызова stringcallback (), которая определена в строке 29. В табл. 3.1 описываются четыре возможных действия пользователя и результат каждого действия.
Таблица 3.1. Результаты ответов пользователя
Действие
Результат как обратный вызов
Введите строку (с именем файла) и выберите кнопку ОК
Оставьте строку пустой и выберите кнопку ОК
Оставьте строку пустой
и выберите кнопку CANCEL
Введите строку и выберите кнопку CANCEL
Введенная строка передается функции обратного вызова
Строка нулевой длины передается функции обратного вызова
Указатель строки NULL передается функции обратного вызова’
Указатель строки NULL передается функции обратного вызова
Не существует функции для создания модального строчного диалогового окна, но вы можете счесть более удобным иметь модальный строчный запрос. Диалоговое окно в этом образце программы модальное из-за вызова функции gtk window_set_modal() в строке 24. Имеется функция, которую вы можете использовать для создания родительского диалогового окна — просто поменяйте таким образом строки с 20 по 23:
dialog = gnome_request_string_dialog_parented( "File name", (GnomeStringCallback)stringcallback, NULL, GTK_WINDOW(app));
Рисунок 3.9.Диалоговое окно для ввода пароляРисунок 3.9.Диалоговое окно для ввода пароляСуществуют две другие функции, создающие диалоговые окна, которые принимают ввод из строки, но с одним отличием. Введенный текст не отображается на экране. Вместо каждого набираемого символа в строке отображается звездочка, как показано на рисунке 3.9. Вы можете скорректировать программу, приглашающую для ввода видимой строки, на приглашающую для ввода завуалированной строки, изменив строки с 20 по 23 следующим образом:
Рисунок 3.9.
Диалоговое окно для ввода пароля
Рисунок 3.9.
Диалоговое окно для ввода пароля
dialog = gnome_request_password_dialog( "Password",
(GnomeStringCallback)stringcallback, NULL);
А еще вы можете создать родительскую версию:
dialog = gnome_request_password_dialog_parented(
"Password",
(GnomeStringCallback)stringcallback,
NULL,
GTK__WINDOW (app));
В некоторых случаях требуется немного больше контроля за содержимым строки ввода диалогового окна. Можно уточнить максимальную длину строки или инициализировать входную строку, указав ее значение по умолчанию. Сделайте это при помощи функции из нижеследующего примера:
/** requestdialog.с *♦/
Iinclude <gnome.h>
3
void requestcallback(gchar *string,gpointer data);
5
int main(int argc,char *argv[J).
{
GtkWidget *app;
GtkWidget *dialog;
GtkWidget *button;
11
gnome_init("requestdialog", "1.0",argc,argv);
app = gnome_app_new("requestdialog","Request Dialog");
button = gtk_button_new_with_label("Button");
gtk_container_set_border_width(GTK_CONTAINER(app),30);
gnome_app_set_contents(GNOME_APP(app),button);
gtk_widget_show(button);
gtk_widget_show(app);
19
dialog = gnome_request_dialog(FALSE,
"File name",
"/var/tmp/workfile.dat",
2336,
2 4(GnomeStringCallback)requestcallback,
25NULL,
2 6GTKWINDOW(app));
27gtk_window_set_modal(GTK_WINDOW(dialog),TRUE);
28
29gtk_main();
30exit(0);
31 }
32 void requestcallback(gchar *string,gpointer data)
33 {
if(string == NULL)
g_print("Called back with a NULL stringXn");
else if(strlen(string) == 0)
g_print("Called back with a zero-length stringXn");
else
g_print("GOT: %s\n",string);
}
Обращение к функции gnome_request_dialog() в строке 20 создает диалоговое окно, которое показано на рис. 3.10.
Первый аргумент — или TRUE, или FALSE — нужен для указания, является ли входная строка завуалированной, как в случае с паролем. Если аргумент принимает значение TRUE, то как начальное значение, так и любые набранные пользователем символы ото-
Рисунок 3.10.Строка приглашения, установленная в значение по умолчаниюРисунок 3.10.Строка приглашения, установленная в значение по умолчаниюбражаются в виде строки звездочек. Второй аргумент — это приглашение, а третий — значение строки по умолчанию, которое было включено в текстовое поле, как только диалоговое окно впервые появилось. Если никакое начальное значение не требуется, то вы можете передать функции NULL, или строку нулевой длины.
Рисунок 3.10.
Строка приглашения, установленная в значение по умолчанию
Рисунок 3.10.
Строка приглашения, установленная в значение по умолчанию
Следующий параметр в строке 23 упомянутого примера— это максимальное количество символов, которые можно ввести в строку. Используйте 0 в качестве максимального значения, если не хотите ограничивать число символов. Количество символов может быть больше, чем вмещает строка ввода данных, так как окно может прокручиваться вперед и назад, чтобы вы ввели данные полностью.
Последние два аргумента похожи на приведенные в предыдущих примерах. Строка 25 — это указатель данных, переданный подпрограмме обратного вызова, а последний параметр — это окно, которое будет родительским по отношению к диалоговому. Если вы не хотите создавать родительское диалоговое окно, передайте указатель NULL в ка
честве родительского окна.
Данные для функции обратного вызова
Как показано в предыдущих примерах, существует обязательное соглашение по передаче указателя данных функции GNOME, который передается функции обратного вызова. Этот указатель данных полностью игнорируется GNOME и GTK+, а это означает, что вы можете передавать любой адрес. Возможность передавать этот указатель может быть очень полезной в программе, в которой вы создали несколько связанных решений в различных местах.
Например, когда программа реагирует на выбор в меню Save As (сохранить как) и появляется диалоговое окно, запрашивающее имя файла, функции обратного вызова обязательно потребуется доступ к текущему имени файла, как только пользователь произведет выбор. Это можно реализовать, если хранить всю информацию в глобальных переменных, но для управления и дизайна программы куда лучше передавать данные в качестве аргументов. А поскольку вы не вызываете напрямую из своей программы функцию обратного вызова, необходимо передать аргументы косвенно, как в этом примере:
/** datacallback.с **/
Iinclude <gnome.h>
3
typedef struct {
GtkWidget *app;
gchar defaultFilename[40];
gchar currentFilename[40];
} pgmContext;
9
gint eventDelete(GtkWidget *widgetr
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
void saveAsButton(GtkWidget *widget,pgmContext *pc);
void setTermination(GtkWidget *app);
void fileSaveCallback(gchar *filename,pgmContext *pc);
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
int main(int argc,char *argv[]) <
GtkWidget *button; pgmContext pc;
strcpy(pc.defaultFilename,"/var/dcall/sqlim.dat");
gnome_init("datacallback","1.0",argc,argv);
pc.app = gnome_app_new("datacallback","Data Passing"); setTermination(pc.app);
button = gtk_button_new_with_label(
"Save As");
gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(saveAsButton), &pc);
gnome_app_set_contents(GNOME_APP(pc.app),button);
gtk_container_set_border_width(
GTK_CONTAINER(pc.app),30);
gtk_widget_show(button);
gtk_widget_show(pc.app);
gtk_main();
exit(0);
}
void saveAsButton(GtkWidget *widget,pgmContext *pc) { GtkWidget *dialog;
dialog = gnome_request_dialog(FALSE, "File name", pc->defaultFilename, 40,
(GnomeStringCallback)fileSaveCallback, pc, GTK_WINDOW(pc->app));
gtk_window_set_modal(GTK_WINDOW(dialog),TRUE); }
void fileSaveCallback(gchar *filename,pgmContext *pc) { if((filename == NULL) || (strlen(filename) == 0)) return;
strcpy(pc->currentFilename,filename);
g_print("Save file as %s\n",pc->currentFilename); }
void setTermination(GtkWidget *app) { gtk_signalconnect(GTK_OBJECT(app), "delete_event", GTKSIGNALFUNC(eventDelete), NULL);
gtk_signal_connect(GTK_OBJECT(app), "destroy", GTK_SIGNAL_FUNC(eventDestroy), NULL);
}
gint eventDelete(GtkWidget *widget, GdkEvent *event,gpointer data) {
7575return(FALSE)return(FALSE)
75
75
return(FALSE)
return(FALSE)
Рисунок 3.11.Кнопка Save AsРисунок 3.11.Кнопка Save As76 >
Рисунок 3.11.
Кнопка Save As
Рисунок 3.11.
Кнопка Save As
77 gint eventDestroy(GtkWidget *widget,
78GdkEvent *event,gpointer data) {
79gtk_main_quit();
80return(O);
81 }
Эта программа отображает окно с единственной кнопкой для на-
жатия, как показано на рис. 3.11.
Передача данных функции обратного вызова происходит путем передачи единственного указателя. Если необходимо передать больше, чем один кусок данных, можно определить структуру данных, а затем передать указатель на структуру. В приведенном примере для этой цели в строке 4 была определена структура pgmContext, а в строке 21 создана структура этого типа. Строка 23 включает имя файла по умолчанию, а строка 26 хранит указатель класса GtkWidget на основное окно приложения. В строке 31 выполняется обращение к gtk_signal__connect (), чтобы указать функцию обратного вызова для кнопки, последний аргумент в обращении — указатель на адрес структуры. А это означает, что, когда бы ни была нажата кнопка, адрес из рс передается функции об
Приглашение со строкой, заданной по умолчаниюПриглашение со строкой, заданной по умолчаниюратного вызова.
Приглашение со строкой, заданной по умолчанию
Приглашение со строкой, заданной по умолчанию
Функция обратного вызова для кнопки определена в строке 44. Основная обязанность функции — создание диалогового окна, в которое пользователь может ввести имя файла. В строке 49 в диалоговое окно вставляется имя файла по умолчанию из структуры pgmContext. Результат этого приведен на рисунке 3.12. В строках 51 и 52 адреса функции обратного вызова и структуры pgmContext уже передаются в диалоговое окно, так что при вызове функции структура переходит к ней. Функция обратного вызова диалогового окна — это f ileSaveCallback(), как задано в строке 56.
Первый аргумент функции f ileSaveCallback() — это имя файла, введенное
пользователем, а второй — структура данных pgmContext. Код в строке 57 осуществляет проверку, нажал ли пользователь кнопку CANCEL или кнопку ОК с именем файла нулевой длиной. Если пользователь ввел имя файла (или оставил имя по умолчанию) и нажал кнопку ОК, то в строке 59 имя файла сохраняется в структуре.
Эта программа просто печатает имя файла, но из-за того, что оно сохранено в контекстной структуре, другое всплывающее окно может быть создано для проверки имени файла. В одном случае в процессе сохранения файла может появиться строка отражения динамики процесса. В другом случае, из-за того, что выбор пользователя хранится в контекстной структуре, эта структура может быть использована для создания другого потока, позволяющего выполнить сохранение файла в виде фонового процесса.
Строка отражения динамики процесса
Речь пойдет о диалоговом окне GNOME, которое отображает постоянно движущуюся строку отражения динамики процесса (progress bar). Приложение создает полосу и затем предусматривает ее регулярное увеличение в соответствии с постоянно обновляемым значением процента выполнения. Вот пример, демонстрирующий строку состояния, которая постоянно обновляется через определенный промежуток времени:
/** progress.с **/
#include <gnome.h>
3
gdouble percentcallback(gdouble *pct);
void cancelcallback(gdouble *pct); .
void stringcallback(gchar ♦string,gpointer data);
7
int main(int argc,char *argv[J)
{
GtkWidget *app;
gdouble pct = 0.0;
12GnomeAppProgressKey *key;
13
14gnome_init("progress*,"1.0",argc,argv);
15app = gnome_app_new("progress","Progress Dialog");
16
17 key = gnome_app_progress_timeout(GNOME_APP(app),
18"Label for Progress Bar",
19250,
20(GnomeAppProgressFunc)percentcallback,
21(GnomeAppProgressCancelFunc)cancelcallback,
22&pct);
23
24gtk_main();
25exit(0);
26 }
27 gdouble percentcallback(gdouble *pct) {
28if((*pct += 0.01) >= 1.0)
*pct = 1.0;
return(*pct);
}
void cancelcallback(gdouble *pct) {
gtk_main_quit();
}
Имеется два вида таких строк: управляемые вручную из вашей программы и работающие в автоматическом режиме. В приведенном примере управление происходит автоматически при помощи функции gnome_app_progress_timeout() из строки 17. Третий аргумент — количество миллисекунд, определяющее период нахождения программы в состоянии ожидания между вызовами percentcallback(). Функция обратного вызова percentcallback(), заданная в строке 27, необходима для возвращения постоянно обновляемого значения. Это значение находится в пределах от 0.0 до 1.0 (от 0% до 100%).
Label for Progress BarLabel for Progress BarX Cancel |X Cancel |Рисунок 3.13.Движущаяся строка состоянияРисунок 3.13.Движущаяся строка состоянияВ этом примере выводится строка отражения динамики процесса, изображенная на рис. 3.13. Функция percentcallback() из строки 27 вызывается каждые 250 миллисекунд, и каждый раз, когда это происходит, процентное значение возрастает на 0.01 (численный эквивалент 1%).
Label for Progress Bar
Label for Progress Bar
X Cancel |
X Cancel |
Рисунок 3.13.
Движущаяся строка состояния
Рисунок 3.13.
Движущаяся строка состояния
Вовсе не обязательно производить изменение каждый раз, как в этом примере. Значение может оставаться тем же для нескольких обратных вызовов. Можно даже получить отображение динамики, идущей в обратном направлении. Например, можно получить обратное движение полосы, если в строке 11 установить начальное значение pct равным 1.0 и изменить код в строках 28 и 29 таким образом:
if((*pct -= 0.01) >= 1.0)
*pct = 1.0;
Заметьте, что в этом примере окно верхнего уровня никогда не появляется, хотя и создано, потому что строка отражения динамики процесса должна обязательно иметь родительское окно. Так как отсутствует обращение к функции gtk_widget_show(), окно верхнего уровня никогда не появляется.
Создание всплывающих и диалоговых окон
Как показано в таб. 3.2, существуют три вида окон, которые можно создать, вызывая gtk_window_new(). В программах, описанных ранее в этой главе, основное окно создавалось при помощи gnome_app_new( ), которая обращалась к функции gtk_window_new(), используя в качестве аргумента GTK_WINDOW_TOPLEVEL.
Таблица 3.2. Известные в GTK+ типы окон
Тип
Описание
GTK_WINKkW_TkPLEVEL
Обычно используется как единственное главное окно приложения, но в сложных приложениях может быть больше одного окна.
GTK_WINKkW_KIALkG
Временное окно с одним или несколькими виджетами. Оно имеет строку заголовка и кнопки системного меню, как и окно
верхнего уровня.
GTK_WINKkW_PkPUP
Временное окно с одним или несколькими виджетами. Оно не имеет строки заголовка и кнопок системного меню.
Всплывающее, окно управляется менеджером окон. Чтобы использовать одно или несколько всплывающих или диалоговых окон, приложение обязательно должно иметь окно верхнего уровня. В следующем примере отсутствует окно верхнего уровня, но в нем можно использовать всплывающее окно с кнопкой для закрытия приложения:
/** hellopopup.c *♦/
#include <gnome.h>
3
void buttonshutdown(GtkWidget *widget,gpointer data);
5
int main(int argc,char *argv[])
{
GtkWidget *popup;
GtkWidget *button;
10
11gnome_init("hellopopup","1.0",argc,argv);
12
popup = gtk_window_new(GTK_WINDOW_POPUP);
button = gtk_button_new_with_label("Close");
gtk_container_set_border_width(
GTK_CONTAINER(popup), 2 0);
gtk_container_add(GTK_CONTAINER(popup),button);
gtksignalconnect(GTK_OBJECT(button),
"clicked",
2 0GTK_SIGNALFUNC(buttonshutdown),
21NULL);
gtk_widget_show(button);
gtk_widget_show(popup);
24
gtk_main();
exit(O);
}
void buttonshutdown(GtkWidget *widget,gpointer data)
{
exit(0);
}
В строке 13 создается виджет всплывающего окна, а в строке 14 для него создается кнопка для нажатия. Обращение к gtk_container_add () в строке 17 добавляет кнопку к виджету всплывающего окна, а в строке 18 кнопке для нажатия назначается метод обратного вызова. Строки 22 и 23 позволяют отобразить всплывающее окно и кнопку, как показано на рис. 3.14. Функция обратного вызова, начинающаяся в строке 28, просто завершает программу при обращении к exit () из строки 30.
Внеся лишь одно изменение, можно создать диалоговое окно. Единственное разлив чие между всплывающим и диалоговым окнами — это отсутствие или наличие средств управления менеджера окон. Чтобы получить возможность работать с менеджером окон, добавьте строку заголовка и другие элементы управления окном, как показано на рис. 3.15, измените строку 13 следующим образом:
popup = gtk_window_new(GTK_WINDOW_DIALOG);
Close]Close]SjwigJk
Close]
Close]
Close]
Рисунок 3.14.Всплывающее окно без рамки менеджера оконРисунок 3.14.Всплывающее окно без рамки менеджера оконРисунок 3.15.Диалоговое окно с рамкой .менеджера оконРисунок 3.15.Диалоговое окно с рамкой .менеджера окон
Рисунок 3.14.
Всплывающее окно без рамки менеджера окон
Рисунок 3.14.
Всплывающее окно без рамки менеджера окон
Рисунок 3.15.
Диалоговое окно с рамкой .менеджера окон
Рисунок 3.15.
Диалоговое окно с рамкой .менеджера окон
Разрушение окна после его закрытияЭтот пример программы демонстрирует несколько новых вещей. Во-первых, главное окно имеет больше одной кнопки (см. рис. 3.16); во-вторых, программа знакомит с функцией обратного вызова, которая используется для быстрого закрытия окна. Верхняя кнопка главного окна вызывает появление всплывающего окна, как на рис. 3.17, а нижняя кнопка — появление диалогового окна, как на рис. 3.18. Эта профамма высвечивает на экране диалоговое окно и, когда оно закрывается, разрушает его таким образом, что занимаемая им память возвращается системе:Разрушение окна после его закрытияЭтот пример программы демонстрирует несколько новых вещей. Во-первых, главное окно имеет больше одной кнопки (см. рис. 3.16); во-вторых, программа знакомит с функцией обратного вызова, которая используется для быстрого закрытия окна. Верхняя кнопка главного окна вызывает появление всплывающего окна, как на рис. 3.17, а нижняя кнопка — появление диалогового окна, как на рис. 3.18. Эта профамма высвечивает на экране диалоговое окно и, когда оно закрывается, разрушает его таким образом, что занимаемая им память возвращается системе:/** popup_dialog.с **/linclude <gnome.h>3void destroyPopup(GtkWidget *widget,gpointer data);void destroyDialog(GtkWidget *widget,gpointer data);void showPopup(GtkWidget *widgetrgpointer data);void showDialog(GtkWidget *widget,gpointer data);gint eventDestroy(GtkWidget *widgetrGdkEvent *eventrgpointer data);/** popup_dialog.с **/linclude <gnome.h>3void destroyPopup(GtkWidget *widget,gpointer data);void destroyDialog(GtkWidget *widget,gpointer data);void showPopup(GtkWidget *widgetrgpointer data);void showDialog(GtkWidget *widget,gpointer data);gint eventDestroy(GtkWidget *widgetrGdkEvent *eventrgpointer data);Popup] Dialog]Popup] Dialog]Рисунок 3.16.Основное окно с двумя кнопкамиРисунок 3.16.Основное окно с двумя кнопкамиClose Popup]Рисунок 3.17.Всплывающее окно с кнопкой CloseClose Popup]Рисунок 3.17.Всплывающее окно с кнопкой Close
Разрушение окна после его закрытия
Этот пример программы демонстрирует несколько новых вещей. Во-первых, главное окно имеет больше одной кнопки (см. рис. 3.16); во-вторых, программа знакомит с функцией обратного вызова, которая используется для быстрого закрытия окна. Верхняя кнопка главного окна вызывает появление всплывающего окна, как на рис. 3.17, а нижняя кнопка — появление диалогового окна, как на рис. 3.18. Эта профамма высвечивает на экране диалоговое окно и, когда оно закрывается, разрушает его таким образом, что занимаемая им память возвращается системе:
Разрушение окна после его закрытия
Этот пример программы демонстрирует несколько новых вещей. Во-первых, главное окно имеет больше одной кнопки (см. рис. 3.16); во-вторых, программа знакомит с функцией обратного вызова, которая используется для быстрого закрытия окна. Верхняя кнопка главного окна вызывает появление всплывающего окна, как на рис. 3.17, а нижняя кнопка — появление диалогового окна, как на рис. 3.18. Эта профамма высвечивает на экране диалоговое окно и, когда оно закрывается, разрушает его таким образом, что занимаемая им память возвращается системе:
/** popup_dialog.с **/
linclude <gnome.h>
3
void destroyPopup(GtkWidget *widget,gpointer data);
void destroyDialog(GtkWidget *widget,gpointer data);
void showPopup(GtkWidget *widgetrgpointer data);
void showDialog(GtkWidget *widget,gpointer data);
gint eventDestroy(GtkWidget *widgetr
GdkEvent *eventrgpointer data);
/** popup_dialog.с **/
linclude <gnome.h>
3
void destroyPopup(GtkWidget *widget,gpointer data);
void destroyDialog(GtkWidget *widget,gpointer data);
void showPopup(GtkWidget *widgetrgpointer data);
void showDialog(GtkWidget *widget,gpointer data);
gint eventDestroy(GtkWidget *widgetr
GdkEvent *eventrgpointer data);
Popup] Dialog]
Popup] Dialog]
Рисунок 3.16.
Основное окно с двумя кнопками
Рисунок 3.16.
Основное окно с двумя кнопками
Close Popup]
Рисунок 3.17.
Всплывающее окно с кнопкой Close
Close Popup]
Рисунок 3.17.
Всплывающее окно с кнопкой Close
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
юю
ю
ю
int main(int argc,char *argv[]) {
GtkWidget *topLevelWindow;
GtkWidget *popupButton;
GtkWidget *dialogButton;
GtkWidget *box;
gnomeinit("popup_dialog","1.0",argc,argv);
topLevelwindow = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk signal_connect(GTK_OBJECT(topLevelwindow), "destroy", GTK_SIGNAL_FUNC(eventDestroy), NULL);
gtk_container_set_border_width( GTK_CONTAINER(topLevelwindow), 20);
box = gtk_vbox_new(FALSE,0);
popupButton = gtk_button_new_with_label("Popup");
gtk_signal_connect(GTK_OBJECT(popupButton), "clicked", GTK_SIGNAL_FUNC(showPopup), NULL);
gtk_box_pack_start(GTK_BOX(box),popupButton, 'FALSE,FALSE,0);
gtk_widget_show(popupButton);
dialogButton = gtk_button_new_with_label("Dialog");
gtk_signal_connect(GTK_OBJECT(dialogButton), "clicked", GTKSIGNALFUNC(showDialog), NULL);
gtkboxpackstart(GTK BOX(box),dialogButton, FALSE,FALSE,0);
gtkwidget show(dialogButton);
gtk_container_add(GTK_CONTAINER(topLevelwindow),box); gtk_widget_show(box);
gtk_widget_show(topLevelwindow);
gtk main();
exit(0);
}
gint eventDestroy(GtkWidget *widget, GdkEvent *event,gpointer data) { gtk_main_quit();
return(0);
}
void showPopup(GtkWidget *widget,gpointer data) { GtkWidget *popup;
' GtkWidget *button;
626364656667626364656667popup = gtk_window_new(GTK_WINDOW_POPUP);
62
63
64
65
66
67
62
63
64
65
66
67
button = gtk_button_new_with_label("Close Popup"); gtk_container_set_border_width(
GTK_CONTAINER(popup),2 0);
gtk_container_add(GTK_CONTAINER(popup),button);
gtks ignal_connect(GTKOBJECT(button),
68"clicked",
69GTK_SIGNAL_FUNC(destroyPopup),
70popup);
gtk_widget_show(button);
gtk_widget_show(popup);
}
void showDialog(GtkWidget *widget,gpointer data) {
GtkWidget *dialog;
GtkWidget *button;
77
78dialog = gtk_window_new(GTK_WINDOW_DIALOG);
79button = gtk_button_new_with_label("CloseDialog");
80gtk_container_set_border_width(
81GTK_CONTAINER(dialog),20);
82gtk_container_add(GTK_CONTAINER(dialog),button);
83gtk_signal__connect(GTK_OBJECT(button),
84"clicked",
85GTK_SIGNAL_FUNC(destroyDialog),
86dialog);
87gtk_widget_show(button);
88gtk_widget_show(dialog);
89 }
90
91 void destroyPopup(GtkWidget *widget,gpointer data)
92 {.
93 gtk_widget_destroy(GTK_WIDGET(data));
94 }
95 void destroyDialog(GtkWidget *widget,gpointer data)
96 {
97 gtk_widget_destroy(GTK_WIDGET(data));
98 }
Close Diaiog|Рисунок 3.18.Диалоговое окно с кнопкой CloseClose Diaiog|Рисунок 3.18.Диалоговое окно с кнопкой CloseСтроки c 18 no 25 инициализируют GNOME, устанавливают функцию обратного вызова для разрушения, создают окно верхнего уровня и определяют границу вокруг окна шириной 20 пикселов.
Close Diaiog|
Рисунок 3.18.
Диалоговое окно с кнопкой Close
Close Diaiog|
Рисунок 3.18.
Диалоговое окно с кнопкой Close
В строке 26 создается специальный вид виджета, называемый контейнером (container). Виджет-контейнер может организовать и отображать несколько виджетов одновременно. Это необходимо, так как главное окно должно отображать более одного виджета. Вместо непосредственного включения кнопок прямо в главное окно, они помещаются в строках 33 и 42 в ящик. В свою очередь, ящик вставляется в главное окно в строке 47. Имеется два основных вида ящиков (горизонтальные и вертикальные), и существуют различные способы упаковки виджетов в каждый из них, что более детально обсуждается в главе 4. В этом примере обращение к функции gtk_vbox_new() в строке 26 создает ящик для вертикальной организации кнопок, а обращение к gtk_box_pack_start () в строках 33 и 42 помещает кнопки, начиная сверху, в вертикальный ящик. Ящик сам изменяет размеры, чтобы приспособиться и удобнее расположиться вокруг кнопок, а основное окно добавляет рамку вокруг окна шириной в 20 пикселов.
Каждая из функций обратного вызова главного окна, стартующих в строках 58 и 74, создает временное окно. Функция showDialog () создает и выводит диалоговое окно, показанное на рисунке 3.18, а функция showPopup() создает и выводит всплывающее окно, показанное на рисунке 3.17. Эти две функции почти полностью идентичны за исключением типа окон, указанных в строках 62 и 78.
И всплывающее, и диалоговое окна имеют функции обратного вызова, которые их же и удаляют. Обращение к gtk_signal_connect ( ) в строке 83 определяет destroyDialog() как функцию обратного вызова для диалогового окна. Последний аргумент, переданный функции в строке 86, — это указатель диалогового окна. В строке 95 упомянутый указатель передается функции обратного вызова как указатель data. Обращение к gtk_widget_destroy () в строке 97 вызывает исчезновение диалогового окна и возвращение любой ранее выделенной памяти в систему.
Эта программа работает, но имеет несколько причуд, которые, возможно, надо изменить, что зависит от вашего приложения. Действительно, вы получаете новое диалоговое или всплывающее окно каждый раз, когда нажимаете (щелчок указателем на кнопке) одну из кнопок в главном окне — и вы можете получить любое их количество. Каждое из этих окон имеет одну и ту же функцию обратного вызова; окна могут закрываться индивидуально в любом порядке, что иногда может пригодиться. Однако в большинстве программ диалоговое окно должно возникать лишь единожды.
Один из путей предотвращения многократного появления диалогового окна — это сделать его модальным. Диалоговое окно в этом примере может быть сделано модальным, если добавить где-то между строками 78 и 87 такую строку:
gtk_window_set_modal(GTK_WINDOW(dialog),TRUE);
Таким же образом всплывающее окно может быть сделано модальным в результате вставки между строками 62 и 71 подобной строки:
gtk_window_set_modal(GTK_WINDOW(popup),TRUE);
Функция gtk_window__set_modal () используется, чтобы сделать из любого немодального окна модальное, задавая TRUE в качестве второго аргумента. И наоборот, эту функцию можно использовать, чтобы сделать из любого модального окна немодальное, задавая FALSE в качестве второго аргумента.
Как прятать окна
В предыдущем примере новое диалоговое окно создавалось всякий раз, когда отображалось; если окно закрывалось, то оно разрушалось. Это обоснованный и особенно полезный подход, если диалоговое окно при каждом очередном выводе несколько отличается от предшествующего состояния. Однако, если требуется многократно использовать диалоговое окно, вы наверняка захотите создать его один раз, а затем раскрывать и закрывать, когда оно понадобится. В этом примере диалоговое окно прячется и возникает вновь:
/** hiding.с *♦/
#include <gnome.h>
3
void closeDialog(GtkWidget *widget,gpointer data);
void showDialog(GtkWidget *widgetfgpointer data);
gint eventShutdown(GtkWidget *widgetfgpointer data);
7
typedef struct {
GtkWidget *dialog;
} hidingcontext;
11
int main(int argc,char *argv[J)
1314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162-63646566676869701314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162-6364656667686970
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62-
63
64
65
66
67
68
69
70
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62-
63
64
65
66
67
68
69
70
GtkWidget *topLevelWindow;
GtkWidget *dialogButton; hidingcontext context;
context.dialog = NULL;
gnome_init("hiding","1.0",argc,argv);
topLevelwindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_s ignal_connect(GTK_OBJECT(topLevelWindow), "destroy", GTK_SIGNAL_FUNC(eventshutdown), &context);
gtk_container_set_border_width( GTK_CONTAINER(topLevelWindow),20);
dialogButton = gtk_button_new_with_label("Dialog");
gtk_signal_connect(GTK_OBJECT(dialogButton), "clicked", GTK_SIGNAL_FUNC(showDialog), scontext);
gtk_container_add(GTK CONTAINER(topLevelWindow), dialogButton);
gtk_widget_show(dialogButton);
gtk_widget_show(topLevelWindow);
gtk_main();
exit(0);
}
gint eventshutdown(GtkWidget *widget,gpointer data) { hidingcontext *context;
context = (hidingcontext *)data;
if(context->dialog != NULL)
gtkwidget destroy(GTK_WIDGET(context->dialog));
gtk_main_quit();
return(0);
}
void showDialog(GtkWidget *widget,gpointer data) { GtkWidget *button;
hidingcontext *context;
context = (hidingcontext *)data;
if(context->dialog ” NULL) { context->dialog =
gtk_window_new(GTK_WINDOW_DIALOG);
button = gtk_button_new_with_label("Close Dialog"); gtk_container_set_border_width(
GTK_CONTAINER(context->dialog),20);
gtkcontainer add(GTK_CONTAINER(context~>dialog), button);
gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(closeDialog), context->dialog);
gtk_window_set_modal(GTK_WINDOW(context->dialog),
71TRUE);
72gtk_widget_show(button);
73}
74gtk_widget_show(context->dialog);
75 }
76
77 void closeDialog(GtkWidget *widgetfgpointer data)
78 {
79 gtk_widget hide(GTK_WIDGET(data));
80 }
Окно верхнего уровня содержит кнопку, определенную в строках с 29 до 33. Функция обратного вызова для кнопки под названием showDialog() описана в строке 52. Функции обратного вызова передается структура hidingContext, которая определена в строке 8. В большем приложении структура может быть расширена для поддержки куда большей информации; но в этом примере она содержит только указатель на виджет диалогового окна. При первом же обращении к hidingContext () в строке 58 определяется, что диалоговое окно отсутствует, поэтому далее создается виджет диалогового окна, адрес которого сохраняется в структуре. После того как диалоговое окно создано, оно продолжает существовать и последующие обращения к hidingContext () просто позволяют удостовериться, что окно по-прежнему отображается при помощи функции gtk_widget_show() из строки 74.
Описанная в строке 61 кнопка диалогового окна использует функцию обратного вызова closeDialog(), определенную в строке 77. Аргумент data переходит к функции обратного вызова как указатель диалогового окна. В функции обратного вызова выполняется обращение к gtk_widget_hide(), что вызывает исчезновение диалогового окна вместе со всем его содержимым.
В строке 70 диалоговое окно становится модальным. В рассматриваемом маленьком примере с одним диалоговым окном это действительно не имеет значения, так как единственное, что выводит диалоговое окно, — кнопку главного окна, а поэтому существует всего одна копия диалогового окна. Это непохоже на происходившее в предыдущих примерах, где новое диалоговое окно создавалось каждый раз, а могло и многократно. Хотя многократные обращения к gtk_widget_show() не дают должного эффекта, диалоговое окно продолжает отображаться и работает нормально.
Функция обратного вызова eventshutdown () закрывает приложение, и возникает специфическая ситуация, так как диалоговое окно продолжает оставаться на экране дисплея. Если диалоговое окно отображается на экране в тот момент, когда приложение завершается, но специально не указано разрушить окно, то оно по-прежнему отображается на экране дисплея. А это быстро надоедает. Например, если после того как было прервано приложение, пользователь производит выбор в диалоговом окне (нажав кнопку), но там уже нет программы, принимающей обращение к функции обратного вызова, следовательно, возникает ошибка. Диалоговое окно продолжает оставаться на экране дисплея, потому что ему не было сказано, что делать в противном случае. Чтобы это предотвратить, функция eventshutdown () в строках 47 и 48 производит проверку, существует ли на экране диалоговое окно или нет, и если находит его, обращается к gtk_widget_destroy().
Ввод и вывод данных
С точки зрения программы, диалоговые и всплывающие окна существуют только для того, чтобы выводить для пользователя данные, получать их от него или для того и другого. В окне могут существовать виджеты, которые разрешают пользователю вводить данные. Программа должна позволять вводить данные в виджеты, чтобы позже извлечь информацию, введенную пользователем.
Следующая простая программа устанавливает диалоговое окно и принимает входную информацию пользователя: -
/** dataoutin.c **/
linclude <gnome.h>
3
void closeDialog(GtkWidget *widget,gpointer data);
void showDialog(GtkWidget *widget,gpointer data);
gint eventshutdown(GtkWidget *widget,gpointer data);
7
typedef struct {
GtkWidget *dialog;
GtkEntry *nameEntry;
} dataoutinContext;
12
int main(int argc,char *argv[])
{‘
GtkWidget *topLevelWindow;
GtkWidget *dialogButton;
dataoutinContext context;
18
context.dialog = NULL;
context.nameEntry = NULL;
21
22gnome_init("dataoutin", "1.0",argc,argv);
topLevelwindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_signal_connect(GTK_OBJECT(topLevelwindow),
"destroy",
GTK_SIGNAL_FUNC(eventshutdown),
^context);
gtk_container_set_border_width(
GTK_CONTAINER(topLevelwindow),20);
30
dialogButton = gtk_button_new_with_label("Dialog");
gtk_signal_connect(GTK_OBJECT(dialogButton),
"clicked",
GTK_SIGNAL_FUNC(showDialog),
.^context);
gtk_container_add(GTK_CONTAINER(topLevelwindow),
dialogButton);
.
gtk_widget_show(dialogButton);
gtk_widget_show(topLevelWindow);
41
gtk_main();
exit(0);
}
gint eventShutdown(GtkWidget *widget,gpointer data) {
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
dataoutinContext *context;
context = (dataoutinContext *)data;
if(context->dialog != NULL)
gtk_widget_destroy(GTK_WIDGET(context->dialog));
gtk_main_quit();
return(0);
}
void showDialog(GtkWidget *widget,gpointer data) { GtkWidget *box;
GtkWidget *okButton;
dataoutinContext *context;
context = (dataoutinContext *)data;
if(context->dialog == NULL) {
context->dialog = gtk_window_new(GTK_WINDOW_DIALOG);
gtk_container_set_border_width( GTK_CONTAINER(context~>dialog),2 0);
box = gtk_vbox_new(FALSE, 0);
gtk_container_add( GTK_CONTAINER(context->dialog),box);
gtk_widget_show(GTK_WIDGET(box));
context->nameEntry - (GtkEntry *)gtk_entry_new(); gtk_entry_set_text(context->nameEntry, "Initial String");
gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(context->nameEntry), FALSE,FALSE,0);
gtk_widget_show(GTK_WIDGET(context->nameEntry));
okButton = gtk_button_new_with_label("OK"); gtk_signal_connect(GTK_OBJECT(okButton), "clicked", GTK_SIGNAL_FUNC(closeDialog), context);
gtk_box_pack_start(GTKBOX(box), okButton,FALSE,FALSE, 0) ;
gtk_widget_show(okButton);
gtk_window_set_modal( GTK_WINDOW(context->dialog),TRUE);
}
gtk_widget_show(context->dialog);
}
void closeDialog(GtkWidget *widget,gpointer data) { dataoutinContext *context;
gchar *gotName;
context = (dataoutinContext *)data;
101102103101102103gotName = gtk_entry_get_text(context->nameEntry); g_print("GOT: %s\n",gotName);
101
102
103
101
102
103
104 gtk_widget_hide(GTK_WIDGET(context->dialog));
105 }
Окно верхнего уровня, показанное на рис. 3.19, имеет одну кнопку, которая вызывает окно диалога, как показано на рис. 3.20. Диалоговое окно содержит два виджета: окно для ввода текста и кнопку ОК. Когда нажимается кнопка ОК, диалоговое окно исчезает и программа демонстрирует в командной строке введенную строку текста. Структура этой программы неполная — она нужна только для демонстрации основного метода ввода- вывода данных с экрана.
Рисунок 3.19. Рисунок 3.20.
Главное окно, содержащее кнопку Окно диалога, принимающее ввод для показа диалогового окна с клавиатуры
Структура, определенная в строке 8, — это данные, передаваемые обратным вызовам. Она содержит указатель на виджет диалогового окна и указатель на текстовый виджет, находящийся внутри диалогового окна. С этими указателями в структуре можно управлять показом диалога и извлекать данные из виджета ввода текста.
Контекстная структура инициализируется в строках 19 и 20. В строке 35 ее адрес используется как указатель данных, передаваемый функции обратного вызова showDialog(), назначенной для кнопки. Функция showDialog(), которая запускается в строке 54, создает новое диалоговое окно, если в контекстной структуре пока отсутствует другое. Когда в строках 72 и 73 создается виджет для ввода текста, начальное значение в его окне устанавливается в виде строки ’’Initial String”. Кнопка ОК (для нажатия) создается в строках с 79 по 86, и ей назначается функция обратного вызова. В строке 83 адрес контекстной структуры используется в качестве указателя данных для функции обратного вызова. Для виджета, принимающего текст, не задана функция обратного вызова, так как он лишь принимает и сохраняет вводимые пользователем данные и не начнет обработку текста до тех пор, пока не будет нажата кнопка ОК.
В строке 94 запускается функция обратного вызова для кнопки ОК. Контекстный указатель переходит к ней, поэтому она имеет адреса виджета для ввода текста и диалогового окна. В строке 101 принимается строка символов от виджета, вводящего текст. Функция gtk_entry_get_text () возвращает указатель на строку. Если вам нужно сохранить строку, ваша программа должна сделать ее копию перед тем, как начать использовать. В этом примере строка просто печатается, а затем игнорируется. Память для строки выделяется внутри виджета, а затем снова освобождается виджетом.
Виджет, управляющий вводом данных, хранит местоположение текущей строки и отображает свою внутреннюю строку, когда бы ни появилось диалоговое окно. Если пользователь редактирует строку, изменяется и внутренняя строка. Таким образом, изменения эффективны даже после закрытия и нового открытия окна. Это может быть именно то, что вы хотите, а может, и нет. Более подробно об управлении данными будет рассказано в главе 4.
Выводы
Диалоговые и всплывающие окна такие же, как и любые другие окна. Возникнув на экране, они имеют собственную жизнь, тесно связанную с основной программой при помощи одной или нескольких функций обратного вызова. Например, в этой главе вы выучили, что:
? Есть множество встроенных диалоговых окон, которые разработаны для стандартных операций вывода сообщений или для задания вопроса пользователю, на который требуется ответ "Yes " (Да) или "No" (Нет).
^ Диалоговое окно может перехватывать сигналы от мыши, запрещая делать это остальным частям приложения.
V' Существует два основных вида временных окон. Диалоговые окна появляются с полной рамкой вокруг себя, даже если она есть у главного окна приложения. Всплывающие окна появляются без рамки и управляющих элементов менеджера окон.
? Виджетам могут быть назначены функции обратного вызова, и, когда происходит определенное событие, вызывается такая функция. Первый параметр обращения — это всегда сам виджет. Последний параметр — это адрес, указываемый вашей программой для передачи функции обратного вызова. Между этими двумя могут быть, а могут и не быть другие параметры.
Когда диалоговое окно исчезает, оно может быть разрушено или сохранено для последующего вывода.
£ * Диалоговое окно — виджет, который содержит другой виджет. Этот виджет может отображаться вместе с диалоговым окном. Виджет, содержащийся в диалоговом или всплывающем окне, может быть специальным контейнером виджетов. Контейнер может организовать и отобразить несколько других виджетов.
В следующей главе вы научитесь располагать виджеты в окнах с использованием ящиков и таблиц.
главаРасположение виджетов
Дв окне
В этой главе
: Упаковка виджетов в горизонтальный и вертикальный ящики
- Варьирование установками конфигурации ящика для изменения организации виджетов
^ Упаковка виджетов в горизонтальную и вертикальную таблицы
Варьирование установками конфигурации и командами упаковки для изменения организации виджетов в таблице
; Совместное использование таблиц и ящиков
Это первая из двух глав, в которой речь пойдет о размещении виджетов в окне. В этой главе будет рассматриваться размещение виджетов с помощью ящиков и таблиц. Процесс размещения виджетов в таблице или ящике называется упаковкой ^packingY Используя ящик и таблицу, можно быстро создавать сложные окна. Все, что требуется, — это создать ящик или таблицу и затем разместить в ней другие виджеты. Ящик также является виджетом и может быть помещен в другие ящики. То же относится и к таблице. По сути, вы можете паковать таблицы в ящики и ящики в таблицы.
Упаковка ящиков
Существует два вида ящиков. Виджеты могут отображаться друг над другом в вертикальном ящике (vertical box) или бок о бок в горизонтальном (horizontal box). Правильнее было бы говорить о ящике с виджетами как о списке виджетов, так как виджеты могут располагаться или бок о бок, или один над другим. Благодаря гнездованию ящиков этот процесс является очень гибким и легким в управлении.
Ящик — виджет, предназначенный содержать другие виджеты, а это означает, что ящик может содержать другие ящики. Так, например, если горизонтальный ящик содержит пару вертикальных ящиков, а каждый вертикальный ящик содержит четыре виджета, то виджеты отображаются в два столбца и четыре строки. Кроме того, так как любой виджет, содержащийся в ящике, может, в свою очередь, быть другим ящиком, содержащим виджеты, то можно создавать окна, по-разному наполняя их виджетами.
Изменение размеров происходит автоматически, благодаря обмену информацией между ящиком и содержащимся в нем виджетом, с помощью этой информации определяется, что виджет может делать и чего не может. Каждый виджет имеет свои внутренние
минимальные высоту и ширину, которые должны быть учтены ящиком при вычислении его положения и размеров. Бывают случаи, когда ящик требует, чтобы виджет увеличил свою высоту или ширину до величины большей, чем требует виджет.
Вертикальный ящик
Start 1, 'Start 2 buttonEnd 2 buttonEnd 1Start 1, 'Start 2 buttonEnd 2 buttonEnd 1Речь идет о виджете, содержащем несколько виджетов и отображающем их вертикально, как показано на рис. 4.1.
Start 1, '
Start 2 button
End 2 button
End 1
Start 1, '
Start 2 button
End 2 button
End 1
Ниже приведен пример программы, которая создает ящик (box) с четырьмя кнопками, показанный на рис. 4.1.
/** vertbox.c **/
linclude <gnome.h> 3
GtkWidget *makeBox();Рисунок 4.1.
gint eventDelete( GtkWidget *widget,Четыре кнопки
GdkEvent ‘event,gpointer data);в вертикальном
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);ящике
9
int main(int argc,char *argv[]) И { 12GtkWidget ♦window;
GtkWidget *box;
14
gnome__init ("vertbox","1.0", argc, argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_container_set_border_width(
GTK_CONTAINER(window), 25);
gtk_signal_connect(GTK_OBJECT(window),
*delete_event",
GTKSIGNALFUNC(eventDelete),
NULL);
gtk_signal_connect(GTKOBJECT(window),
"destroy",
GTK^SIGNALFUNC(eventDestroy),
NULL);'
27
box = makeBox();
gtkcontaineradd(GTK_CONTAINER(window),box);
gtk_widget_show(window);
gtk_main();
exit(0);
}
GtkWidget *makeBox() {
GtkWidget *box;
GtkWidget *button;
37
box » gtk_vbox_new(FALSE,0);
gtk_widget_show(box);
40
button = gtk_button_new_with_label("Start1");
gtkboxpackstart(GTKBOX(box),button,FALSE,FALSE, 0);
gtk_widget_show(button);
44
button = gtk_button_new_with_JLabel("End 1");
6gtk_box_pack_end(GTKBOX(box),button,FALSE,FALSE, 0);
gtk_widget_show(button);
48
49 button = gtk_button_new_with_label("Start 2 button");
50 gtk_box_pack_start(GTK_BOX(box),button,FALSE,FALSE,0);
51gtk_widget_show(button);
52
53button = gtk_button_new_with_label("End 2 button");
54gtk_box_pack_end(GTK_BOX(box),button,FALSE,FALSE,0);
55gtk_widget_show(button);
56
57return(box);
58 }
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data) {
return(FALSE);
}
gint eventDestroy(GtkWidget *widget^
GdkEvent *event,gpointer data) {
gtk_main_quit();
return(O);
}
В основной части программы в строке 16 создается окно верхнего уровня, а в строках 17 и 18 его кромки окружает рамка шириной 25 пикселов. После закрытия программы инициализируются функции обратного вызова. Функция makeBox() в строке 28 создает ящик виджетов. Функция gtk_container_add() в строке 29 помещает виджет ящика в главное окно, а обращение в строке 30 к функции gtk_widget__show() делает главное окно видимым.
Функция makeBox(), запускаемая в строке 34, создает и возвращает вертикальный ящик, содержащий четыре кнопки. Обращение к функции gtk_vbox_new() в строке 38 создает ящик (box). Кнопки добавляются в том порядке, в каком они будут отображаться, но их можно добавлять как сверху, так и снизу. Кнопка (Start 1), созданная в строке 41, добавляется в начало ящика в строке 42, это означает, что она вставляется вверху ящика. Кнопка (End 1), созданная в строке 45, в строке 46 добавляется в конец ящика, это означает, что она вставляется внизу ящика. Любой другой из виджетов (Start 2 button), который добавляется в начало ящика, помещается ниже имеющихся вверху виджетов, а любой из виджетов (End 2 button), который добавляется в конец ящика, располагается выше имеющихся там виджетов.
Взятый по умолчанию размер изображения на рис. 4.1 говорит о том, что все пригнано оптимальным образом. Каждая из кнопок сообщает ящику свой размер. Ящик пытается выровнять элементы вдоль своих кромок, поэтому анализирует высоту и ширину кнопок, чтобы установить все размеры и позицию каждой из них. Все кнопки имеют одинаковую высоту, следовательно, отсутствует необходимость в вертикальной пригонке. Ящик определяет ширину самой широкой кнопки, каковой в нашем случае является кнопка Start 2 button, и использует это значение для задания ширины всех кнопок. Помимо ширины ящик сообщает каждой кнопке ее координаты х и у на экране. Следуя инструкциям, каждая кнопка центрирует свой текст и отображает себя в заданном месте и в требуемом размере. Ящик (box) также является виджетом, и, следовательно, когда главное окно запрашивает его размер, ящик возвращает размер общей области, необходимой для размещения всех четырех кнопок. Главное окно использует эти размеры и, задавая координаты х и у окна, добавляет рамку шириной 25 пикселов.
Размеры и конфигурации, получаемые по умолчанию, являются оптимальными. Изменить размеры окна можно с помощью мыши, но они не могут быть меньше его первоначальных размеров ни по горизонтали, ни по вертикали. Но размеры можно сделать больше. Например, увеличение высоты окна, как показано на рис. 4.2, приводит к тому, что кнопки в ящике разделяются: упакованные сверху, остаются вверху, а упакованные снизу, остаются внизу. Растяжение ящика по горизонтали, как показано на рис. 4.3, увеличивает ширину кнопок, заполняющих его.
Start 1
Start 2 button
_Start 1
End 2 buttonEnd 1End 2 buttonEnd 1Start 2 button
End 2 button
End 1
End 2 button
End 1
. End 2 buttonEnd 1
Рисунок 4.2.Изменение высоты окна разделяет кнопкиРисунок 4.2.Изменение высоты окна разделяет кнопкиРисунок 4.3.Изменение ширины окна удлиняет кнопкиРисунок 4.3.Изменение ширины окна удлиняет кнопки
Рисунок 4.2.
Изменение высоты окна разделяет кнопки
Рисунок 4.2.
Изменение высоты окна разделяет кнопки
Рисунок 4.3.
Изменение ширины окна удлиняет кнопки
Рисунок 4.3.
Изменение ширины окна удлиняет кнопки
Очевидно, что высота кнопок в вертикальном ящике не может быть увеличена, может быть увеличена только ширина. Кроме того, смещение виджетов, содержащихся в ящике, рассчитывается от верхнего или от нижнего края в зависимости от того, как этот виджет добавлен в ящик. На практике это довольно удобно. Если все виджеты упакованы на одном краю ящика, они остаются вместе на том краю независимо от растяжения окна.
Горизонтальный ящик
Горизонтальный и вертикальный ящики абсолютно аналогичны за исключением того, что упаковка виджета в начале ящика располагает его слева, а упаковка виджета в конце ящика располагает его справа. Предыдущую программу vertbox • с можно переделать в программу horizbox.c, всего лишь изменив название программы и одну строку кода. Строка 38 для вертикального ящика выглядит следующим образом:
box = gtk_vbox_new(FALSE,0);’
Заменив эту строку приведенной ниже, мы получим горизонтальный ящик:
box = gtk_hbox_new(FALSE, 0);
Это и все. Экран дисплея теперь выглядит, как представлено на рис. 4.4.
Start 11 start 2 button] End 2 button] End 1|Start 11 start 2 button] End 2 button] End 1|Рисунок 4.4. Четыре кнопки в горизонтальном ящикеРисунок 4.4. Четыре кнопки в горизонтальном ящикеПригонка размеров в горизонтальном ящике дает тот же самый эффект, что и в вертикальном, за исключением того, что изменения происходят в другом измерении. На рис. 4.5 показан горизонтальный ящик с увеличенной высотой, при этом увеличилась высота всех кнопок. На рис. 4.6 показан горизонтальный ящик с увеличенной шириной, при этом размеры кнопок не увеличиваются, а кнопки пристраиваются к тому краю, к которому были первоначально добавлены.
Start 11 start 2 button] End 2 button] End 1|
Start 11 start 2 button] End 2 button] End 1|
Рисунок 4.4. Четыре кнопки в горизонтальном ящике
Рисунок 4.4. Четыре кнопки в горизонтальном ящике
Рисунок 4.5.Изменение высоты ящика меняет высоту кнопокРисунок 4.5.Изменение высоты ящика меняет высоту кнопокXiXiStart 1| Start 2 button)Start 1| Start 2 button)End 2 button) End 1 ]End 2 button) End 1 ]Рисунок 4.6.Изменение ширины ящика разделяет кнопкиРисунок 4.6.Изменение ширины ящика разделяет кнопки
Рисунок 4.5.
Изменение высоты ящика меняет высоту кнопок
Рисунок 4.5.
Изменение высоты ящика меняет высоту кнопок
Xi
Xi
Start 1| Start 2 button)
Start 1| Start 2 button)
End 2 button) End 1 ]
End 2 button) End 1 ]
Рисунок 4.6.
Изменение ширины ящика разделяет кнопки
Рисунок 4.6.
Изменение ширины ящика разделяет кнопки
Опции горизонтального ящика
Существуют три опционные установки, которые управляют размещением виджетов в ящике. (По правде говоря, их четыре, но задание интервала между виджетами будет рассмотрено далее в этой главе). Все три установки булевы и, таким образом, возможны воСуществуют три опционные установки, которые управляют размещением виджетов в ящике. (По правде говоря, их четыре, но задание интервала между виджетами будет рассмотрено далее в этой главе). Все три установки булевы и, таким образом, возможны восемь комбинаций, которые показаны на рис. 4.7.В горизонтальном ящике виджеты однородны (homogeneous), если области экрана, выделенные для их размещения, имеют одну и ту же ширину. Каждый виджет отображается в центре горизонтальной области, предназначенной для него, и может быть или не быть расширенным для заполнения области.Виджетам может быть указано расшириться (expand) таким образом, чтобы использовать весь ящик. Это не влияет на видимый размер виджета. Просто при этом существующий виджет центрируется в области, которая может иметь или не иметь ширину больше, чем естественная ширина виджета. Области под каждый виджет выделяются на процентной основе. Если минимальный размер по умолчанию одного из виджетов составляет половину такого же размера другого виджета, то такое соотноше-семь комбинаций, которые показаны на рис. 4.7.В горизонтальном ящике виджеты однородны (homogeneous), если области экрана, выделенные для их размещения, имеют одну и ту же ширину. Каждый виджет отображается в центре горизонтальной области, предназначенной для него, и может быть или не быть расширенным для заполнения области.Виджетам может быть указано расшириться (expand) таким образом, чтобы использовать весь ящик. Это не влияет на видимый размер виджета. Просто при этом существующий виджет центрируется в области, которая может иметь или не иметь ширину больше, чем естественная ширина виджета. Области под каждый виджет выделяются на процентной основе. Если минимальный размер по умолчанию одного из виджетов составляет половину такого же размера другого виджета, то такое соотноше-non-homogeneous, no expand, no fill. Purple) Red) LavenderBlue] Yellow)non-homogeneous, no expand, no fill. Purple) Red) LavenderBlue] Yellow)non-homogeneous, по expand, fill: Purple) Red] LavenderBlue] Yellow)non-homogeneous, по expand, fill: Purple) Red] LavenderBlue] Yellow)3. non-homogeneous, expand, по fill:3. non-homogeneous, expand, по fill:njx.njx.non-homoaeneous, expand, fill Purple JRed | LavenderBlue| Yellow|non-homoaeneous, expand, fill Purple JRed | LavenderBlue| Yellow|homogeneous, no expand, no fill:Purple) Red] Laverhomogeneous, no expand, no fill:Purple) Red] Laver6 homogeneous, no expand, fillPurple ] Red ) LavenderBlue) Yellow ]6 homogeneous, no expand, fillPurple ] Red ) LavenderBlue) Yellow ]homogeneous, expand, no fill:Purple] Red] Lahomogeneous, expand, no fill:Purple] Red] La8. homogeneous, expand, fillPurple ] Red ] LavenderBlue] Yellow ]8. homogeneous, expand, fillPurple ] Red ] LavenderBlue] Yellow ]
Существуют три опционные установки, которые управляют размещением виджетов в ящике. (По правде говоря, их четыре, но задание интервала между виджетами будет рассмотрено далее в этой главе). Все три установки булевы и, таким образом, возможны во
Существуют три опционные установки, которые управляют размещением виджетов в ящике. (По правде говоря, их четыре, но задание интервала между виджетами будет рассмотрено далее в этой главе). Все три установки булевы и, таким образом, возможны во
семь комбинаций, которые показаны на рис. 4.7.
В горизонтальном ящике виджеты однородны (homogeneous), если области экрана, выделенные для их размещения, имеют одну и ту же ширину. Каждый виджет отображается в центре горизонтальной области, предназначенной для него, и может быть или не быть расширенным для заполнения области.
Виджетам может быть указано расшириться (expand) таким образом, чтобы использовать весь ящик. Это не влияет на видимый размер виджета. Просто при этом существующий виджет центрируется в области, которая может иметь или не иметь ширину больше, чем естественная ширина виджета. Области под каждый виджет выделяются на процентной основе. Если минимальный размер по умолчанию одного из виджетов составляет половину такого же размера другого виджета, то такое соотноше-
семь комбинаций, которые показаны на рис. 4.7.
В горизонтальном ящике виджеты однородны (homogeneous), если области экрана, выделенные для их размещения, имеют одну и ту же ширину. Каждый виджет отображается в центре горизонтальной области, предназначенной для него, и может быть или не быть расширенным для заполнения области.
Виджетам может быть указано расшириться (expand) таким образом, чтобы использовать весь ящик. Это не влияет на видимый размер виджета. Просто при этом существующий виджет центрируется в области, которая может иметь или не иметь ширину больше, чем естественная ширина виджета. Области под каждый виджет выделяются на процентной основе. Если минимальный размер по умолчанию одного из виджетов составляет половину такого же размера другого виджета, то такое соотноше-
non-homogeneous, no expand, no fill. Purple) Red) LavenderBlue] Yellow)
non-homogeneous, no expand, no fill. Purple) Red) LavenderBlue] Yellow)
non-homogeneous, по expand, fill: Purple) Red] LavenderBlue] Yellow)
non-homogeneous, по expand, fill: Purple) Red] LavenderBlue] Yellow)
3. non-homogeneous, expand, по fill:
3. non-homogeneous, expand, по fill:
njx.
njx.
non-homoaeneous, expand, fill Purple JRed | LavenderBlue| Yellow|
non-homoaeneous, expand, fill Purple JRed | LavenderBlue| Yellow|
homogeneous, no expand, no fill:
Purple) Red] Laver
homogeneous, no expand, no fill:
Purple) Red] Laver
6 homogeneous, no expand, fill
Purple ] Red ) LavenderBlue) Yellow ]
6 homogeneous, no expand, fill
Purple ] Red ) LavenderBlue) Yellow ]
homogeneous, expand, no fill:
Purple] Red] La
homogeneous, expand, no fill:
Purple] Red] La
8. homogeneous, expand, fill
Purple ] Red ] LavenderBlue] Yellow ]
8. homogeneous, expand, fill
Purple ] Red ] LavenderBlue] Yellow ]
Рисунок 4.7.Использование горизонтальных ящиков для размещения виджетовРисунок 4.7.Использование горизонтальных ящиков для размещения виджетовние сохраняется и при увеличении размеров виджетов до размеров ящика. Например, если ширина ящика составляет 800 пикселов и он содержит один виджет шириной 100 пикселов
Рисунок 4.7.
Использование горизонтальных ящиков для размещения виджетов
Рисунок 4.7.
Использование горизонтальных ящиков для размещения виджетов
и другой — шириной 300 пикселов, то при заполнении всего ящика ширина обоих виджетов удваивается до 200 и 600 пикселов соответственно.
Виджетам может быть указано заполнить (fill) всю выделенную им область. По умолчанию области, выделяемая под виджет, имеет ширину, равную минимальной ширине виджета, но если виджету поступило указание расшириться и занять выделенную область, превышающую его размеры, он расширится, заполняя эту область.
На рис. 4.7 приведены все восемь возможных комбинаций, но при этом имеются некоторые дублирования. В действительности существуют всего шесть различающихся комбинаций. Совпадают изображения под номерами 5 и 7, а также под номерами 6 и 8. Это обусловлено тем, что если ящик однородный (homogeneous), то установка expand не
оказывает никакого влияния.
Окно, показанное на рис. 4.7, построено приведенной ниже программой, которая создает главное окно, содержащее один вертикальный ящик. В свою очередь, вертикальный ящик наполнен горизонтальными ящиками. Эти горизонтальные ящики заполнены кнопками — простыми виджетами со скошенными краями, что позволяет без труда видеть, где каждая кнопка начинается и завершается.
/** horizboxes.c **/
linclude <gnome.h>
3
GtkWidget *makeBoxes();
gint eventDelete(GtkWidget *widget,
GdkEvent ♦event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent ♦event,gpointer data);
void buttonFill(GtkWidget *box,gboolean expand,
gboolean fill,guint spacing);
11
static gchar *buttonLabel[] = {
"Purple",
"Red",
"LavenderBlue",
"Yellow"
};
18
19 int main(int argc,char *argv[])
{
GtkWidget *window;
GtkWidget *box;
23
24gnome_init("horizboxes","1.0",argc,argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtksignalconnect(GTK_OBJECT(window),
"delete_event",
GTKSIGNALFUNC(eventDelete),
NULL); '
gtk_signal_connect(GTKOBJECT(window),
"destroy",
GTK_SIGNAL__FUNC (even tDe Stroy),
NULL);
34
35box = makeBoxes();
gtk_container_set_border_width(
GTK_CONTAINER(window),25);
gtk_container_add(GTK_CONTAINER(window),box);
gtk_widget_show(box);
40
gtk_widget_show(window);
gtk_main();
exit(0);
}
GtkWidget *makeBoxes() {
GtkWidget *vbox;
GtkWidget *hbox;
GtkWidget *label;
49
gboolean homogeneous;
gboolean expand;
52 53 54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72 73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90 ' 91 ■ 92
93
94
95
96
97
98
99
100 101 102
103 104 105
106 107 108
109
gboolean fill
gint gint gint gint
HCount; eCount; fCount; count = 0
gchar labelstring[80];
vbox = gtk_vbox_new(FALSE,0);
for(hCount = 0; HCount <= 1; hCount++) { homogeneous = HCount ? TRUE : FALSE; for(eCount = 0; eCount <= 1; eCount++) { expand = eCount ? TRUE : FALSE; for(fCount = 0; fCount <= 1; fCount++) { fill = fCount ? TRUE ; FALSE; if(count > 0) { label = gtk_label_new(" "); gtk_box_pack_start(GTK_BOX(vbox), label,FALSE,FALSE,0); gtk_widget_show(label);
} sprintf(labelstring,"%d. ",++count); if(homogeneous) streat(labelstring,"homogeneous, "); else
streat(labelstring,"non-homogeneous, "); if(expand)
strcat(labelString,"expand, " else
streat(labelstring,"no expand if(fill)
strcat(labelstring,"fill:"); else
strcat(labelstring,"no fill:"
);
);
)
label = gtk_label_new(labelstring); gtk_misc_set_alignment(
GTK MISC(label),0,0); gtkboxpackstart(GTKBOX(vbox), label,FALSE,FALSE,0); gtk_widget_show(label);
hbox = gtk_hbox_new(homogeneous,0); buttonFill(hbox,expand,fill,0);
gtkboxpackstart(GTKJBOX(vbox), hbox,FALSE,FALSE,0);
gtkwidgetshow(hbox);
}
}
Return(vbox);
}
void buttonFill(GtkWidget *box,gboolean expand gboolean fill,guint spacing)
{
GtkWidget *button; gint i;
button • gtk_button_new_with_label(buttonLabel[i]);
gtk_box_pack_start(GTK_BOX(box),button,
expand,fill,spacing);
112gtk_widget_show(button);
113}
114 }
115 gint eventDelete(GtkWidget *widget,
116GdkEvent *event,gpointer data) {
117 return(FALSE);
118 }
119 gint eventDestroy(GtkWidget *widget,
120GdkEvent *event,gpointer data) {
121gtk_main_quit();
122return(O);
123 }
Обращение к функции makeBoxes () в строке 35 возвращает вертикальный ящик, содержащий все горизонтальные ящики. В строках с 36 по 39 задается рамка вокруг ящика, добавляется в главное окно, а затем окно выводится на экран.
Функция makeBoxes (), которая начинается со строки 45, создает по одному ящику для каждого из восьми вариантов возможных установок. Поскольку в данном примере изображение часто повторяется и нет необходимости назначать кнопкам функции обратного вызова, все ящики и кнопки создаются в цикле, который начинается со строки 61. В действительности, это вложенный цикл с оператором for для каждой установки. Булевы значения homogeneous, expand и fill переключаются в начале каждого цикла и используются все их возможные комбинации, чтобы создать ящик, заполненный кнопками.
Каждому горизонтальному ящику предшествует пустая метка(для создания интервала) и метка, описывающая установки ящика. Строки с 67 по 72 включают пустую метку. В строках с 74 по 85 на основе установок конфигурации создается строка описания, которая используется в строке 86 при создании виджета метки. Обращение к функции gtk_misc_set_alignment () в строке 88 выравнивает текст метки (надписи) по левому краю (по умолчанию центрирует).
Вызванная в строке 92 функция gtk_hbox_new() создает горизонтальный ящик, а функция buttonFill () из строки 93 заполняет его кнопками. Именно здесь создаются установки конфигурации. Ойи передаются ящику, а не отдельным виджетам, если размещение виджетов однородное, поэтому в качестве булева значения первого аргумента, передаваемого при вызове функции gtk^hbox_new(), принимается homogeneous. Аргументы expand и fill передаются от виджета к виджету, поэтому они передаются функции buttonFill () для применения их к кая(цой новой кнопке.
Функция buttonFill (), которая начинается со строки 102, использует значения переданных ей аргументов для упаковки ящика с виджетами четырех кнопок. Метки кнопок создаются из массива строк разной длины, так что различия в расположении кнопок весьма очевидны. Цикл, который начинается со строки 108, создает каждую кнопку й добавляет ее в ящик.
Опции вертикального ящика
На рис. 4.8 приведен результат применения всех восьми комбинаций к последовательности вертикальных ящиков. Сравнивая вертикальные ящики на этом рисунке с горизонтальными, приведенными ранее на рис. 4.7, можно без труда понять, как работает такое размещение. Одни и те же правила применяются как для горизонтального расположения, так и для вертикального.
1 Purple
2 Purple.
3 „ , Puree
4 Purole
5-.
Purple :
1 6. .•
1 . Purple
7 Purple ।
1 8- *
|■ Purple
3; X
Red
Red
Lavender Blue
Lavender Blue
. - Red 1
1Red
■ Red ■
Red
Red
Red
Lavender Blue
Lavender ■ B,u®
■ ' Yellow
Yellow
Lavender Blue
Lavender
■ Lavender Blue
■ Lavender Blue
Yellow |
| Yellow
Yellow
Yellow
VeWow
Yellow
Рисунок 4.8. Использование вертикальных ящиков для размещения виджетов
Пример программы, приведенный ниже, очень похож на предыдущий, единственными различиями являются операторы, которые необходимы для переделки ящиков из горизонтальных в вертикальные и для правильного их вывода на экран.
/♦* vertboxes.c **/
#include <gnome.h>
3
GtkWidget *makeBoxes();
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
void buttonFill(GtkWidget *box,gboolean expand,
gboolean fill,guint spacing);
11
static gchar *buttonLabel[] = {
"Purple",
"Red",
"LavenderXnBlue",
"Yellow"
Irie
19 int main(int argc,char *argv[])-
{
GtkWidget *window;_.
GtkWidget *box;
23
24gnome_init("vertboxes","1.0",argc,argv);
25window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
26gtk_signal_connect(GTK_OBJECT(window),
27"delete_event",
28GTK_SIGNAL_FUNC(eventDelete),
,29NULL);
30gtk_signal_connect(GTK_OBJECT(window),
31"destroy",
32•GTK_SIGNAL_FUNC(eventDestroy),
33NULL);
34.
35box = makeBoxes();
36gtk_container_set_border_width(
37GTK_CONTAINER(window),25);
38gtk_container_add(GTK_CONTAINER(window),box);
39gtk_widget_show(box);
40
41gtk_widget_show(window);
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
gtk_main();
exit(0);
}
GtkWidget *makeBoxes() {
GtkWidget *hbox;
GtkWidget *buttonBox;
GtkWidget *label;
gboolean homogeneous;
gboolean expand;
gboolean fill;
gint HCount;
gint eCount;
gint fCount;
gint count = 0;
gchar labelstring[80];
hbox = gtk_hbox_new(FALSE,0);
for(hCount = 0; HCount <= 1; hCount++) { homogeneous = HCount ? TRUE : FALSE; for(eCount = 0; eCount <= 1; eCount++) { expand = eCount ? TRUE : FALSE;
for(fCount = 0; fCount <= 1; fCount++) { fill = fCount ? TRUE : FALSE;
if(count > 0) { label = gtk_label_new(" "); gtk_box_pack_start(GTK_BOX(hbox), label,FALSE,FALSE, 0);
gtk_widget_show(label); }
sprintf(labelstring," %d. ",++count); label = gtk_label_new(labelString);
gtk_misc_set_alignment(
GTKMISC(label),0,0);
gtkboxpackstart(GTK_BOX(hbox), label,FALSE,FALSE,0);
gtk_widget_show(label);
buttonBox = gtk_vbox_new(homogeneous,0); buttonFill(buttonBox,expand,fill,0);
gtkboxpackstart(GTKBOX(hbox), buttonBox,FALSE,FALSE, 0) ;
gtk_widget_show(buttonBox); } } } return(hbox);
}
void buttonFill(GtkWidget *box,gboolean expand, gboolean fill,guint spacing)
{
GtkWidget *button;
9697989996979899gint i;
96
97
98
99
96
97
98
99
button = gtk_button_new_with_label(buttonLabel[i]); gtk_box_pack_start(GTKBOX(box),button, expand,fill,spacing);
100gtk_widget_show(buttonJ;
101}
102 }
103 gint eventDelete(GtkWidget *widget,
104GdkEvent *event,gpointer data) {
105 return(FALSE);
106 }
107 gint eventDestroy(GtkWidget *widget,
108GdkEvent *event,gpointer data) {
109gtk_main_quit();
110return(O);
Hl }
В наименовании цвета в строке 15 появился символ newline (новой строки), который делит текст кнопки на две строки вместо одной. Различное количество строк в наименовании также позволяет варьировать размеры кнопок, помогая увидеть, как работает позиционирование.
Обращение к функции makeBoxes() в строке 35 создает набор вертикальных ящиков, содержащихся в горизонтальном, а в строке 38 горизонтальный ящик включается в главное окно. Три вложенных цикла, которые начинаются со строки 61, осуществляют переключение значений установок для получения всех восьми возможных комбинаций. В строках с 73 по 76 для каждого вертикального ящика создается метка. Она содержит только номер, причем номера на рис. 4.8 соответствуют номерам на рис. 4.7.
Задание интервалов между виджетами в ящиках
Существует несколько вариантов включения интервалов между виджетами в ящике. Вы можете задать количество пикселов для добавления к пространству вокруг каждого виджета ящика, задать количество пикселов между виджетами или сделать и то, и другое одновременно. Все это справедливо как для горизонтальных, так и для вертикальных ящиков. Приведенный пример демонстрирует задание интервалов в вертикальном ящике.
/** spacebox.с **/
#include <gnome.h>
3
GtkWidget *makeBox();
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
9
Idefine ALL_SPACE 5
Idefine FIRSTSPACE 0
Idefine SECOND_SPACE 0
Idefine THIRD_SPACE 0
Idefine FOURTH_SPACE 0■
15
int main(int argc,char *argv[])
{
GtkWidget *window;
GtkWidget *box;
'■
21gnome_init("spacebox","1.0",argc,argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_signal_connect(GTK_OBJECT(window),
"delete_event",
GTK_SIGNAL_FUNC(eventDelete),
NULL);
gtk_signal_connect(GTK_OBJECT(window),
"destroy",
GTKSIGNALFUNC(eventDestroy),
NULL);
31
box = makeBox();
gtk_container_add(GTK_CONTAINER(window),box);
gtk_widget_show(window);
gtk_main();
exit(0);
}
GtkWidget *makeBox() {
GtkWidget *box;
GtkWidget *btn;
41
box = gtk_vbox_new(FALSE,ALL_SPACE);
gtk_widget_show(box);
44
45
btn = gtk_button_new_with_label("The First Widget");
gtk_box_pack_start(GTK_BOX(box),btn,
FALSE,FALSE,FIRST_SPACE);
gtk_widget_show(btn);
50
btn = gtk_button_new_with_label("The Second Widget");
2gtkboxpackstart(GTK_BOX(box),btn,
FALSE,FALSE,SECOND_SPACE);
gtk_widget_show(btn);
55
btn = gtk_button_new_with_label("TheThird Widget");
gtkboxpackstart(GTK_BOX(box),btn,
FALSE,FALSE,THIRD_SPACE);
gtk_widget_show(btn);
60
btn = gtkbutton_new_with_label("TheFourth Widget");
gtkboxpackstart(GTKBOX(box),btn,
FALSE,FALSE,FOURTH^SPACE);
gtk_widget_show(btn);
65
return(box);
}
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data) {
return(FALSE);
}
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data) {
gtk_main_quit();
return(0);
}
Константы, определенные в строках с 10 по 14, это величины интервалов, которые используются для размещения виджетов в вертикальном ящике. Значение ALL_SPACE применяется для каждого виджета ящика путем его использования в качестве аргумента функ-
The First WidgetThe Second WidgetThe Third WidgetThe Fourth WidgetРисунок 4.9.Одинаковые вертикальные интервалы между виджетамиThe First WidgetThe Second WidgetThe Third WidgetThe Fourth WidgetРисунок 4.9.Одинаковые вертикальные интервалы между виджетами1ИИЕ®йThe First widget1ИИЕ®йThe First widgetThe Second WidgetThe Second WidgetThe Third WidgetThe Third WidgetThe Fourth WidgetThe Fourth WidgetРисунок 4.10.Разные интервалы между виджетамиРисунок 4.10.Разные интервалы между виджетамиРисунок 4.11.Одновременное задание интервалов для ящика и для виджетовРисунок 4.11.Одновременное задание интервалов для ящика и для виджетов
The First WidgetThe Second WidgetThe Third WidgetThe Fourth Widget
Рисунок 4.9.
Одинаковые вертикальные интервалы между виджетами
The First WidgetThe Second WidgetThe Third WidgetThe Fourth Widget
Рисунок 4.9.
Одинаковые вертикальные интервалы между виджетами
1ИИЕ®й
The First widget
1ИИЕ®й
The First widget
The Second Widget
The Second Widget
The Third Widget
The Third Widget
The Fourth Widget
The Fourth Widget
Рисунок 4.10.
Разные интервалы между виджетами
Рисунок 4.10.
Разные интервалы между виджетами
Рисунок 4.11.
Одновременное задание интервалов для ящика и для виджетов
Рисунок 4.11.
Одновременное задание интервалов для ящика и для виджетов
ции gtk_box_vbox_new(), когда в строке 44 создается ящик. Остальные четыре зна
чения используются для задания интервалов вокруг каждого виджета путем передачи их
в качестве аргументов при каждом обращении к функции gtk_box_pack_start () в
строках 49, 54, 59 и 64.
Величины интервалов в приведенной программе составляют 5 пикселов для ящика и 0 пикселов для каждого отдельно взятого виджета. Результат выполнения программы приведен на рис. 4.9. Интервалы расставляются только между виджетами. Над верхним и под нижним виджетом интервалы отсутствуют, но между виджетами каждой пары имеется интервал в 5 пикселов.
Интервал может быть задан для каждого отдельно взятого виджета. Изображение на рис. 4.10 можно создать, заменив строки с 10 по 14 следующими:
♦define ALLSPACE 0
Idefine FIRST_SPACE 5
Idefine SECOND_SPACE 10
Idefine THIRD_SPACE 20
♦define FOURTH SPACE 40
Интервал в 5 пикселов вставляется над первым виджетом, поскольку сам виджет требует этого. Ящик перед размещением в нем виджетов запрашивает у каждого виджета размеры области, необходимой для его размещения. Так как интервал для первого виджета равен 5, этот виджет получает 10 дополнительных пикселов — 5 пикселов над и 5 пикселов под телом виджета. Второй виджет соответственно требует интервал размером 10 пикселов и, следовательно, между первым и вторым виджетами возникает интервал, равный 15 пикселов. Аналогично, интервал между вторым и третьим виджетами составляет 30 пикселов (10+20), а интервал между третьим и четвертым — 60 пикселов (20+40). Еще 40 пикселов вставляется под четвертым виджетом.
Можно также одновременно задавать интервалы для ящика в целом и для каждого виджета по отдельности. Например, заменив строки с 10 по 14 приведенными ниже, можно создать окно, изображенное на рис. 4.11:
Idefine ALL_SPACE 5
♦define FIRST_SPACE 2
♦define SECOND_SPACE 10
♦define THIRD_SPACE 10
♦define FOURTH_SPACE 2
В каждом случае актуальная величина интервала определяется как сумма величин всех задаваемых интервалов. Так как сам ящик только вставляет между виджетами интервал величиной ALL_SPACE, то первый виджет размещается на расстоянии 2 пикселов от верхнего края окна. Интервал между первым и вторым виджетами составляет 17 пикселов: ящик задает 5 пикселов, первый виджет добавляет 2 и второй добавляет 10. Интервал между вторым и третьим виджетами составляет 25 пикселов, т.е. сумму интервала в 5 пикселов для всего ящика и дважды по 10 пикселов с учетом каждого из виджетов. Ин-
тервал между третьим и четвертым виджетами составляет 17 пикселов и еще 2 пиксела
под четвертым виджетом.
The First WidgetThe First WidgetThe Second WidgetThe Second WidgetThe Third WidgetThe Fourth WidgetРисунок 4.12.Применение различных интервалов между виджетамиThe Third WidgetThe Fourth WidgetРисунок 4.12.Применение различных интервалов между виджетамиПоскольку значение интервала, задаваемого для виджета, получается в результате сложения интервалов над и под виджетом, далеко не все комбинации интервалов могут быть получены этим методом. Например, разместить три виджета вместе и вставить интервалы над и под ними возможно только, вставив еще один ящик для их поддержки, как будет показано в следующем разделе. Но, тем не менее, даже используя интервалы внутри одного ящика, можно достичь довольно большого разнообразия. Например, расположение виджетов, представленное на рис. 4.12, получено следующей заменой констант:
The First Widget
The First Widget
The Second Widget
The Second Widget
The Third WidgetThe Fourth Widget
Рисунок 4.12.
Применение различных интервалов между виджетами
The Third WidgetThe Fourth Widget
Рисунок 4.12.
Применение различных интервалов между виджетами
♦define ALL_SPACE О
♦define FIRSTSPACE О
♦define SECONDSPACE 30
♦define THIRDSPACE 0
♦define FOURTHSPACE 5
Этот пример показывает, насколько могут отличаться величины интервалов между виджетами. Интервал для первого виджета равен 0, таким образом, он располагается вверху содержащего его ящика. Интервал для второго виджета составляет 30 пикселов над и 30 пикселов под виджетом. И, наконец, интервал для четвертого виджета составляет 5 пикселов между ним и третьим виджетом и еще 5 пикселов между ним и низом ящика.
Ящики внутри других ящиков
Вы можете получить любые комбинации интервалов и расположения виджетов путем размещения одних ящиков внутри других. Ящики предназначены для размещения в них виджетов и при этом сами являются виджетами, следовательно, вы можете упаковать одни ящики в другие, как зашей душе угодно. В этой главе уже приводилось несколько примеров такого использования, но следующий пример показывает, как можно применять вложенные ящики для создания более сложных вариантов расположения виджетов. Пусть, например, необходимо создать окно с одной кнопкой вверху, тремя кнопками, сгруппированными в центре, и еще двумя кнопками, расположенными бок о бок внизу окна, как
показано на рис. 4.13.
'. Alone at Top ■■'. Alone at Top ■■First of Three In MiddleSecond of Three in MiddleThird of Three in MiddleFirst of Three In MiddleSecond of Three in MiddleThird of Three in MiddleLeft J Right JРисунок 4.13.Использование вложенных ящиков для размещения виджетов в окнеLeft J Right JРисунок 4.13.Использование вложенных ящиков для размещения виджетов в окнеТакое размещение получено благодаря использованию вертикального ящика, содержащего одну кнопку вверху, встроенный вертикальный ящик в центре и горизонтальный ящик внизу, что демонстрирует следующая программа:
'. Alone at Top ■■
'. Alone at Top ■■
First of Three In MiddleSecond of Three in MiddleThird of Three in Middle
First of Three In MiddleSecond of Three in MiddleThird of Three in Middle
Left J Right J
Рисунок 4.13.
Использование вложенных ящиков для размещения виджетов в окне
Left J Right J
Рисунок 4.13.
Использование вложенных ящиков для размещения виджетов в окне
/♦* boxnest.с **/
♦include <gnome.h>
GtkWidget *makeBox();
GtkWidget *makeMiddleBox();
GtkWidget *makeBottomBox();
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
11
int main(int argc,char *argv[J)
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
GtkWidget *window;
GtkWidget *box;
gnome__init( "boxnest","1.0",argc,argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_signal_connect(GTK_OBJECT(window), "delete_event", GTK_SIGNAL_FUNC(eventDelete), NULL);
gtk_signal_connect(GTK_OBJECT(window), "destroy", GTK_SIGNAL_FUNC(eventDestroy), NULL);
box = makeBox();
gtk_container_add(GTK_CONTAINER(window),box); gtk_widget_show(box);
gtk_widget_show(window);
gtk_main();
exit(0);
}
GtkWidget *makeBox() {
GtkWidget *box;
GtkWidget *button;
GtkWidget *middleBox;
GtkWidget *bottomBox;
box = gtk_vbox_new(FALSE,30);
button = gtkbuttonnewwithlabel("Alone at Top"); gtk_box_pack_start(GTK_BOX(box),button,
FALSE,FALSE,0); gtk_widget_show(button);
middleBox = makeMiddleBox();
gtk_box_pack_start(GTK_BOX(box),middleBox, FALSE,FALSE,0);
gtk_widget_show(middleBox);
bottomBox = makeBottomBox();
gtk_box_pack_start(GTK_BOX(box),bottomBox, FALSE,FALSE,0);
gtk_widget_show(bottomBox);
return(box);
}
GtkWidget *makeMiddleBox() {
GtkWidget *box;
GtkWidget *button;
box = gtkvboxnew(FALSE, 0);
6768697067686970button = gtk_button_new_with_label(
67
68
69
70
67
68
69
70
"First of Three in Middle");
gtk_box_pack_start(GTKBOX(box),button,FALSE,FALSE,0);
gtk_widget_show(button);
71
button = gtk_button_new_with_label(
"Second of Three in Middle");
gtkboxpackstart(GTKJ3OX(box),button,FALSE,FALSE, 0);
gtk_widget_show(button);
-
button = gtk_button_new_with_label(
"Third of Three in Middle");
gtkboxpackstart(GTKBOX(box),button,FALSE,FALSE,0);
gtk_widget_show(button);
81
return(box);
}
GtkWidget *makeBottomBox() { '85GtkWidget *box;
GtkWidget *button;
87
box = gtk_hbox_new(FALSE,0);
•
button = gtk_button_new_with_label("Left");
gtkboxpackstart(GTKBOX(box),button,TRUE,TRUE,5);
gtk_widget_show(button);
93
button = gtk_button_new_with_label("Right");
gtk_box_pack_end(GTKBOX(box),button,TRUE,TRUE, 5);
gtk_widget_show(button);
97
return(box);
}
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data) {
return(FALSE);
}
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data) {
gtk_main_quit();
return(0);
}
Вызов функции makeBox() в строке 28 создает ящик и все его содержимое. Созданный ящик добавляется к контейнеру главного окна в строке 29.
Функция makeBox (), которая начинается со строки 36, создает вертикальный ящик и вставляет в него три виджета. В строке 42 этот ящик собственно создается и для содержащихся в нем виджетов устанавливается интервал в 30 пикселов. Первый виджет — кнопка, создается и вставляется в ящик в строках с 44 по 47. Второй виджет — ящик, возвращается в результате вызова функции makeMiddleBox() в строке 49, и третий виджет — ящик, возвращается в результате вызова функции makeBottomBox() в строке 54. При выводе на экран главное окно подстраивает само себя к высоте и ширине содержащегося в нем ящика. Высота ящика, а следовательно, и высота окна, определяется как сумма высот всех трех виджетов и плюс два интервала по 30 пикселов каждый.
Функция makeMiddleBox (), которая начинается со строки 61, создает вертикальный ящик, содержащий три кнопки. При создании ящика интервал между виджетами установлен равным 0, и следовательно, ширина ящика равна ширине самой широкой кнопки, а высота — сумме высот всех кнопок.
Функция makeBottomBox (), которая начинается в строке 84, создает горизонтальный ящик, содержащий две кнопки. Эти кнопки помещены в ящик как однородные (homogeneous), т.е. имеющие равную ширину, и расширяемые (expand), следовательно, заполняют все доступное им пространство. Кроме того, между соседними кнопками установлен интервал в 5 пикселов. Это приводит к тому, что при горизонтальном растяжении окна кнопки сами меняют свою ширину и перемещаются, сохраняя интервалы и соотношения размеров.
Перед началом создания сложного окна путем упаковки ящиков необходимо выяснить, что из себя представляют ваши ящики. И вовсе не обязательно иметь глубину вложения ящиков, равную трем, четырем и даже пяти, чтобы получить требуемый эффект.
Упаковка с помощью таблиц
Вы можете расположить виджеты в окне, используя значения координат х и у, и, кроме того, вы можете задать размеры сетки. Чтобы разместить виджет на сетке, просто укажите эту сетку и количество занимаемых ею ячеек. Такая сетка называется таблицей (table), она является для виджетов контейнером, очень похожим на ящик, хотя использует другие правила при размещении внутри себя виджетов.
Упаковка маленькой таблицы
Расположение виджетов, показанное на рис. 4.14, основано на таблице шириной две ячейки и высотой три ячейки. Края виджетов привязываются к краям ячеек. На рис. 4.15 представлена сетка 2X3, которая использовалась при создании окна, показанного на рис. 4.14.
:-JBHXj|Top Lett Top Right Mid Left Mid Right■ BottomРисунок 4.14.Размещение кнопок при помощи таблицы:-JBHXj|Top Lett Top Right Mid Left Mid Right■ BottomРисунок 4.14.Размещение кнопок при помощи таблицыСетка 2X3Сетка 2X3Рисунок 4.15.Рисунок 4.15.Виджет располагается в сетке путем привязки его сторон к линиям сетки. Все четыре стороны виджета должны быть присоединены к какой-либо линии сетки. Например, на рис. 4.14 кнопка, помеченная как "Mid Left”, своей левой стороной привязывается к вертикальной линии 0, а своей правой стороной — к вертикальной линии 1. Верхняя сторона кнопки привязана к горизонтальной линии 1, а ее нижняя сторона — к горизонтальной линии 2.
:-JBHXj|
Top Lett Top Right Mid Left Mid Right
■ Bottom
Рисунок 4.14.
Размещение кнопок при помощи таблицы
:-JBHXj|
Top Lett Top Right Mid Left Mid Right
■ Bottom
Рисунок 4.14.
Размещение кнопок при помощи таблицы
Сетка 2X3
Сетка 2X3
Рисунок 4.15.
Рисунок 4.15.
Каждый виджет может накрывать любое количество ячеек сетки. Например, на рис. 4.14 кнопка ’’Bottom” вверху привязана к горизонтальной линии 2, внизу — к горизонтальной линии 3, слева — к вертикальной линии 0, справа — к вертикальной линии 2. Горизонтальная привязка вынуждает кнопку растянуться на две ячейки таблицы.
Приведенная далее программа создает изображение, показанное на рис. 4.14. Кнопки ложатся в таблицу, которая имеет два столбца в ширину и три строки в высоту. Каждая из четырех кнопок в верхней части окна размещается в одной ячейке таблицы, а кнопка в нижней части покрывает две ячейки.
/*♦ fiver.с **/
tinclude <gnome.h>
3
GtkWidget *makeTable();
gint eventDelete(GtkWidget *widget,.
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
9
int main(int argc,char *argv[])
И {
GtkWidget *window;
GtkWidget *table;
14
15gnome_init("fiver","1.0",argc,argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_signal_connect(GTK_OBJECT(window),,
"delete_event",
GTK_SIGNAL_FUNC(eventDelete),
NULL);
gtk_signal_connect(GTK_OBJECT(window),
"destroy",
GTK_SIGNAL_FUNC(eventDestroy),
NULL);*
25
table = makeTable();
gtk_container_add(GTK_CONTAINER(window),table);
gtk_widget_show(window);
gtk_main();
exit(0);
}
GtkWidget *makeTable() {
GtkWidget *table;
GtkWidget *button;
35
table = gtk_table_new(3,2,TRUE);
gtk_widget_show(table);
38
39
button = gtk_button_new_with_label("Top Left");
gtk_table_attach_defaults(GTK_TABLE(table),button,
0,1,0,1);
gtk_widget_show(button);
44
button = gtk_button_new_with_label("Top Right");
gtk_table_attach_defaults(GTK_TABLE(table),button,
1,2,0,1);
gtk_widget_show(button);
49
button = gtk_button_new_with_label("Mid Left");
gtk_table_attach_defaults(GTK_TABLE(table),button,
520,1,1,2);
gtk_widget_show(button);
54
button = gtk__button_new_with_label("Mid Right");
gtk_table_attach_defaults(GTK_TABLE(table),button,
571,2,1,2);
gtk_widget_show(button);
59
button = gtk_button_new_with_label("Bottom");
gtk_table_attach_defaults(GTK_TABLE(table),button,
620,2,2,3);
gtk_widget_show(button);
64
return(table);
}
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data) {
return(FALSE);
}
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data) {
gtk_main_quit();
return(0);
}
Обращение к функции makeTable () в строке 26 возвращает виджет таблицы (table) с пятью кнопками. Таблица добавляется в главное окно в строке 27. Таблица — это виджет и поэтому может быть вставлена в другое окно так же, как и ящик, кнопка или любой другой виджет.
Сама таблица создается в строке 36 внутри функции makeTable (). Первый аргумент — число строк, второй — число столбцов. Третий аргумент задает, будут ли ячейки таблицы однородными, т.е. иметь одинаковые размеры. В данном примере ячейки являются однородными. Таблица подгоняет свои размеры к размерам содержащихся в ней виджетов. Если таблица однородная, то размеры ее ячеек одинаковы и устанавливаются по высоте самой высокой ячейки и по ширине самой широкой ячейки.
Если таблица неоднородная, то все ячейки в каждой строке имеют одну и ту же высоту и все ячейки в каждом столбце имеют одну и ту же ширину. Высота строки виджетов устанавливается равной высоте самого высокого виджета в строке, а ширина определяется по ширине самого широкого виджета в столбце. Если в столбце нет ни одного виджета, то ширина столбца равна нулю.
За отображение виджета на экране несет ответственность сам виджет. Таблица запрашивает минимальную высоту и минимальную ширину, начиная с которых приспосабливается к размерам каждого виджета. Далее таблица определяет минимальный размер для каждой строки и каждого столбца и сообщает каждому виджету эти подстроенные значения высоты и ширины. Одной из особенностей любого виджета является то, что он имеет стандартный набор вызовов функций, используемых для выдачи инструкций и возврата данных.
ПЕРЕКРЕСТНАЯ ССЫЛКА
Более подробно о виджетах см. в главе 18.
Виджеты, отображаемые на экране, в нашем случае группа кнопок, создаются и добавляются в таблицу в строках с 40 по 63. Кнопка, созданная в строке 40, подключается путем вызова функции gtk_table_attach_defaults() в строке 41. Позиционными параметрами являются ”0,1,0,1”, это означает, что слева сторона кнопки подключается к нулевой линии сетки, справа — к линии 1, сверху — к линии 0 и снизу — к линии 1. Позиционными параметрами в строке 52 являются ”0,1,1,2”, т.е. слева кнопка подключается к линии 0, справа — к линии 1, сверху — к линии 1, снизу — к линии 2.
Чтобы растянуть виджет на две или более ячеек, необходимо всего лишь указать начальную и конечную линии сетки. Кнопка ’’Bottom”, которая размещается в строке 61, имеет следующие позиционные параметры — ”0,2,2,3”, т.е. слева кнопка подключается к линии 0, справа — к линии 3, линия 2 пропускается и перекрывается виджетом.
Три кнопки в таблице
Следующая программа располагает три виджета в одной таблице. Каждый виджет отображает в качестве текста числа, используемые для указания его положения в таблице.
/** thrice.с **/''
Iinclude <gnome.h>,
3
GtkWidget *makeTable();
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
9
Idefine HOMOGENEOUS FALSE
11
Idefine ROWS 3
Idefine COLS 3
14
Idefine LOCATE_1N 0,1,0,1
Idefine LOCATE2N 1,2,1,2
Idefine LOCATE_3N 2,3,2,3
18
19 Idefine LOCATE1S "0,1,0,1"
20 Idefine LOCATE2S "1,2,1,2"
21 Idefine LOCATE3S "2,3,2,3"
22
23 int main(int argc,char *argv[])
{.
GtkWidget *window;
GtkWidget *table;
27
gnome_init("thrice","1.0",argc,argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtksignalconnect(GTK_OBJECT(window),
"delete_event",
GTKSIGNALFUNC(eventDelete),
NULL);
gtk_signal_connect(GTK_OBJECT(window),
"destroy",
GTK_SIGNAL_FUNC(eventDestroy),
NULL);
38
table = makeTable();
0gtkcontaineradd(GTK_CONTAINER(window),table);
gtk_widget_show(window);
gtk_main();
exit(O);
}
GtkWidget *makeTable() {
GtkWidget *table;
GtkWidget *button;
48
49table = gtktablenew(ROWS,COLS,HOMOGENEOUS);
50gtkwidgetshow(table);
51
52
53button = gtk_button_new_with_label(LOCATE_1S);
54gtk_table_attach_defaults(GTK_TABLE(table),button,
55LOCATE_1N);
56gtk_widget_show(button);
57
58button = gtk_button_new_with_label(LOCATE_2S);
59gtk_table_attach_defaults(GTK_TABLE(table),button,
60LOCATE2N);
61gtk_widget_show(button);
62
63button = gtkbuttonnewwithlabel(LOCATE3S);
4gtk_table_attach_defaults(GTK_TABLE(table),button,
65LOCATE3N);
gtkwidgetshow(button);
67
return(table);
}
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data) {
return(FALSE);
}
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data) {
gtk_main_quit();
return(O);
}
Константы, объявленные в строках с 10 по 21, определяют размер таблицы, ее расположение и метки (надписи) с текстом на кнопках. В данном примере текст каждой метки отображает положение кнопки в таблице. Константы, объявленные в строках с 10 по 13, используются при вызове функции gtk_table_new() в строке 49, где указывается сетка 3x3 для неоднородной таблицы. Константы, объявленные в строках с 15 по 17, используются в качестве четырех последних аргументов при вызове функции gtk_table_attach__def aults () в строках 54, 59 и 64.
Рисунок 4.16. Три виджета, размещаемые с помощью таблицыРисунок 4.16. Три виджета, размещаемые с помощью таблицыOkhq, полученное из этой программы, представлено на рис. 4.16. Поскольку рассмотренная таблица неоднородная, то ширина столбцов, как и высота строк, может варьироваться, но все кнопки имеют одинаковые размеры, вынуждая строки и столбцы быть единообразными.
Рисунок 4.16. Три виджета, размещаемые с помощью таблицы
Рисунок 4.16. Три виджета, размещаемые с помощью таблицы
Эту же программу можно использовать для добавления интервалов между виджетами, но для этого необходимо, чтобы таблица была однородной. В качестве примера заменим строки 10-21 предшествующей программы на следующие:
Рисунок 4.17.Пустоты, вставленные благодаря однородности таблицыРисунок 4.17.Пустоты, вставленные благодаря однородности таблицыРисунок 4.18.В неоднородной таблице пустоты убираютсяРисунок 4.18.В неоднородной таблице пустоты убираютсяможет вызывать некото-может вызывать некото-
Рисунок 4.17.
Пустоты, вставленные благодаря однородности таблицы
Рисунок 4.17.
Пустоты, вставленные благодаря однородности таблицы
Рисунок 4.18.
В неоднородной таблице пустоты убираются
Рисунок 4.18.
В неоднородной таблице пустоты убираются
может вызывать некото-
может вызывать некото-
♦define HOMOGENEOUS TRUE
♦define ROWS 5
♦define COLS 5
♦define LOCATE_1N 0,1,0,1
♦define LOCATE_2N 1,2,1,2
♦define LOCATE_3N 4,5,4,5
♦define LOCATE_1S "0,1,0,1"
♦define LOCATE_2S "1,2,1,2"
♦define LOCATE_3S "4,5,4,5"
Эти изменения создадут сетку 5x5 и сделают таблицу однородной. Последняя кнопка располагается в нижнем правом углу таблицы. Поскольку таблица однородная, то все ячейки имеют одинаковые размеры. При этом экран дисплея выглядит так, как показано на рис. 4.17.
Изменение установки HOMOGENEOUS с TRUE на FALSE изменяет вид окна, как показано на рис. 4.18. Для каждой ячейки таблицы установлены ее минимальные размеры. Между вертикальными линиями 2 и 4 нет ни одного виджета, так что минимальная ширина равна нулю. Но и между горизонтальными линиями 2 и 4 нет ни одного виджета, так что минимальная высота равна нулю.
Запоминание правильного порядка параметров размещен]
рые затруднения. При создании окна со многими виджетами можно перепутать, какой номер чему соответствует. Если вы сделаете ошибку в порядке параметров, полученный результат может сбить вас с толку. Даже пара неправильно заданных чисел может привести к тому, что окно будет выглядеть совсем не так, как предполагалось, и вы должны будете начать все с начала. Удобно было бы нарисовать где-нибудь в блокноте что-то похожее на следующее:
<- -> ф ф
Каждая стрелка указывает направление привязки. Первое число определяет линию сетки слева, второе число определяет линию сетки справа, следующее — линию сверху и, наконец, последнее — линию снизу.
Необязательные установки
Во всех предыдущих примерах для вставки виджета в таблицу использовалась функция gtk_table_attach_defaults(). Если хотите получить больше свободы, вызовите функцию gtk__table_attach () и измените значения установок по умолчанию. Обе эти функции используют одни и те же аргументы и в том же самом порядке, за исключением того, что функция gtk_table_attach () требует еще четыре дополнительных аргумента. Фактически есть только одна функция, ибо gtk_table_attach_def aults () вызывает функцию gtk_table_attach () следующим образом:
gtk_table_attach(table, widget, left_attach, right_attach,
top_attach, bottom_attach, GTKJEXPAND|GTK_FILL,/*xoptions♦/
GTK_EXPAND|GTK_FILL,/*yoptions*/
0f/*xpadding*/
0);/*ypadding*/
Последние два аргумента определяют значения горизонтального и вертикального заполнения — количество пикселов, которое определяет либо ширину, либо высоту границы вокруг виджета. Указанное число пикселов добавляется к обеим сторонам виджета. Например, если задано значение 5, то полный размер увеличивается на 10.
xoptions и yoptions — это флаги, которые инструктируют виджет, каким образом располагаться в ячейке таблицы и выбирать свои размеры. Значения этих опций перечислены в табл. 4.1. Как видно из списка аргументов функции gtk_table_attach (), с помощью флагов можно заставить виджет вести себя по-разному в вертикальном и горизонтальном направлениях. Когда эти флаги используются совместно с заполнением, позиционированием сетки таблицы и установкой однородности, можно получить очень большое число комбинаций для конфигурирования изображения виджета.
Таблица 4.1. Значения опций привязки таблицы
Значение
Описание
0
Виджет не меняет размер, который устанавливается равным минимальному. Если ячейка или ячейки, содержащие этот виджет, больше по размеру, виджет центрируется.
GTK_FILL
Виджет заполняет всю ячейку или ячейки, в которых он находится. Изменение размеров окна приводит к изменению размеров виджета.
GTK_SHRINK
Если ячейка или ячейки, содержащие виджет, имеют размеры меньшие, чем минимальные размеры виджета, он сжимается до размеров ячейки.
GTK_EXPANK
Это значение заставляет таблицу увеличить свои размеры для заполнения всего свободного пространства в окне вокруг нее.
Приведенная ниже программа демонстрирует работу этих установок:
/** opset.с **/
Iinclude <gnome.h> 3
GtkWidget *makeTable();
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
9 10 tdefine HOMOGENEOUS FALSE
tdefine X_MARGIN 0
Idefine Y MARGIN 0
13
struct {
gint setting;
gchar *text;
} op[] = {
{ 0, "O" },
{ GTKEXPAND, "Ex" },
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71.
72
73
74
{ GTK_FILL, "Fi" },
{ GTK_SHRINK, "Sh" },
{ GTK_FILL | GTK_EXPANDr "FiEx" },
{ GTK_SHRINK | GTK_EXPAND, "ShEx" },
{ GTK_FILL | GTK_SHRINKr "FiSh" },
{ GTK_SHRINK | GTK_FILL | GTK_EXPAND, "ShFiEx" } }?
int main(int argc,char *argv[])
{
GtkWidget *window;
GtkWidget *table;
gnome_init("opset","1.0",argc,argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_signal_connect(GTK_OBJECT(window), "delete_event", GTK_SIGNAL_FUNC(eventDelete), NULL);
gtk_signal_connect(GTK_OBJECT(window), "destroy", GTK_SIGNAL_FUNC(eventDestroy), NULL);
table = makeTable();
gtk_container_add(GTK CONTAINER(window),table);
gtk_widget_show(window);
gtk_main();
exit(0);
}
GtkWidget *makeTable() { int r;
int c;
int index;
GtkWidget *table;
GtkWidget *button;
table = gtk_table_new(2,4,HOMOGENEOUS); gtk_widget_show(table);
for(r=0; r<2; r++) {
for(c=0; c<4; C++) { index = (r * 4) + c; button = gtk buttonnewwithlabel( op[index].text);
gtk_table_attach(GTKJTABLE(table),button, c,c+l,r,r+l, op[index].setting, op[index].setting, XMARGIN, YMARGIN);
gtk_widget_show(button);
}
}
return(table);
757677757677}
75
76
77
75
76
77
gint eventDelete(GtkWidget *widget, GdkEvent *event,gpointer data) {
78return(FALSE);
79 }
80 gint eventDestroy(GtkWidget *widget,
81GdkEvent *event,gpointer data) {
82gtk_main_quit();
83return(O);
84 }
Рисунок 4.20. Неоднородное окно при увеличении его размеровРисунок 4.20. Неоднородное окно при увеличении его размеровСтроки c 10 по И определяют, является ли таблица однородной, и ширину заполнения вокруг виджетов. Массив структур, объявленный в строках с 14 по 25, содержит все возможные комбинации значений опций, а также текст на метках для каждой из кнопок. В строке 57 создается таблица 2x4 для поддержки всех виджетов, а цикл, который начинается со строк 60 и 61, создает и вставляет кнопки в ячейки. На рис. 4.19 показан вид окна после запуска программы. На рис. 4.20 показано то же окно после изменения его размеров с помощью мыши.
Рисунок 4.20. Неоднородное окно при увеличении его размеров
Рисунок 4.20. Неоднородное окно при увеличении его размеров
ср set
Ео[ Exj Fi Sh| Ex|shExjnSh ShFiEx
Рисунок 4.19. Неоднородное окно с его минимальными размерами
Все виджеты, созданные с помощью опции GTKFILL (обозначенные частицей "Fi" в своем названии), увеличили свои размеры до размеров полной ячейки. Опция GTKEXPAND (кнопки с "Ех" в названии) не привела к увеличению размеров ее виджетов, поскольку GTK EXPAND — это инструкция для таблицы, а не для виджета.
Во всех приведенных примерах применяются одни и те же правила как к горизонтальным, так и к вертикальным компонентам, создающим интервалы между виджетами и размеры виджетов. Однако, используя два аргумента, можно установить собственные опции для каждого направления. Окно можно сделать однородным, заменив строку 10 следующей строкой:
♦define HOMOGENEOUS TRUE
Полученное в результате этого изменения окно, все ячейки которого имеют одинаковые размеры, показано на рис. 4.21. При изменении размеров окна с помощью мыши все ячейки увеличивают свои размеры на одну и ту же величину, как показано на рис. 4.22.
Рисунок 4.21. Однородное окно с его минимальными размерамиРисунок 4.21. Однородное окно с его минимальными размерамиРисунок 4.22. Однородное окно при увеличении его размеровРисунок 4.22. Однородное окно при увеличении его размеров
Рисунок 4.21. Однородное окно с его минимальными размерами
Рисунок 4.21. Однородное окно с его минимальными размерами
Рисунок 4.22. Однородное окно при увеличении его размеров
Рисунок 4.22. Однородное окно при увеличении его размеров
Два последних аргумента используются для задания заполнения вокруг виджета. Окно, показанное на рис. 4.23, можно получить, заменив строки 10-12 следующими:
♦define HOMOGENEOUS FALSE
♦define X_MARGIN 5
♦define Y MARGIN 10
К каждому виджету добавляется по 5 пикселов справа и слева и по 10 пикселов сверху и снизу. Это означает, что виджеты теперь отделены один от другого 20-ю пикселами по вертикали (по 10 для каждого виджета) и 10-ю пикселами от верхнего и нижнего края окна. Полученное в результате этого окно показано на рис. 4.23. При изменении размеров окна оно будет выглядеть так, как показано на рис. 4.24. Несмотря ни на увеличение, ни на уменьшение размеров окна, виджеты все равно сохраняют между собой заданную дистанцию.
Рисунок 4.23. Неоднородное окноРисунок 4.24. Неоднородное окнос интерваламис интервалами при увеличении его размеровРисунок 4.23. Неоднородное окноРисунок 4.24. Неоднородное окнос интерваламис интервалами при увеличении его размеров
Рисунок 4.23. Неоднородное окноРисунок 4.24. Неоднородное окно
с интерваламис интервалами при увеличении его размеров
Рисунок 4.23. Неоднородное окноРисунок 4.24. Неоднородное окно
с интерваламис интервалами при увеличении его размеров
Перекрывающиеся виджеты
Если два каких-либо виджета расположены в одном и том же месте, то один из виджетов перекрывает другой. Порядок, в котором виджеты включались в таблицу, определяет, какой из виджетов находится сверху, а именно: виджет, добавленный первым, остается наверху. Это свойство может быть и не очень существенно для разработки программ, но, тем не менее, вы все равно должны знать о его существовании, а если вдруг один из виджетов отсутствует, вы сможете догадаться, куда он пропал. Следующая программа демонстрирует перекрытие виджетов:
/** overlap.с **/
♦include <gnome.h> 3
GtkWidget *makeTable();
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
9
int main(int argc,char *argv[]) И {
GtkWidget *window;
GtkWidget *table;
14
gnome_init("overlap", "1.0",argc,argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_signal_connect(GTK_OBJECT(window),
"delete_event",
GTK_SIGNAL_FUNC(eventDelete),
NULL);•
gtk_signal_connect(GTKOBJECT(window),
"destroy",
GTK_SIGNAL_FUNC(eventDestroy),
NULL);
25
table = makeTableO;
gtk_container_add(GTK_CONTAINER(window),table);
gtk_widget_show(window);
gtk_main();
exit(0);
}
GtkWidget *makeTable() {
GtkWidget *table;
GtkWidget *button;
35
table = gtk_table_new(5,4,TRUE);
37gtk_widget_show(table);
38
39 button = gtk_button_new_with_label("1,2,1,2");
40gtktable_attach_defaults(GTK_TABLE(table),button,
411,2,1,2);
42gtk_widget_show(button);
43
44button = gtk_button_new_with_label("0,2,0,2");
45gtk_table_attach_defaults(GTK_TABLE(table),button,
460,2,0,2);
47gtk_widget_show(button);
48
49 button = gtk_button_new_with_label("1,5,3,4");
50gtk_table_attach_defaults(GTK_TABLE(table),button,
511,5,3,4);
52gtk_widget_show(button);
53
54button = gtk_button_new_with_label("3,4,0,5");
55gtk__table_attach_defaults(GTK_TABLE(table),button,
563,4,0,5);
gtk_widget_show(button);
58
return(table);
}
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data) {
return(FALSE);
}
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data) {
gtk_main_quit();
return(0);
}
3,4,0,53,4,0,51,5,3,41,5,3,4Рисунок 4.25.Перекрывающиеся кнопкиРисунок 4.25.Перекрывающиеся кнопкиЭта программа создает таблицу 5x4 и помещает в нее четыре кнопки, как показано на рис. 4.25. В верхнем левом углу меньшая кнопка расположена поверх большей. Меньшая кнопка находится наверху потому, что она была вставлена в таблицу раньше. Если бы они были включены в таблицу в обратном порядке, меньшая кнопка была бы не видна. Две кнопки в нижнем правом углу пересекаются; но более широкая кнопка была вставлена раньше, поэтому она располагается поверх другой.
3,4,0,5
3,4,0,5
1,5,3,4
1,5,3,4
Рисунок 4.25.
Перекрывающиеся кнопки
Рисунок 4.25.
Перекрывающиеся кнопки
Совместное использование ящиков и таблиц
Ящики, таблицы и другие виджеты можно без всяких ограничений использовать совместно. Вы можете иметь ящики виджетов, хранящиеся внутри таблиц, которые, в свою очередь, могут быть вставлены в другие ящики и виджеты. Преимуществом совместного использования ящиков и таблиц является то, что результирующий уровень (комбинация ящиков и таблиц) может иметь свои собственные правила размещения и изменения размеров, позволяя вам располагать в нем виджеты так, как вы хотите.
Следующая программа демонстрирует использование вложенных ящиков и таблиц на примере создания окна, содержащего составные виджеты:
/*♦ collection.с ♦*/
linclude <gnome.h>
3
GtkWidget *makeTable();
GtkWidget *makeCheckButtons();
GtkWidget *makeTextEntry();
GtkWidget *makeButtonBox();
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent ♦event,gpointer data);
12
int main(int argc,char *argv[]).
{
GtkWidget *window;
GtkWidget *table;
17
gnome_init("collection","1.0",argc,argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtks ignal_connect(GTK_OBJECT(window),
"delete_event",
GTK_SIGNAL_FUNC(eventDelete),
NULL);
gtk_signal_connect(GTK_OBJECT(window)r
"destroy",
GTK_SIGNAL_FUNC(eventDestroy),
NULL);
28
table = makeTable();
gtk_container_add(GTK_CONTAINER(window),table);
gtk_widget_show(window);
gtk_main(); .
exit(0);
}
GtkWidget *makeTable() {
GtkWidget*table;
GtkWidget*checkButtons;
GtkWidget*textEntry;
GtkWidget*buttonBox;
40
table = gtktable new(2,2,FALSE);
gtk_widget show(table);
43
textEntry = makeTextEntry();
gtk_table_attach(GTK_TABLE(table),textEntry, 0,1,0,1, 0, 0, 5, 5);
gtk_widget_show(textEntry);
checkButtons = makeCheckButtons();
gtk_table_attach(GTK_TABLE(table),checkButtons, 1,2,0,1, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 10, 0);
gtk_widget_show(checkButtons);
buttonBox = makeButtonBox();
gtk_table_attach(GTK_TABLE(table),buttonBox, 0,2,1,2, GTK_EXPAND | GTK_FILL, 0, 0, 8);
gtk_widget_show(buttonBox);
return(table);
}
GtkWidget *makeCheckButtons()
{
GtkWidget *vbox;
GtkWidget *check;
vbox = gtk_vbox_new(FALSE, 0);
check = gtk_check_button_new_with_label("Get Mad"); gtk_box_pack_start(GTK_BOX(vbox),check,FALSE,FALSE,0); gtkwidgetshow(check);
check = gtk_check_button_new_with_label("Get Even"); gtk_box_pack_start(GTK_BOX(vbox),check,FALSE,FALSE,0); gtk_widget_show(check);■
check = gtk_check_button_new_with_label("Get Down"); gtk_box_pack_start(GTKBOX(vbox),check,FALSE,FALSE,0); gtk_widget_show(check);
check = gtk_check_button_new_with_label( "Reverse Neutron Polarity");
gtk_box_pack_start(GTK_BOX(vbox),check,FALSE,FALSE,0); gtk_widget_show(check);
return(vbox);
}
GtkWidget *makeTextEntry()
{
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
GtkWidget *vbox;
102
GtkWidget *label
103GtkWidget *text;
104
105vbox = gtk_vbox_new(FALSE,0);
106
107label = gtk_label_new("Enter destinationplanet");
108gtk_box_pack_start(GTK_BOX(vbox),label,FALSE,FALSE,0);
109gtk_widget_show(label);
110
111text = gtk_entry_new_with_max_length(32);
112gtk_box_pack_start(GTK_BOX(vbox),text,FALSE,FALSE,0);
113gtk_widget_show(text);
114
115return(vbox);
116 }
117 GtkWidget *makeButtonBox()
118 {
119GtkWidget *hbox;
120GtkWidget *button;
121
122hbox = gtk_hbox_new(TRUE,0);
123
124button = gtk_button_new_with_label("OK");
125gtk_box_pack_start(GTK_BOX(hbox),button,FALSE,FALSE,0);
126gtk_widget_show(button);
127
128button = gtk_button_new_with_label("Apply");
129gtk_box_pack_start(GTK_BOX(hbox),button,FALSE,FALSE,0);
130gtk_widget_show(button);
131
132button = gtk_button_new_with_label("Cancel");
133gtkboxpackstart(GTKBOX(hbox),button,FALSE,FALSE,0);
134gtk_widget_show(button);
135
136return(hbox);
137 }
138 gint eventDelete(GtkWidget *widget,
139GdkEvent *event,gpointer data) {
140 return(FALSE);
141 }
142 gint eventDestroy(GtkWidget *widget,
143GdkEvent *event,gpointer data) {
144gtk_main_quit();
145return(0);
146 }
Рисунок 4.26.Виджеты, таблицы и ящики внутри других таблиц и ящиковРисунок 4.26.Виджеты, таблицы и ящики внутри других таблиц и ящиковВсе окно целиком располагается в таблице, созданной в строке 41. Это таблица 2x2, содержащая три виджета. Окно показано на рис. 4.26. Каждый виджет привязан к таблице, и для создания этих виджетов используются три функции.
Рисунок 4.26.
Виджеты, таблицы и ящики внутри других таблиц и ящиков
Рисунок 4.26.
Виджеты, таблицы и ящики внутри других таблиц и ящиков
Функция makeCheckButtons (), которая начинается со строки 73, создает вертикальный ящик и упаковывает в него четыре контрольные кнопки. Функция makeTextEntry (), которая начинается со строки 99, создает вертикальный ящик и включает в него метку (надпись) и виджет с полем для
ввода текста. Функция makeButtonBox () создает горизонтальный ящик и подсоединяет к нему три кнопки. Этот последний ящик создается однородным, так что кнопки сами равномерно располагают себя по низу окна.
В строках с 44 по 51 создается виджет с полем для ввода текста и привязывается к ячейке в верхнем левом углу. Этот виджет создается путем вызова функции makeTextEntry (). Опции привязки не установлены для расширения и заполнения, следовательно, виджет сохраняет свои размеры, что бы ни случилось с таблицей, в которой он содержится. Кроме того, вокруг всего виджета установлена граница шириной 5 пикселов.
В строках с 53 по 60 создаются виджеты с контрольными панельками, и затем виджеты привязываются к верхнему правому углу. Виджеты создаются путем вызова функции makeCheckButtons () и подключаются с использованием опций GTK_EXPAND и GTK_FILL, что дает тот же самый результат, что и обращение к функции gtk_table_attach_def aults (), за исключением добавления слева и справа границы шириной 10 пикселов.
В строках с 62 по 69 создается виджет, содержащий три кнопки, и привязывается к таблице таким образом, что он занимает две ячейки в нижней части таблицы. Виджет создан с возможностью расширения и заполнения, но только вдоль оси х. Кроме того, установлена граница над и под виджетом шириной 8 пикселов.
Тот факт, что все является виджетом, очень ценен для программиста. Обратите внимание, что объявления в строках 37, 38 и 39 определяют каждый из объектов, содержащихся в таблице, как GtkWidget. При таком объявлении функция makeTable () не обязательно должна знать, какой именно виджет будет в ней содержаться. Вместо этого она просто получает указатель на объект из GtkWidget и добавляет этот объект в таблицу. Таким виджетом может быть другая таблица, ящик, кнопка, метка или один из других доступных виджетов. Это очень важное свойство, которое не только упрощает кодирование, но и позволяет вам делать изменения одной части, не беспокоясь о влиянии этих изменений на другие части окна. Несомненно, если вы изменяете какие-то размеры, вам, может быть, придется сделать некоторые изменения в расположении виджетов, но не придется переписывать куски программы из-за несовместимости типов.
Выводы
В этой главе рассмотрены пути добавления виджетов в окна. Вы узнали, что таблицы и ящики могут быть упакованы с виджетами для быстрого размещения диалогового окна. Кроме того, автоматизация при размещении виджетов в диалоговом окне и задании интервалов между ними высвобождает программиста для решения более важных задач.
В этой главе вы также узнали следующее:
у Существует два типа ящиков — вертикальный и горизонтальный.
Виджеты могут быть добавлены в ящик с любого конца.
> Таблица — это сетка, к которой могут быть привязаны виджеты.
Любой виджет может быть упакован в ящики или таблицы, включающие другие ящики и таблицы.
Тем не менее, это всего лишь введение в использование виджетов. Например, существует еще несколько вариантов упаковки виджетов в окне. Существуют также некоторые специализированные возможности, так например, можно расположить виджет в окне, указав его координаты. В главе 5 рассмотрены некоторые специализированные контейнеры виджетов, которые могут использоваться совместно или вместо таблиц и ящиков.
главаВиджеты в качестве
5контейнеров другим
виджетов
В этой главе
& Размещение виджетов по заданным координатам х и у ^ Добавление к большому окну полос прокрутки Ш Установка виджета, следующего своим собственным правилам изменения размеров вместо правил его контейнера
$> Конфигурирование виджетов, сохраняющих соотношение высоты и ширины при изменении размеров их контейнера
I/ Группировка виджетов по расположению и путем помещения их в рамку
Эта глава рассказывает о контроле за положением виджета, его размерами и о его реакции на изменение размеров окна. Для этого существует несколько виджетов, которые могут содержать в себе другие виджеты и влиять на их поведение. Каждый из них имеет свои особенности и специальные возможности и может быть использован для создания различных вариантов размещения виджетов.
Фиксированный контейнер
Вы можете использовать фиксированный контейнер (fixed container) для размещения в нем виджетов по заданным координатам х и у. В приведенном ниже примере создаются три кнопки и помещаются в фиксированный контейнер. Кнопки первоначально размещаются по координатам (100,100), т.е. верхний левый угол каждой кнопки располагается на 100 пикселов правее и на 100 пикселов ниже левого верхнего угла контейнера. Метка каждой кнопки содержит координаты размещения х и у. Если щелкнуть на кнопке, она перемещается в другое место, меняя координаты х и у.
/** fixed.с **/
linclude <gnome.h>
3
typedef struct {
GtkWidget *fixed;
GtkWidget *button;
} ButtonMover;
8
GtkWidget *makeFixedContainer();
gint eventDelete(GtkWidget *widget,
GdkEvent ♦event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
void buttonclick(GtkWidget *widget,ButtonMover *bm);
♦define WIDTH 400
♦define HEIGHT 300
int main(int argc,char *argv[]) {
GtkWidget *window;
GtkWidget *fixed;
gnome_init("fixed","1.0",argc,argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size(GTKWINDOW(window), WIDTH,HEIGHT);
gtk_signal_connect(GTK_OBJECT(window), "delete_event", GTK SIGNAL_FUNC(eventDelete), NULL);
gtk_signal_connect(GTK_OBJECT(window), "destroy", GTK_SIGNAL_FUNC(eventDestroy), NULL);
fixed = makeFixedContainer();
gtk_container_add(GTK_CONTAINER(window),fixed); gtk_widget_show(window);
gtk_main();
exit(0);
}
GtkWidget *makeFixedContainer() { int i;
GtkWidget *fixed;
static ButtonMover bm[3J;
fixed = gtk_fixed_new();
gtk_widget_show(fixed);
for(i=0; i<3; i++) { bm[i).fixed = fixed; bm[i].button = gtk_button_new_with_label( "(100,100)");
gtk_signal_connect(GTK_OBJECT(bm[i].button), "clicked", GTK_SIGNAL_FUNC(buttonClick), &bm[i]);
gtk_widget_show(bm[i].button);
gtkfixedput(GTK_FIXED(fixed),bm[i].button, 100,100);
}
return(fixed);
}
void buttonclick(GtkWidget *widget,ButtonMover *bm) {
gchar labelstring[80];
GtkWidget *label;
71727172gint х * (mt) (random () % WIDTH); gint у * (int)(random() % HEIGHT);
71
72
71
72
73sprintf(labelstring,"(%d,%d)",x,у);
74label = GTK_WIDGET(GTK_BUTTON(bm->button)->child);
75gtk_label_set_text(GTK_LABEL(label),labelstring);
76gtk_fixed_move(GTK_FIXED(bm->fixed),bm->button,x,y);
77 }
78 gint eventDelete(GtkWidget *widget,
79GdkEvent ♦event,gpointer data) {
80return(FALSE);
81 }
82 gint eventDestroy(GtkWidget *widget, ,
83GdkEvent *event,gpointer data) {
84gtk_main_quit();
85return(O);
86 }
Функция makeFixedContainer (), которая начинается co строки 44, создает фиксированный контейнер и добавляет в него три кнопки. Сам контейнер создается путем вызова функции gtk__f ixed_new() в строке 49.
Фиксированный контейнер не имеет предопределенного размера. Наоборот, он автоматически меняет свои размеры, удерживая положение всех добавленных в него виджетов. В предыдущем примере в строке 26 с помощью функции gtk_window_set_default_size() было установлено окно фиксированного размера, содержащее контейнер, что вынуждает окно сохранять свои размеры, несмотря ни на что. Если убрать эту функцию из текста программы, полученное окно будет маленьким. При передвижении кнопок из одного места в другое размеры контейнера увеличиваются, заставляя окно увеличивать свои размеры.
В цикле, который начинается со строки 52, создаются три кнопки и добавляются в контейнер. Обращение к функции gtk_fixed_put() вставляет каждую кнопку в контейнер в точку с координатами (100,100). В строке 4 определена структура ButtonMover, которая объявлена в строке 47 в виде массива из трех элементов — по одному для каждой кнопки. В структуре хранятся указатели на кнопку и контейнер, которые могут передаваться функции обратного вызова. Для всех трех кнопок используется функция обратного вызова buttonclick().
Функция обратного вызова buttonClick (), начинающаяся со строки 66, перемещает
Рисунок 5.1. Кнопки располагаются в фиксированном контейнереРисунок 5.1. Кнопки располагаются в фиксированном контейнеревыбранную кнопку из одного места в другое. В строках 71 и 72 для установки нового набора значений координат х и у используется генератор случайных чисел. В строках 73 и 74 устанавливается ASCII-представление этих значений в виде метки для кнопки. Для отображения текста кнопка содержит помеченный виджет, так что в строке 75 вызывается функция gtk_label__set_text (), меняющая строку, отображаемую кнопкой. В строке 76 производится вызов функция gtk_f ixed_move() с новыми координатами, что меняет расположение кнопки. После нескольких щелчков, выполняемых на кнопках, экран будет выглядеть примерно так, как
Рисунок 5.1. Кнопки располагаются в фиксированном контейнере
Рисунок 5.1. Кнопки располагаются в фиксированном контейнере
Минимальный размер фиксированного контейнера очень легко вычислить. Его ширина равна максимальному расстоянию от левой стороны контейнера до правой стороны каждого виджета. Высота равна максимальному расстоянию от вершины контейнера до низа каждого виджета.
Виджеты могут быть перемещены из одного места в другое. Вы можете это сделать независимо от того, активно окно или нет. Обращение к функции gtk_f ixed_move(), перемещающей виджеты, выполняется с теми же аргументами, что и обращение к функции gtk_f ixed_put (), добавляющей виджет. Например, если виджет button уже добавлен в фиксированный контейнер, следующий вызов перемещает его в другое место:
gtk_fixed_move(GTK_FIXED(fixed),button,25,25);
Настроенный контейнер
Такой контейнер (alignment container) можно использовать для размещения в нем одного виджета и получения возможности контролировать его положение и размеры. Содержащийся в таком контейнере виджет подгоняет свое положение и размеры до текущих размеров и формы настроенного контейнера. Виджет располагается на некотором расстоянии, определяемом в процентах, от вершины и на некотором расстоянии, также определяемом в процентах, от левой стороны. Кроме того, размеры виджета составляют определенный процент от ширины и высоты контейнера.
В приведенном ниже примере программы виджет GtkButton центрируется в настроенном контейнере:
/** alignment.с **/
linclude <gnome.h>
.
GtkWidget *makeAlignment();
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
9
int main(int argc,char *argv[])
И {
GtkWidget *window;
GtkWidget *alignment;
14
gnome_init("alignment","1.0",argc,argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size(GTK_WINDOW(window),
200,200);
gtk_s ignal_connect(GTK_OBJECT(window),
"delete_event",
GTK_SIGNAL_FUNC(eventDelete),
NULL);
gtk_signal_connect(GTKOBJECT(window),
"destroy",
GTK_SIGNAL_FUNC(eventDestroy),
NULL);
27
alignment = makeAlignment();
29
gtk_containeradd(GTKCONTAINER(window),alignment);
gtk_widget_show(window);
gtk_main();
exit(O);
}
GtkWidget «makeAlignment() {
GtkWidget «alignment;
GtkWidget «button;
gfloatxalign=0.5;'
gfloatyalign=0.5;
gfloatxscale=0.8;
gfloatyscale=0.8;
42
alignment = gtk_alignment_new(xalign,yalign,
xscale,yscale);
gtk_widget_show(alignment);
button = gtk_button_new_with_label("Button");
gtk_widget_show(button);
gtk_container add(GTK_CONTAINER(alignment),button);
49
return(alignment);
}
gint eventDelete(GtkWidget «widget,
GdkEvent «event,gpointer data) {
return(FALSE);
}
gint eventDestroy(GtkWidget «widget,
GdkEvent «event,gpointer data) {
gtk_main_quit();
return(0);
}
Функция makeAlignment ( ), начинающаяся в строке 35, создает настроенный контейнер с виджетом GtkButton. Контейнер создается по вызову функции gtk_alignment_new() в строке 43. Настроенный контейнер может содержать только один виджет, а значения, которые определяют его размер и положение, устанавливаются при создании контейнера. Значения xalign и yalign определяют положение виджета относительно размеров и формы контейнера. Значения xscale и yscale определяют размеры виджета относительно размеров контейнера.
Значения, приведенные в строках 38-41, совместно с первоначальными размерами окна, устанавливаемыми в строке 17, вызывают появление окна, показанного на рис. 5.2. Кнопка сама изменяет свои размеры, приспосабливаясь к размерам своего контейнера. На рис. 5.3 показано то же самое окно после изменения его размеров с помощью мыши.
ПРИМЕЧАНИЕ НАУЧНОГО РЕДАКТОРА
Далее по тексту термин GtkAlignment определяет настроенный в среде GTK контейнер.
Размены xscale и yscale — это числа с плавающей запятой, лежащие в диапазоне от 0.0 до 1.0. Они определяют размеры виджета в долях от размера контейнера. В приведенном примере обе величины равны 0.8, т.е. кнопка занимает 80% как от высоты, так и от ширины контейнера. Если обе величины равны 1.0, кнопка занимает весь контейнер.
Два настраиваемых числа xalign и yalign — это числа с плавающей запятой, меняющиеся в диапазоне от 0.0 до 1.0 и задающие протяженность вдоль контейнера в долях размеров. На рис. 5.2 кнопка центрирована, так как обе величины равны 0.5. При установке значений xalign и yalign равными 0.0 окно будет выглядеть так, как показано
на рис. 5.4. Установив значения xalign и yalign равными 1.0, получим окно, как на рис. 5.5.
Рисунок 5.2.Кнопка, центрированная в контейнере GtkAlignmentРисунок 5.2.Кнопка, центрированная в контейнере GtkAlignment: Button: ButtonРисунок 5.3.
Рисунок 5.2.
Кнопка, центрированная в контейнере GtkAlignment
Рисунок 5.2.
Кнопка, центрированная в контейнере GtkAlignment
: Button
: Button
Рисунок 5.4.Кнопка в верхнем левом углу контейнера GtkAlignmentРисунок 5.4.Кнопка в верхнем левом углу контейнера GtkAlignmentРисунок 5.5.Кнопка в нижнем правом углу контейнера GtkAlignmentРисунок 5.5.Кнопка в нижнем правом углу контейнера GtkAlignmentИзменение размеров контейнера GtkAlignment вызывает изменение размеров находящегося в нем виджета
Рисунок 5.4.
Кнопка в верхнем левом углу контейнера GtkAlignment
Рисунок 5.4.
Кнопка в верхнем левом углу контейнера GtkAlignment
Рисунок 5.5.
Кнопка в нижнем правом углу контейнера GtkAlignment
Рисунок 5.5.
Кнопка в нижнем правом углу контейнера GtkAlignment
Алгоритм, который используется для вычисления действительного положения виджета по значениям xalign и yalign, никогда не помещает какую-либо часть виджета за пределами контейнера. Так как размеры виджета определяются в первую очередь, высота и ширина могут быть вычислены в процессе позиционирования. На рис. 5.6 показано, каким образом можно выполнить вертикальное позиционирование виджета. Пунктирная линия представляет все возможные положения центра виджета в вертикальном направлении. Крайние положения соответствуют центру виджета, находящемуся на верхней или нижней сторонах контейнера. Для крайних положений используются конечные точки линии, применяемой для позиционирования виджета. Действительное положение виджета (его центра) по вертикали — это расстояние от верхнего конца этой линии до центра в процентах от всей длины линии. Этот же метод используется при горизонтальном позиционировании, только в этом случае расстояние измеряется от 0.0 до 1.0 слева направо.
Вы не связываетесь с настройкой при создании виджета, но всегда можете поменять ее путем вызова следующей функции:
gtk_alignment_new(GTK_ALIGNMENT(alignment),
xalign,yalign, xscale,yscale);
Первый аргумент — это настраиваемый контейнер, получающий новые значения, а четыре значения с плавающей запятой уже использовались для функции gtk_alignment_new() в приведенной программе.
Рисунок 5.6.
Воображаемая линия для размещения виджетов в контейнере
GtkAlignment
Обрамляющий контейнер
Такой контейнер (frame container) содержит единственный виджет, окруженный прямоугольной рамкой. Нарисованный прямоугольник может иметь метку, расположенную вверху. Существует несколько типов линий, которыми можно воспользоваться при рисовании рамки. Всего их пять, если считать тот случай, когда прямоугольник вообще от
сутствует. В следующем примере для демонстрации опций, используемых для отображения обрамляющих линий, применяется пять рамок вокруг меток (надписей). Полученное окно представлено на рис. 5.7.
/** framel.c **/
#include <gnome.h>
3
GtkWidget *makeFrames();
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
GTK_SHADOW_NONEj CmCSHADOWJNGTK SHADOW OUT|GTK_SHADOW_ETCHEDJN :GTK_SHADOW_ETCHED_OUTGTK_SHADOW_NONEj CmCSHADOWJNGTK SHADOW OUT|GTK_SHADOW_ETCHEDJN :GTK_SHADOW_ETCHED_OUTРисунок 5.7.Пять типов рамокРисунок 5.7.Пять типов рамок9
GTK_SHADOW_NONE
j CmCSHADOWJN
GTK SHADOW OUT|
GTK_SHADOW_ETCHEDJN :
GTK_SHADOW_ETCHED_OUT
GTK_SHADOW_NONE
j CmCSHADOWJN
GTK SHADOW OUT|
GTK_SHADOW_ETCHEDJN :
GTK_SHADOW_ETCHED_OUT
Рисунок 5.7.
Пять типов рамок
Рисунок 5.7.
Пять типов рамок
struct {
gchar *typeName;
GtkShadowType type;
13 } shadow!] = {
14{"GTK_SHADOW_NONE", GTK_SHADOW_NONE },
15{"GTK_SHADOW_IN", GTK_SHADOW_IN },
16{"GTK_SHADOW_OUT", GTK_SHADOW_OUT },
17{"GTK_SHADOW_ETCHED_IN", GTK_SHADOW_ETCHED_IN},
18{"GTK_SHADOW_ETCHED_OUT", GTK_SHADOW_ETCHED_OUT }
19 };
20
21 int main(int argc,char *argv[J)
22 {
23GtkWidget *window;
24GtkWidget *frame;
25
26gnome_init("framel","1.0",argc,argv);
27window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
28gtk_container_set_border_width(
29GTK_CONTAINER(window),25);
30gtk_signal_connect(GTK_OBJECT(window),
31"delete_event",
32GTK_SIGNAL_FUNC(eventDelete),
33NULL);
34gtk_signal_connect(GTK_OBJECT(window),
35"destroy",
36GTK_SIGNAL_FUNC(eventDestroy),
37NULL);
38
39frame = makeFrames();
40gtk_container_add(GTK_CONTAINER(window),frame);
41gtk_widget_show(window);
42gtk_main();
43exit(0);
44 }
GtkWidget *makeFrames() {
int i;
GtkWidget*box;
GtkWidget*frame;
49GtkWidget*label;
50
51box = gtk_vbox_new(FALSE,10);
52gtk_widget_show(box);
53
54for(i=0; i<5; i++) {
55frame = gtk_frame_new(NULL);
56gtk_widget_show(frame);
57gtkframesetshadowtype(GTK_FRAME(frame),
58shadow!i].type);
59gtk_container_add(GTK_CONTAINER(box),frame);
60label = gtk_label_new(shadow!i].typeName);
61gtk_widget_show(label);
62gtkcontaineradd(GTK_CONTAINER(frame),label);
63}
64
65return(box);
66 }
67 gint eventDelete(GtkWidget *widget,
68GdkEvent *event,gpointer data) {
69 return(FALSE);
70 }
71 gint eventDestroy(GtkWidget *widget, 72GdkEvent *event,gpointer data) {
73gtk_main_quit();
74return(O);
75 }
Массив shadow, объявленный в строках с 10 по 18, содержит имена и численные значения, представляющие каждый из методов обрисовки рамки. В цикле используется структура для создания набора обрамленных меток (надписей).
Функция makeFrames (), создающая набор рамок, начинается со строки 45. Поскольку в список будет включен более, чем один виджет, то в строке 51 создается виджет в виде прямоугольного контейнера и с метками внутри цикла упаковывается в строке 62.
Calculations j Calculate new average; л Calculate new median: j Calculate new maximumCalculations j Calculate new average; л Calculate new median: j Calculate new maximumРисунок 5.8.Тип рамки и положение метки (надписи), устанавливаемые по умолчаниюРисунок 5.8.Тип рамки и положение метки (надписи), устанавливаемые по умолчаниюЦикл, который начинается в строке 54, используется для создания всех типов линий применяемых рамок. В строках 55 и 57 создается и конфигурируется рамка. Обращение к функции gtk_f rame__set__shadow_type () указывает тип рамки. По умолчанию устанавливается тип GTK_SHADOW_ETCHED_IN. В строке 59 рамка добавляется в вертикальный ящик. В строках 60 и 61 создается метка (надпись) и вставляется в рамку.
Calculations j Calculate new average
; л Calculate new median
: j Calculate new maximum
Calculations j Calculate new average
; л Calculate new median
: j Calculate new maximum
Рисунок 5.8.
Тип рамки и положение метки (надписи), устанавливаемые по умолчанию
Рисунок 5.8.
Тип рамки и положение метки (надписи), устанавливаемые по умолчанию
Рамки могут использоваться просто для улучшения внешнего вида, но часто они применяются в диалоговом окне для группировки связанных виджетов. Приводимая ниже программа отображает окно, представленное на рис. 5.8.
/** frame2.с **/
Iinclude <gnome.h>
GtkWidget *makeFrame();
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
int main(int argc,char *argv[])
{
GtkWidget ♦window;
GtkWidget *frame;
14
15gnome_init("frame2","1.0",argc,argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_signal_connect(GTK_OBJECT(window),
"delete_event",
GTK_SIGNAL_FUNC(eventDelete),
NULL);
gtk_signal_connect(GTK_OBJECT(window),
"destroy",
GTK_SIGNAL_FUNC(eventDestroy),
NULL);
25
frame = makeFrame();
gtk_container_add(GTK_CONTAINER(window),frame);
gtk_widget_show(window);
gtk_main();
exit(0);
}
GtkWidget *makeFrame() {
GtkWidget*box;
GtkWidget*frame;
GtkWidget«button;
36
box = gtk_vbox_new(FALSE, 0);
gtk_widget_show(box);
39
button = gtk_check_button_new_with_label(
"Calculate new average");
gtk_widget_show(button);
gtk_container_add(GTKCONTAINER(box),button);
44
button = gtk_check_button_new_with_label(
"Calculate new median");
gtk_widget_show(button);
gtk_container_add(GTK_CONTAINER(box),button);
49
button = gtk_check_button_new_with_label(
"Calculate new maximum");
gtk_widget_show(button);
gtkcontaineradd(GTK_CONTAINER(box),button);
54
55frame = gtkframe_new("Calculations");
56gtk_widget_show(frame);
57gtk_container_set_border_width(GTK_CONTAINER(frame),
5815);
59gtk containeradd(GTKCONTAINER(frame),box);
60
61return(frame);
62 }
63 gint eventDelete(GtkWidget «widget,
64GdkEvent *event,gpointer data) {
65return(FALSE);
66 }
67 gint eventDestroy(GtkWidget «widget,
68GdkEvent *event,gpointer data) {
69gtk_main_quit();
70return(0);
71 }
Функция makeFrame (), которая начинается co строки 32, создает ящик, наполняет его Кнопками управления и окружает ящик рамкой. Кнопки создаются в строках с 40 по 53. Рамка с текстовой меткой создается в строке 55. По умолчанию метка располагается сверху и выравнивается по левому краю. Строка 57 указывает, что между ящиком и находящимся в нем контейнером располагается граница — рамка шириной 15 пикселов.
Вы можете установить положение метки на рамке путем вызова функции gtk_frame_set_label_align(). Метка, возникающая вверху рамки, выравнивается по левому краю (по умолчанию), по правому краю или по центру. Размещение характеризуется числом с плавающей запятой от 0.0, что соответствует выравниванию по левому краю, до 1.0, что соответствует выравниванию по правому краю. Используя значения между 0.0 и 1.0, можно располагать метку (надпись) между двумя крайними положениями. Например, при установке значения 0.5 метка центрируется. Для сдвига метки
Calculations\ J Calculate new average > j Calculate new median; J Calculate new maximumCalculations\ J Calculate new average > j Calculate new median; J Calculate new maximumРисунок 5.9.Изменение положения метки на рамкеРисунок 5.9.Изменение положения метки на рамкевправо, как показано на рис. 5.9, добавьте следующую строку после вызова функции gtk_frame_new() в строке 55:
Calculations
\ J Calculate new average > j Calculate new median
; J Calculate new maximum
Calculations
\ J Calculate new average > j Calculate new median
; J Calculate new maximum
Рисунок 5.9.
Изменение положения метки на рамке
Рисунок 5.9.
Изменение положения метки на рамке
gtk_frame_set_label_align(GTK_FRAME(frame), 1.0,0.0);
Первый аргумент — виджет рамки. Второй аргумент — xalign — установлен равным 1.0 для сдвига метки вправо. Третий аргумент называется yalign, не оказывает никакого влияния на внешний вид виджета.
Аспектный обрамляющий контейнер
Такой контейнер (aspect frame container) содержит в себе один виджет и сохраняет
постоянное отношение между его шириной и высотой независимо от изменения размеров окна. Упомянутый контейнер объединяет некоторые возможности двух предыдущих контейнеров. Как и обычный обрамляющий контейнер, он окружает виджет рамкой с меткой. И, как и в настроенном контейнере, вы можете задавать положение виджета внутри контейнера.
Рисунок 5.10.Кнопка внутри контейнера при отношении ширины к высоте как 2:1Рисунок 5.10.Кнопка внутри контейнера при отношении ширины к высоте как 2:1Для создания рамки такого виджета применяется линия типа GTK_SHADOW_ETCHED_IN, а метка всегда располагается с верхнего левого угла рамки. Приведенная ниже программа создает окно, показанное на рис. 5.10.
Рисунок 5.10.
Кнопка внутри контейнера при отношении ширины к высоте как 2:1
Рисунок 5.10.
Кнопка внутри контейнера при отношении ширины к высоте как 2:1
/** aspect.с **/
Iinclude <gnome.h>
GtkWidget *makeAspectFrame();
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
'
int main(int argc,char *argv[])
И <
GtkWidget *window;
GtkWidget *aspect;
14
gnome_init("aspect","1.0",argc,argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size(GTK_WINDOW(window),
200,200);
gtk_signal_connect(GTK_OBJECT(window),
"deleteevent",
GTK_SIGNAL_FUNC(eventDelete),
NULL);
gtk_signal_connect(GTK_OBJECT(window),
"destroy",
GTK_SIGNAL_FUNC(eventDestroy),
NULL);
27
aspect = makeAspectFrame();
29
gtk_container_add(GTK_CONTAINER(window),aspect);
gtk_widget_show(window);
gtk_main();
exit(O);
}
GtkWidget *makeAspectFrame() {
GtkWidget *aspect;
GtkWidget *button;
gfloat xalign = 0.5;
gfloat yalign = 0.5;
gfloat ratio = 2;
41
aspect = gtk_aspect_frame_new("AspectFrame",
xalign,yalign,
ratio,
FALSE);
gtk_widget_show{aspect);
gtk_container_set_border_width(GTK_CONTAINER(aspect),
10);
button = gtk_button_new_with_label("Button");
50gtk_widget_show(button);
51gtk_container_set_border_width(GTK_CONTAINER(button),
5210);
53gtk__container_add(GTK_CONTAINER(aspect),button);
54
return(aspect);
}
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data) {
return(FALSE);
}
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data) {
gtk_main_quit();
return(0);
}
Контейнер создается функцией makeAspectFrame (), которая начинается со строки 35. Обрамляющий контейнер конструируется в строке 42. Первый аргумент — метка, которая появляется вверху рамки. Второй и третий аргументы — xalign и yalign, они используются для задания положения виджета, находящегося в контейнере, и действуют так же, как и для настроенного виджета, описанного ранее. В этом примере оба значения равны 0.5, то есть виджет располагается по центру как в горизонтальном, так и в вертикальном направлениях.
Коэффициент ratio в строке 44 — это отношение ширины к высоте. Если необходимо, чтобы ширина виджета была в четыре раза больше его высоты, задайте значение 4/1. Если требуется, чтобы высота виджета в четыре раза превышала его ширину, используйте коэффициент 1/4. При значении коэффициента, равном 1, будет создан квадратный виджет, при значениях больше 1 — прямоугольник с шириной, превышающей высоту, при значениях меньше 1 — прямоугольник с высотой, превышающей ширину.
Последний аргумент в строке 45 устанавливается в значение TRUE, если необходимо, чтобы отношение сторон определялось по размерам виджета, и FALSE, если необходимо, чтобы значение коэффициента передавалось. То есть, если установить значение TRUE, значение аргумента, передаваемое функции, будет проигнорировано и будет браться соотношение ширины и высоты виджета. Каждый виджет имеет предпочтительные размеры, предполагающие соответствующий аспектный коэффициент.
В программе дважды вызывается функция gtk_container_set_border_width(): в строке 47 она вставляет 10 пикселов вокруг рамки, а в строке 51 — 10 пикселов между кнопкой и рамкой.
AspectFrameButton |AspectFrameButton |На рис. 5.10 показано окно так, как оно возникает впервые. Размеры окна и его форма определяются аспектным коэффициентом, требованиями к минимальным размерам кнопки и шириной окружающих граничных областей. Еслй растянуть окно в горизонтальном направлении и сжать в вертикальном, оно будет выглядеть примерно так, как показано на рис. 5.11. Если сузить окно, но увеличить высоту, оно будет выглядеть так, как показано на рис. 5.12. Размеры контейнера меняются, но отношение сторон виджета остается постоянным.
AspectFrame
Button |
AspectFrame
Button |
Рисунок 5.11.Рисунок 5.12.Растягивание контейнера по горизонтали Растягивание контейнера по вертикали сохраняет отношение сторон виджета сохраняет отношение сторон виджетаРисунок 5.11.Рисунок 5.12.Растягивание контейнера по горизонтали Растягивание контейнера по вертикали сохраняет отношение сторон виджета сохраняет отношение сторон виджета
Рисунок 5.11.Рисунок 5.12.
Растягивание контейнера по горизонтали Растягивание контейнера по вертикали сохраняет отношение сторон виджета сохраняет отношение сторон виджета
Рисунок 5.11.Рисунок 5.12.
Растягивание контейнера по горизонтали Растягивание контейнера по вертикали сохраняет отношение сторон виджета сохраняет отношение сторон виджета
Вы можете динамически изменить заданное ранее соотношение сторон. Для изменения одного или всех параметров, определяющих размеры, которые были установлены при создании аспектного обрамляющего контейнера, используется следующая функция:
gtk_aspect_frame_set(GTK_ASPECT_FRAME(aspect),
xalign,yalign, ratio,
FALSE);
Это изменяет все первоначальные установки за исключением метки (надписи) в рамке, но и ее можно изменить. Так как аспектный обрамляющий контейнер является расширением обрамляющего контейнера, то изменение метки можно произвести следующим образом:
gtkframe_set_label(GTK_FRAME(aspect),"New Label Text");
Контейнер с панелями
Такой контейнер (paned container) может содержать два виджета либо бок о бок, либо один над другим с желобом-разделителем между ними. С помощью мыши можно передвигать разделитель, меняя таким образом размеры каждого виджета, находящегося в контейнере. Кнопка на разделителе, с помощью которой можно переместить разделитель, называется манипулятором.
Приведенный далее пример демонстрирует горизонтальный контейнер с панелями и с текстовым виджетом в каждой из них, как показано на рис. 5.13. Каждый текстовый виджет содержит по одной строке текста, которая автоматически переносится на новую строку для заполнения всего виджета. Автоматический перенос на новую строку обозначен стрелкой в конце каждой строки. При перемещении манипулятора перемещается желоб- разделитель и изменяет размеры обоих виджетов, как показано на рис. 5.14.
The quick brown fox jumpe 3 : d on the leftovers. The qul ») ck brown fox jumped on th 3 ; e leftovers. The quick brow» \ n fox jumped on the leftove# • rs. The quick brown fox ju # i mped on the leftovers. The # ■ quick brown fox jumped on # : the leftovers. The quick br# • own fox jumped on the left # ; overs The quick brown fox# ; jumped on the leftovers. T # \ he quick brown fox jumped# * on the leftovers The Quick#The quick brown fox jumpe 3 : d on the leftovers. The qul ») ck brown fox jumped on th 3 ; e leftovers. The quick brow» \ n fox jumped on the leftove# • rs. The quick brown fox ju # i mped on the leftovers. The # ■ quick brown fox jumped on # : the leftovers. The quick br# • own fox jumped on the left # ; overs The quick brown fox# ; jumped on the leftovers. T # \ he quick brown fox jumped# * on the leftovers The Quick#The lazy gray dog slept by # foe leftovers. The lazy gra # у dog slept by foe leftovers# . The lazy gray dog slept b # у the leftovers. The lazy gr # ay dog slept by foe leftove # rs. The lazy gray dog slept # by foe leftovers. The lazy # gray dog slept by the lefto # vers. The lazy gray dog si # ept by foe leftovers The la # zy gray dog slept by the Ie # ftovers The lazy gray dog # slept bv the leftovers. The I#The lazy gray dog slept by # foe leftovers. The lazy gra # у dog slept by foe leftovers# . The lazy gray dog slept b # у the leftovers. The lazy gr # ay dog slept by foe leftove # rs. The lazy gray dog slept # by foe leftovers. The lazy # gray dog slept by the lefto # vers. The lazy gray dog si # ept by foe leftovers The la # zy gray dog slept by the Ie # ftovers The lazy gray dog # slept bv the leftovers. The I#The quick brown fox jumped on foe leftove 3 rs. The quick brown fox jumped on the left # overs. The quick brown fox jumped on foe 3 leftovers. The quick brown fox jumped on 13 he leftovers. The quick brown fox jumped # on the leftovers The quick brown fox jump 3 ed on the leftovers. The quick brown fox ju# mped on foe leftovers. The quick brown fo #The quick brown fox jumped on foe leftove 3 rs. The quick brown fox jumped on the left # overs. The quick brown fox jumped on foe 3 leftovers. The quick brown fox jumped on 13 he leftovers. The quick brown fox jumped # on the leftovers The quick brown fox jump 3 ed on the leftovers. The quick brown fox ju# mped on foe leftovers. The quick brown fo #< jumped on the leftovers. The quick brow 3 n fox jumped on foe leftovers. The quick br? own fox jumped on the leftovers. The quick# brown fox jumped on foe leftovers The qu# lek brown fox jumped on the leftovers The 3 quick brown fox jumped on the leftovers. 3< jumped on the leftovers. The quick brow 3 n fox jumped on foe leftovers. The quick br? own fox jumped on the leftovers. The quick# brown fox jumped on foe leftovers The qu# lek brown fox jumped on the leftovers The 3 quick brown fox jumped on the leftovers. 3Рисунок 5.13.Горизонтальный контейнер с панелями и с двумя текстовыми виджетамиРисунок 5.13.Горизонтальный контейнер с панелями и с двумя текстовыми виджетамиThe lazy gr# ay dog sle # pt by foe le 3 ftovers The# lazy gray 3 dog slept b 3 у the leftov 3 ers. The Iaz3The lazy gr# ay dog sle # pt by foe le 3 ftovers The# lazy gray 3 dog slept b 3 у the leftov 3 ers. The Iaz3у gray dog 3 slept by the# leftovers T3 he lazy gra# у dog slept 3 bv the left 3у gray dog 3 slept by the# leftovers T3 he lazy gra# у dog slept 3 bv the left 3Рисунок 5.14.Горизонтальный контейнер с панелями и с двумя текстовыми виджетамиРисунок 5.14.Горизонтальный контейнер с панелями и с двумя текстовыми виджетами/** hpaned.c **/
The quick brown fox jumpe 3 : d on the leftovers. The qul ») ck brown fox jumped on th 3 ; e leftovers. The quick brow» \ n fox jumped on the leftove# • rs. The quick brown fox ju # i mped on the leftovers. The # ■ quick brown fox jumped on # : the leftovers. The quick br# • own fox jumped on the left # ; overs The quick brown fox# ; jumped on the leftovers. T # \ he quick brown fox jumped# * on the leftovers The Quick#
The quick brown fox jumpe 3 : d on the leftovers. The qul ») ck brown fox jumped on th 3 ; e leftovers. The quick brow» \ n fox jumped on the leftove# • rs. The quick brown fox ju # i mped on the leftovers. The # ■ quick brown fox jumped on # : the leftovers. The quick br# • own fox jumped on the left # ; overs The quick brown fox# ; jumped on the leftovers. T # \ he quick brown fox jumped# * on the leftovers The Quick#
The lazy gray dog slept by # foe leftovers. The lazy gra # у dog slept by foe leftovers# . The lazy gray dog slept b # у the leftovers. The lazy gr # ay dog slept by foe leftove # rs. The lazy gray dog slept # by foe leftovers. The lazy # gray dog slept by the lefto # vers. The lazy gray dog si # ept by foe leftovers The la # zy gray dog slept by the Ie # ftovers The lazy gray dog # slept bv the leftovers. The I#
The lazy gray dog slept by # foe leftovers. The lazy gra # у dog slept by foe leftovers# . The lazy gray dog slept b # у the leftovers. The lazy gr # ay dog slept by foe leftove # rs. The lazy gray dog slept # by foe leftovers. The lazy # gray dog slept by the lefto # vers. The lazy gray dog si # ept by foe leftovers The la # zy gray dog slept by the Ie # ftovers The lazy gray dog # slept bv the leftovers. The I#
The quick brown fox jumped on foe leftove 3 rs. The quick brown fox jumped on the left # overs. The quick brown fox jumped on foe 3 leftovers. The quick brown fox jumped on 13 he leftovers. The quick brown fox jumped # on the leftovers The quick brown fox jump 3 ed on the leftovers. The quick brown fox ju# mped on foe leftovers. The quick brown fo #
The quick brown fox jumped on foe leftove 3 rs. The quick brown fox jumped on the left # overs. The quick brown fox jumped on foe 3 leftovers. The quick brown fox jumped on 13 he leftovers. The quick brown fox jumped # on the leftovers The quick brown fox jump 3 ed on the leftovers. The quick brown fox ju# mped on foe leftovers. The quick brown fo #
< jumped on the leftovers. The quick brow 3 n fox jumped on foe leftovers. The quick br? own fox jumped on the leftovers. The quick# brown fox jumped on foe leftovers The qu# lek brown fox jumped on the leftovers The 3 quick brown fox jumped on the leftovers. 3
< jumped on the leftovers. The quick brow 3 n fox jumped on foe leftovers. The quick br? own fox jumped on the leftovers. The quick# brown fox jumped on foe leftovers The qu# lek brown fox jumped on the leftovers The 3 quick brown fox jumped on the leftovers. 3
Рисунок 5.13.
Горизонтальный контейнер с панелями и с двумя текстовыми виджетами
Рисунок 5.13.
Горизонтальный контейнер с панелями и с двумя текстовыми виджетами
The lazy gr# ay dog sle # pt by foe le 3 ftovers The# lazy gray 3 dog slept b 3 у the leftov 3 ers. The Iaz3
The lazy gr# ay dog sle # pt by foe le 3 ftovers The# lazy gray 3 dog slept b 3 у the leftov 3 ers. The Iaz3
у gray dog 3 slept by the# leftovers T3 he lazy gra# у dog slept 3 bv the left 3
у gray dog 3 slept by the# leftovers T3 he lazy gra# у dog slept 3 bv the left 3
Рисунок 5.14.
Горизонтальный контейнер с панелями и с двумя текстовыми виджетами
Рисунок 5.14.
Горизонтальный контейнер с панелями и с двумя текстовыми виджетами
Iinclude <gnome.h>
3
4 56 78 910 11 12 1314 15 1617 18 1920 21 22 2324 25 26 27 2829 3031 3233 3435 3637 38 39404 56 78 910 11 12 1314 15 1617 18 1920 21 22 2324 25 26 27 2829 3031 3233 3435 3637 38 3940GtkWidget *makeHorizontalPane();
4 5
6 7
8 9
10 11 12 13
14 15 16
17 18 19
20 21 22 23
24 25 26 27 28
29 30
31 32
33 34
35 36
37 38 39
40
4 5
6 7
8 9
10 11 12 13
14 15 16
17 18 19
20 21 22 23
24 25 26 27 28
29 30
31 32
33 34
35 36
37 38 39
40
gint eventDelete(GtkWidget *widget, GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget, GdkEvent *event,gpointer data);
int main(int argc,char *argv[]) { GtkWidget *window; GtkWidget *pane;
gnome_init("hpaned","1.0",argc,argv); window « gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_default_size(GTK_WINDOW(window), 200,200);
gtk_signal_connect(GTK_OBJECT(window), "delete-event", GTKSIGNALFUNC(eventDelete), NULL);
gtks ignal_connect(GTK_OBJECT(window), "destroy", GTK_SIGNAL_FUNC(eventDestroy), NULL);
pane = makeHorizontaIPane();
gtk_container_add(GTK_CONTAINER(window),pane); gtk_widget_show(window);
gtk_main(); . exit(0);
}
GtkWidget *makeHorizontalPane() { int i;
GtkWidget *leftText;
GtkWidget *rightText;
GtkWidget *paned;
leftText * gtk_text_new(NULL,NULL);
gtk_widget_show(leftText);
rightText = gtk_text_new(NULL,NULL);
gtk_widget_show(rightText);
for(i=0; i<15; i++) {
gtk_text_insert(GTK_TEXT(leftText),NULL,NULL,NULL,
47"The quick brown fox jumped on the leftovers. ",
48-1);
49gtk_text_insert(GTK_TEXT(rightText),NULL,NULL,NULL,
50"The lazy gray dog slept by the leftovers. ",
51-1);
52}
53
54paned = gtk_hpaned_new();
55gtk_widget_show(paned);
56gtkpaned_addl(GTK_PANED(paned),leftText);
57gtk_paned_add2(GTK_PANED(paned),rightText);
58
59return(paned);
60 }
61 gint eventDelete(GtkWidget *widget,
62GdkEvent *event,gpointer data) {
63return(FALSE);
64 }
65 gint eventDestroy(GtkWidget *widget,
66GdkEvent *event,gpointer data) {
67gtk_main_quit();
68return(O);
69 }
Функция makeHorizontalPane(), которая начинается co строки 35, создает контейнер с панелями и вставляет в него два текстовых виджета. Эти виджеты создаются и заполняются текстом в строках с 41 по 52.
Обращение в строке 54 к функции gtk__hpaned_new() создает горизонтальный виджет с панелями, подобный показанным на рис. 5.13 и 5.14.
Обращение в строке 54 к функции gtk_hpaned_new() создает новый горизонтальный виджет с панелями. В строках 56 и 57 функция gtk_paned__addl () добавляет текстовый виджет в левую панель, a gtk_paned_add2 () — в правую.
Вот и все. Виджет с панелями и два содержащихся в нем виджета обмениваются информацией друг с другом о положении и размерах. Изменение размеров окна и перемещение разделителя приводит к изменению размеров обоих виджетов. Минимальный размер виджета не ограничивает перемещение разделителя, поэтому существует возможность постоянно перемещать разделитель от одного края окна до другого, полностью закрывая один текстовый виджет и открывая другой на все окно.
Вертикальный контейнер с панелями показан на рис. 5.15 и 5.16. Вы можете получить такое окно, изменив одну строку в предыдущей программе. Строка 54 должна выглядеть следующим образом:
paned=gtk_vpaned_new();
Все остальное можно не менять. Те же функции используются для добавления виджетов в вертикальный контейнер с панелями. Функция gtk_paned_addl () вставляет виджет в верхнюю панель, а функция gtk_paned_add2 () — в нижнюю.
he leftovers. The quick brown fox8 jumped on the leftovers The qui 8 ck brown fox jumped on the lefto 8 vers The quick brown fox jumpe 8 d on the leftovers. The quick bro 8 <vn fox jumped on the leftovers. T 8 he quick brown fox jumped on th 8 e leftovers. The quick brown fox j8 umped on the leftovers. The quic 8
The lazy gray dog slept by the Ie 8 ftovers. The lazy gray dog slept 8 by the leftovers. The lazy gray d 8 og slept by the leftovers The laz 8 у gray dog slept by the leftovers 8 The lazy gray dog slept by the I 8 eftovers. The lazy gray dog slept 8 by the leftovers. The lazy gray d8 og slept by the leftovers The laz 8 у gray dog slept by the leftovers 8
ТТ)е()и1скЬгомПь^итрес^^ he leftovers The quick brown fox8
on the leftovers. The qui 8
The lazy gray dog slept by the Ie 8 ftovers. The lazy gray dog slept 8 by the leftovers. The lazy gray d 8 og slept by the leftovers. The laz 8 у gray dog slept by the leftovers. 8 The lazy gray dog slept by the I 8 eftovers The lazy gray dog slept 8 by the leftovers. The lazy gray d8 og slept by the leftovers The laz 8 у gray dog slept by the leftovers 8 The lazy gray dog slept by the I 8 eftovers. The lazy gray dog slept 8 by the leftovers. The lazy gray d8 og slept by the leftovers The laz 8 у gray dog slept by the leftovers 8 The lazy gray dog slept by the I 8 eftovers The lazy gray dog slept 8
Рисунок 5.15.
Вертикальный контейнер с панелями с двумя текстовыми виджетами
Рисунок 5.16.
Вертикальный контейнер с панелями с двумя текстовыми виджетами
Имеется возможность установить толщину разделителя и размер кнопки-манипулятора. Например, чтобы воспроизвести конфигурацию, показанную на рис. 5.17, вставьте два следующих вызова функций после строки 54 предыдущей программы:
gtk_paned_set_handle_size(GTK_PANED(paned),30);
gtk_paned_set_gutter_size(GTK_PANED(paned),20);
Это устанавливает размер манипулятора 30x30 пикселов и толщину разделителя 20 пикселов. Однако размеры кнопки-манипулятора ограничены толщиной разделителя, поэтому фактические размеры манипулятора составят 20x30 пикселов. По умолчанию высота и ширина манипулятора составляют 10 пикселов, а ширина разделителя — 6 пикселов.
The quick brown fox jumped on the 8 leftovers. The quick brown fox jump 8 ed on the leftovers. The quick brow 8 n fox jumped on the leftovers The q8 uick brown fox jumped on the leflov 8 ers The quick brown fox jumped on8 the leftovers The quick brown foxj8The quick brown fox jumped on the 8 leftovers. The quick brown fox jump 8 ed on the leftovers. The quick brow 8 n fox jumped on the leftovers The q8 uick brown fox jumped on the leflov 8 ers The quick brown fox jumped on8 the leftovers The quick brown foxj8umped on the leftovers. The quick b8 ;rown fox jumped on the leftovers. T 8 he quick brown fox jumped on the I 8 eftovers. The quick brown fox jump 8 ed on the leftovers. The quick brow 8 n fox jumped on the leftovers The q8 uick brown fox jumped on the leftov 8umped on the leftovers. The quick b8 ;rown fox jumped on the leftovers. T 8 he quick brown fox jumped on the I 8 eftovers. The quick brown fox jump 8 ed on the leftovers. The quick brow 8 n fox jumped on the leftovers The q8 uick brown fox jumped on the leftov 8The lazy gray dog 8 slept by the Ieftov8 ers. The lazy gray 8 dog slept by the I 8 eftovers. The lazy 8 gray dog slept by 8 the leftovers. The 18The lazy gray dog 8 slept by the Ieftov8 ers. The lazy gray 8 dog slept by the I 8 eftovers. The lazy 8 gray dog slept by 8 the leftovers. The 18azy gray dog slept8 by the leftovers T8 he lazy gray dog 8 slept by the leflov 8 ers The lazy gray 8 dog slept by the 18 eftovers. The lazv 8azy gray dog slept8 by the leftovers T8 he lazy gray dog 8 slept by the leflov 8 ers The lazy gray 8 dog slept by the 18 eftovers. The lazv 8Рисунок 5.17.Контейнер с оконными секциями с пользовательской кнопкой-манипулятором и желобом-разделителемРисунок 5.17.Контейнер с оконными секциями с пользовательской кнопкой-манипулятором и желобом-разделителем
The quick brown fox jumped on the 8 leftovers. The quick brown fox jump 8 ed on the leftovers. The quick brow 8 n fox jumped on the leftovers The q8 uick brown fox jumped on the leflov 8 ers The quick brown fox jumped on8 the leftovers The quick brown foxj8
The quick brown fox jumped on the 8 leftovers. The quick brown fox jump 8 ed on the leftovers. The quick brow 8 n fox jumped on the leftovers The q8 uick brown fox jumped on the leflov 8 ers The quick brown fox jumped on8 the leftovers The quick brown foxj8
umped on the leftovers. The quick b8 ;
rown fox jumped on the leftovers. T 8 he quick brown fox jumped on the I 8 eftovers. The quick brown fox jump 8 ed on the leftovers. The quick brow 8 n fox jumped on the leftovers The q8 uick brown fox jumped on the leftov 8
umped on the leftovers. The quick b8 ;
rown fox jumped on the leftovers. T 8 he quick brown fox jumped on the I 8 eftovers. The quick brown fox jump 8 ed on the leftovers. The quick brow 8 n fox jumped on the leftovers The q8 uick brown fox jumped on the leftov 8
The lazy gray dog 8 slept by the Ieftov8 ers. The lazy gray 8 dog slept by the I 8 eftovers. The lazy 8 gray dog slept by 8 the leftovers. The 18
The lazy gray dog 8 slept by the Ieftov8 ers. The lazy gray 8 dog slept by the I 8 eftovers. The lazy 8 gray dog slept by 8 the leftovers. The 18
azy gray dog slept8 by the leftovers T8 he lazy gray dog 8 slept by the leflov 8 ers The lazy gray 8 dog slept by the 18 eftovers. The lazv 8
azy gray dog slept8 by the leftovers T8 he lazy gray dog 8 slept by the leflov 8 ers The lazy gray 8 dog slept by the 18 eftovers. The lazv 8
Рисунок 5.17.
Контейнер с оконными секциями с пользовательской кнопкой-манипулятором и желобом-разделителем
Рисунок 5.17.
Контейнер с оконными секциями с пользовательской кнопкой-манипулятором и желобом-разделителем
Слоистый контейнер
Подобный контейнер (layout container) может содержать любое количество виджетов. Положение виджетов задается их координатами х и у. Размеры контейнера не ограничены. Вы можете задать его высоту и ширину по своему усмотрению. Имеется также пара специальных настраиваемых объектов, по одному для каждой оси, устанавливая которые можно указать, какая часть контейнера доступна. Вы смотрите на панель окна контейнера через глазок; окно можно передвигать, чтобы взглянуть на другие части контейнера.
Приведенная далее программа создает слоистый контейнер с кнопками и для определения видимых кнопок использует значения, указывающие положение, из двух полос прокрутки.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
/** layout.с
#include <gnome.h>
GtkWidget *makeLayout();
void addButtons(GtkWidget ♦layout);
gint eventDelete(GtkWidget *widget, GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget, GdkEvent *event,gpointer data);
int main(int argc,char *argv[J) < GtkWidget *window;
GtkWidget *layout;
gnome_init("layout","1.0",argc,argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_s et_def ault_si ze(GTK_WINDOW(window), 200,200);
gtk_signal_connect(GTK_OBJECT(window), "delete_event", GTKSIGNALFUNC(eventDelete), NULL);
gtk_signal_connect(GTK_OBJECT(window), "destroy", GTK_SIGNAL_FUNC(eventDeStroy), NULL);
layout = makeLayout();
gtk_container_add(GTK_CONTAINER(window),layout); gtk_widget_show_all(window);
gtk_main();
exit(0);
}
GtkWidget *makeLayout() < GtkWidget *layout; GtkWidget *vscroll; GtkWidget *hscroll; GtkWidget *table; GtkAdjustment *horizAdj; GtkAdjustment *vertAdj;
vertAdj = (GtkAdjustment *)gtk_adjustment_new( 0.0, 0.0, 1000.0, 1.0, .10.0,
20.0);
horizAdj = (GtkAdjustment *)gtk_adjustment_new( 0.0, 0.0, 1000.0, 1.0, 10.0,
5859585920.0);
58
59
58
59
60 layout = gtk_layout__new(horizAd j, vertAd j);
61gtk_layout_set_size(GTK_LAYOUT(layout),1000,1000);
62addButtons(layout);
63
vscroll = gtk_vscrollbar_new(vertAdj);
hscroll = gtk_hscrollbar_new(horizAdj);
66
table = gtk_table_new(2,2,FALSE);
68
gtk_table_attach_defaults(GTK_TABLE(table),layout,
700,1,0,1);
gtk_table_attach(GTK_TABLE(table),vscroll,
721,2,0,1,
GTK_FILL,GTK_FILL,0,0);
gtk_table_attach(GTK_TABLE(table),hscroll,
750,1,1,2,
6GTK_FILL,GTK_FlLL,0,0);
77 78return(table);
}
void addButtons(GtkWidget *layout) 81 { 82gint i;
gint j;
GtkWidget *button;
gchar label[20];
86 87for(i»100; i<1000; i += 100) {
88for(j=100; j<1000; j+= 50) {
sprintf(label,"(%d,%d)",i,j);
button = gtkbuttonnewwithlabel(label);
gtk_layout_put(GTK_LAYOUT(layout),button,i,j);
}
}
}
gint eventDelete(GtkWidget *widget, 96GdkEvent *event,gpointer data) {
return(FALSE);
}
gint eventDestroy(GtkWidget *widget, 100GdkEvent *event,gpointer data) {
101gtk_main_quit();
102return(0);
103 }
Приведенный пример создает таблицу 2x2, в верхний левый угол которой вставлен слоистый контейнер, а справа и снизу — полосы прокрутки, как показано на рис. 5.18. В каждый слой контейнера через равные промежутки вставлены кнопки. Метка каждой кнопки содержит ее координаты х и у внутри слоистого контейнера. Таким образом вы можете перемещать контейнер вокруг себя и видеть все кнопки, те же самые объекты GtkAd justment, определяющие положение, используются как контейнером, так и полосой прокрутки.
Функция makeLayout (), начинающаяся со строки 36, создает таблицу и вставляет в нее различные виджеты. Таблица — это сетка 2x2. В ее верхний левый угол вставлен слоистый контейнер, а справа и снизу — полосы прокрутки. Нижняя правая ячейка остается пустой.
100)|(500,500)1(600,500)](700,500)|i50)|(500,550)](600,550)|(700,55Q)|i00)|(500,600)1(600,600)1(700,600)150)|(500,650)|(600,650)1(700,650)]00)|(500,700)1(600,700)](700,700)|RIZIZZZZZZZZ1100)|(500,500)1(600,500)](700,500)|i50)|(500,550)](600,550)|(700,55Q)|i00)|(500,600)1(600,600)1(700,600)150)|(500,650)|(600,650)1(700,650)]00)|(500,700)1(600,700)](700,700)|RIZIZZZZZZZZ1Рисунок 5.18.В слоистом контейнере видна только часть его окнаРисунок 5.18.В слоистом контейнере видна только часть его окнаВ строках с 45 по 58 создается пара объектов GtkAd justment, которые используются для управления положением слоистого контейнера. Для горизонтальной и вертикальной настройки позиционирования существует по одному объекту. Функция gtk_ad justment_new() требует шесть аргументов с плавающей запятой. Первый аргумент задает начальное значение, которое должно находиться в диапазоне между значениями второго и третьего аргументов. Второй и третий аргументы определяют соответственно начальное и конечное положение контейнера в окне. В этом примере и вертикальный, и горизонтальный размеры контейнера могут находиться в диапазоне от 0 до 1000.
100)|(500,500)1(600,500)](700,500)|
i50)|(500,550)](600,550)|(700,55Q)|
i00)|(500,600)1(600,600)1(700,600)1
50)|(500,650)|(600,650)1(700,650)]
00)|(500,700)1(600,700)](700,700)|
RIZIZZZZZZZZ1
100)|(500,500)1(600,500)](700,500)|
i50)|(500,550)](600,550)|(700,55Q)|
i00)|(500,600)1(600,600)1(700,600)1
50)|(500,650)|(600,650)1(700,650)]
00)|(500,700)1(600,700)](700,700)|
RIZIZZZZZZZZ1
Рисунок 5.18.
В слоистом контейнере видна только часть его окна
Рисунок 5.18.
В слоистом контейнере видна только часть его окна
Три последних аргумента функции gtk_ad justment_new() — это инструкции программным элементам, например, полосам прокрутки, которые будут обновлять текущее значение GtkAd justment. Аргумент 1.0 — это шаг приращения, или минимальное значение, на которое окно может быть передвинуто. В приведенном примере так получилось, что значение 1.0 соответствует 1 пикселу. Аргумент 10.0 — это количество слоев, перемещаемых при щелчке указателем мыши на полосе прокрутки. Последний аргумент — размер страницы на случай, если вы хотите, чтобы программа могла передвигаться
вверх и вниз на целую страницу.
Слоистый контейнер создается в строке 60. Он передается двум объектам настройки положения. Для изменения положения контейнера в отображаемом глазке вам необходимо всего лишь установить текущее значение объекта настройки. В строке 62 устанавливается размер слоистого объекта, а с помощью обращений в строке 62 к функции addButtons() происходит наполнение его кнопками. Функция addButtons(), начинающаяся со строки 80, представляет простой цикл создания кнопок и размещения их в большом прямоугольнике слоистого контейнера. Кнопки помещаются в контейнер с помощью функции gtk_layout_put () в строке 91.
ПРИМЕЧАНИЕ
Обратите внимание на вызов функции gtk_widget_show_all() в строке 32. Это приводит к тому, что указанный виджет (в данном случае главное окно) и все его дочерние виджеты выводятся на экран. То же самое выполняет функция gtk^widget_show(), но для каждого виджета в отдельности.
Вы можете переместить виджет внутри контейнера в другое место, вызвав функцию gtk_layout_move (), как показано ниже:
gtk_layout_move(GTK_LAYOUT(layout),button,5,10);
Это перемещает виджет под названием button в точку, отстоящую на 5 пикселов от левого края контейнера и на 10 пикселов ниже вершины. Размер видимой части контейнера можно изменить с помощью обращения к функции gtk_layout_set_size (), задав ширину и высоту. Например, следующее обращение задает высоту видимой части окна 200 пикселов и ширину соответственно 350 пикселов:
gtk_layout_set_size(GTK_LAYOUT(layout),200,350);
Объекты положения могут быть получены путем обращения к следующим двум функциям:
vertAdj = gtk_layout_get_vadjustment(GTK_LAYOUT(layout));
horizAdj = gtk_layout_get_hadjustment(GTK_LAYOUT(layout));
Иногда вам может понадобиться получить эти объекты после того, как они были изменены внутри программы. Функции, которые используются для установки параметров положения, имеют некоторые встроенные ограничения на численные значения. Неправильные значения исправляются без сообщения об этом. Кроме того, обычно текущее положение отображается с помощью объекта GtkAd justment. Эти функции могут задать новые значения параметров настройки положения:•
gtk_layout_set_hadjustment(GTK_LAYOUT(layout),horizAdj);
gtk_layout_set_vadjustment(GTK_LAYOUT(layout),vertAdj);
Использование группы приведенных выше функций для проведения большого количества изменений может привести к тому, что на экране будет заметно мерцание, так как виджеты станут появляться, исчезать и перемещаться из одного положения в другое. Если вы хотите подавить автоматическую перерисовку окон, которая происходит при каждом вызове функции, можно запретить вывод изображений, пока не будут проведены какие- либо изменения, и лишь затем разрешить перерисовку экрана. В этом случае будет казаться, что изменения происходят одновременно:
gtk_layout_freeze(GTK_LAYOUT(layout));
/* The code to make the changes goes here. */
gtk_layout_thaw(GTK_LAYOUT(layout));
Скроллинговый оконный контейнер
0)| (180, 90)| (240, 90)| (300, $0)| (180, 90)| (240, 90)| (300, $:0)| (180,120)| (240,120)| (300,1 i0)| (180,15G)|(240,150) j (300,1 Ю)| (180,18Q)[ (240,180)1(300,1 0)] (180,210)| (240,210)| (300,2 -.1I...I ~ZZ^ZIZZ^:0)| (180,120)| (240,120)| (300,1 i0)| (180,15G)|(240,150) j (300,1 Ю)| (180,18Q)[ (240,180)1(300,1 0)] (180,210)| (240,210)| (300,2 -.1I...I ~ZZ^ZIZZ^Такой контейнер (scrolled window container) отображает через окно просмотра часть большего окна. Он также подсоединяет справа вертикальную полосу прокрутки, а внизу — горизонтальную полосу прокрутки. В следующем примере для создания большого окна с кнопками, содержащего сетку 30x30, используется фиксированный контейнер (см. рис. 5.19).
0)| (180, 90)| (240, 90)| (300, $
0)| (180, 90)| (240, 90)| (300, $
:0)| (180,120)| (240,120)| (300,1 i0)| (180,15G)|(240,150) j (300,1 Ю)| (180,18Q)[ (240,180)1(300,1 0)] (180,210)| (240,210)| (300,2 -.1I...I ~ZZ^ZIZZ^
:0)| (180,120)| (240,120)| (300,1 i0)| (180,15G)|(240,150) j (300,1 Ю)| (180,18Q)[ (240,180)1(300,1 0)] (180,210)| (240,210)| (300,2 -.1I...I ~ZZ^ZIZZ^
/** scrolled.с **/
tinclude <gnome.h> 3
GtkWidget *makeScrolledWindow();
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
9
int main(int argc,char *argv[])
{Рисунок 5.19. Обзор
GtkWidget ‘window;скроллингового окна
GtkWidget *scrolled;
14
15gnome_init("scrolled","1.0",argc,argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size(GTK_WINDOW(window),
18200,200);
gtk_signal_connect(GTK_OBJECT(window),
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69 >0
71
72
73
"delete^event", GTKSIGNALFUNC(eventDelete), NULL);
gtksignalconnect(GTK_OBJECT(window), "destroy*, GTKSIGNALFUNC(eventDestroy), NULL);
scrolled * makeScrolledWindow();
gtk_container_add(GTK_CONTAINER(window),scrolled); gtkwidgetshowall(window);
gtk_main(); exit(0);
}
GtkWidget *makeScrolledWindow() < gint i; gint j; gchar label[40]? GtkWidget *scrolled; GtkWidget *button; GtkWidget *fixed;
scrolled = gtk_scrolled_window_new(NULL,NULL); gtkscrolledwindowsetpolicy(
GTK_SCROLLED_WINDOW(scrolled), GTKPOLICYALWAYS, GTKPOLICYALWAYS);
fixed = gtkfixednew();
for(i=30; i<300; i 4-* 30) { for(j=30; j<300; j += 30) { sprintf(label,"(%3d,%3d)",2*i,j); button = gtkbuttonnewwithlabel(label); gtk fixed_put(GTK_FIXED(fixed),button,2*i,j);
-}
}
gtkscrolledwindowaddwithviewport( GTK_SCROLLED_WINDOW(scrolled), fixed);
return(scrolled); }
gint eventDelete(GtkWidget *widget, GdkEvent *event,gpointer data) { return(FALSE);
}
gint eventDestroy(GtkWidget *widget, GdkEvent ♦event,gpointer data) { gtk_main_quit();
return(0);
}
Скроллинговый оконный контейнер создается в строке 44. В качестве обоих аргументов функции gtk_scrolled_window_new() передаются указатели NULL. Первый аргумент — объект GtkAd justment, управляющий горизонтальным позиционированием,
второй аргумент — объект GtkAd justment, управляющий вертикальным позиционированием. Если в качестве хотя бы одного из аргументов передать указатель NULL, объекты настройки создаются автоматически. Обычно так и делают. Однако, если вы хотите менять положение окна просмотра не только с помощью полос прокрутки или желаете установить значения приращения, используемые полосой прокрутки, вам необходимо иметь доступ к объектам настройки.
Обращение к функции gtk_scrolled_window_setjpolicy () в строке 45 указывает, что обе полосы прокрутки должны всегда присутствовать. Первая установка распределения ресурсов относится к нижней полосе прокрутки, вторая — к правой полосе прокрутки. Значение GTKPOLICYALWAYS предполагает постоянное присутствие полосы прокрутки независимо от ее необходимости. Значение GTKPOLICYAUTOMATIC инициирует появление полос прокрутки (скроллинга) лишь в случае, если контейнер больше, чем окно просмотра. Обе полосы прокрутки могут возникать автоматически, если заменить строки 45-48 на следующие:
20, 30)| (180, 30)| (240, 3( 20 60)| (180, 60)| (240, 6С20, 90)] (180, 90)| (240, ЭС 20,12O)|(18O;120)|(240,12 20,150)] (180,150)] (240,15 20,180)] (180,180)] (240,18 20,210)|(180,2Ю)|(240,21 20,240)| (180,240)] (240,24 20,270)] (180,270)1 (240,27к—=320, 30)| (180, 30)| (240, 3( 20 60)| (180, 60)| (240, 6С20, 90)] (180, 90)| (240, ЭС 20,12O)|(18O;120)|(240,12 20,150)] (180,150)] (240,15 20,180)] (180,180)] (240,18 20,210)|(180,2Ю)|(240,21 20,240)| (180,240)] (240,24 20,270)] (180,270)1 (240,27к—=3gtk_scrolled_window_set_policy(
20, 30)| (180, 30)| (240, 3( 20 60)| (180, 60)| (240, 6С
20, 90)] (180, 90)| (240, ЭС 20,12O)|(18O;120)|(240,12 20,150)] (180,150)] (240,15 20,180)] (180,180)] (240,18 20,210)|(180,2Ю)|(240,21 20,240)| (180,240)] (240,24 20,270)] (180,270)1 (240,27
к—=3
20, 30)| (180, 30)| (240, 3( 20 60)| (180, 60)| (240, 6С
20, 90)] (180, 90)| (240, ЭС 20,12O)|(18O;120)|(240,12 20,150)] (180,150)] (240,15 20,180)] (180,180)] (240,18 20,210)|(180,2Ю)|(240,21 20,240)| (180,240)] (240,24 20,270)] (180,270)1 (240,27
к—=3
Рисунок 5.20.Вертикальная полоса прокрутки исчезаетавт ом ат и ч ескиРисунок 5.20.Вертикальная полоса прокрутки исчезаетавт ом ат и ч ескиGTK_SCROLLED_WINDOW(scrolled), GTKPOLICYAUTOMATIC, GTK_POLICY_AUTOMATIC);
Рисунок 5.20.
Вертикальная полоса прокрутки исчезает
авт ом ат и ч ески
Рисунок 5.20.
Вертикальная полоса прокрутки исчезает
авт ом ат и ч ески
На рис. 5.20 показано окно с автоматическими полосами прокрутки при увеличении его высоты до размера полного отображения всего столбца кнопок. Необходимости в вертикальной полосе прокрутки нет, и полоса исчезла. На рис. 5.21 показано окно, растянутое по горизонтали до размера, когда видна вся строка кнопок, при этом исчезла горизонтальная полоса прокрутки.
>c?oiledaulo
( 60,180)| (120,180)j (180,180)| (240,180)| (300,160) | (360,180)| (420,180)[ (480,160)] (540,180)| ( 60,210) ] (120,210)| (180,210)| (240,210)] (300,210)|(360,210)|(420,210)|(480,210)](540,210)| ( 60,240)] (120,240)] (180,240)] (240,240)] (300,240)](360,240)] (420,240)] (480,240)](540,240)]
Рисунок 5.21. Горизонтальная полоса прокрутки исчезает автоматически
Записная книжка
Контейнер по типу записной книжки (notebook container) размещает виджеты один под другим и прилагает ряд клавиш, которые используются для переключения между виджетами. Клавиши могут располагаться сверху, снизу, слева или справа. Содержащиеся виджеты могут представлять любую разновидность отображаемых виджетов, включая другие записные книжки. Каждый виджет, содержащийся в записной книжке, называется страницей (page), поскольку по аналогии с книгой за текущей видимой страницей не видны все остальные страницы. Видимая в настоящий момент страница называется активной праницей.
Существует пара ограничений размеров. Если клавиши переключения располагаются сверху или снизу, то ширина записной книжки должна быть не меньше ширины кнопки.
Если клавиши располагаются слева или справа, то высота записной книжки должна быть не меньше высоты клавиш.
Приведенная ниже программа создает окно, показанное на рис. 5.22.
/** notebook.c *♦/
♦include <gnome.h>
GtkWidget *makeNotebook();
GtkWidget *makeButtonPage(gchar *str);
GtkWidget *makeTextPage(gchar * str); gint eventDelete(GtkWidget *widget, GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget, GdkEvent *event,gpointer data);
int main(int argc,char *argv[]) <
GtkWidget *window;
GtkWidget *notebook;
gnome_init("notebook","1.0",argc,argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size(GTK_WINDOW(window), 200,200);
gtk_signal_connect(GTK_OBJECT(window), "delete_event", GTK_SIGNAL_FUNC(eventDelete), NULL);
gtk_signal_connect(GTK_OBJECT(window), "destroy", GTKSIGNALFUNC(eventDestroy), NULL);
notebook = makeNotebook();
В X,
This is the text of the first text page. ♦ This is the text of the first text page 2 . This is the text of the first text pag 3 e. This Is the text of the first text pa 3 ge. This is the text of the first text p 2 age This is the text of the first text 2 page. This is the text of the first text 2 page. This is the text of the first tex2 t page. This is the text of the first te 2 Kt page. This is the text of the first t 2 ext page. This is the text of the first 2 text папе This is the text nf the first2
Back
Рисунок 5.22.
Записная книжка, состоящая из пяти страниц
gtk_container_add(GTK_CONTAINER(window),notebook); gtk_widget_show_all(window);
gtk_main(); exit(0);
}
GtkWidget *makeNotebook() { GtkWidget *notebook; GtkWidget *page;
GtkWidget *label;
notebook = gtk_notebook_new();
gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTKPOSTOP);
page = makeButtonPage("First Button Page");
label = gtk_label_new("Front");
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page,label);
51
52
53
54
page = makeTextPage("first");
label = gtk_label_new("Second");
gtk_notebook_append_page(GTKNOTEBOOK(notebook) page,label);
1 2
3 4
5
6
7
8
9
10 11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
page = makeButtonPage("Second Button Page"); label = gtk_label_new("Third");
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page,label);
page = makeTextPage("second"); label = gtk_label_new("Fourth");
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page,label);.
page = makeButtonPage("Third Button Page"); label = gtk_label_new("Back");
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page,label);
return(notebook);
}
GtkWidget *makeButtonPage(gchar *str) <
GtkWidget *alignment;
GtkWidget *button;
alignment = gtk_alignment_new(0.5,0.5,0.5,0.5); button = gtk_button_new_with_label(str);
gtk_container_add(GTK_CONTAINER(alignment),button);
return(alignment); }
GtkWidget *makeTextPage(gchar *str) < int i;
GtkWidget *text; gchar string[80];
text = gtk_text_new(NULL,NULL); sprintf(string,
"This is the text of the %s text page. ",str); for(i=0; i<80; i++) {
gtktextinsert(GTKTEXT(text),NULL,NULL,NULL, string,-!);
}
return(text);
}
gint eventDelete(GtkWidget *widget, GdkEvent *event,gpointer data) { return(FALSE);
}
gint eventDestroy(GtkWidget *widget, GdkEvent *event,gpointer data) { gtk_main_quit();
return(0);
Функция makeNotebook(), которая начинается со строки 37, создает записную книжку из нескольких страниц. Записная книжка создается и конфигурируется в строках с 42 по 44. Страницы создаются и вставляются в контейнер записной книжки в строках с
46 по 69. Сами актуальные страницы создаются функциями makeButtonPage () и makeTextPage (), которые начинаются соответственно со строк 73 и 84.
В контейнере записной книжки может быть размещен ряд клавиш переключения вдоль любой из четырех ее сторон. Для установки положения клавиш используется функция gtk_notebook_set_tab_pos(). Значение GTK_POS_TOP помещает клавиши сверху, как показано на рис. 5.22. Значение GTK_POS_BOTTOM помещает клавиши внизу, как показано на рис. 5.23. GTK_POS_LEFT помещает клавиши слева, как изображено на рис. 5.24. GTK_POS_RIGHT располагает клавиши справа. По умолчанию используется GTK_POS_TOP. Именно такое расположение клавиш используется чаще всего.
notebooknotebookЗаписная книжка с клавишами переключения слеваЗаписная книжка с клавишами переключения слеваЖ]
notebook
notebook
Записная книжка с клавишами переключения слева
Записная книжка с клавишами переключения слева
This is the text of the second texl p 5 age. This is the text of the second 15 ext page This is the text of the sec 3 ond text page This is the text of the? second text page This is the text o? f the second text page This is the 13 ext of the second text page. This is 3 the text of the second text page Th 3 is is the text of the second text pag 3 e. This is the text of the second text? page This is the text of the secon ? ri text пяле This is the text nf the s 3 Front | Second iThird [Fourth|| Back
Рисунок 5.23.
Записная книжка с клавишами переключения внизу
Каждый виджет страницы включается в записную книжку с помощью функции gtk_notebook_append__page (). Эта функция добавляет новую страницу под уже существующими страницами. Другими словами, вставляемая страница становится последней в записной книжке. Страница, добавленная подобным образом, располагает свою клавишу переключения либо внизу, либо справа, в зависимости от ориентации клавиш.
Обращение к функции gtk_notebook_append_page () также содержит третий параметр. При вставке новой страницы в записную книжку необходимо указать виджет, который будет использоваться в качестве метки (надписи) на клавише. Обычно, как и в приведенном примере, используется виджет метки, отображающий текст на клавише переключения. Однако можно использовать и любой другой графический виджет. При этом клавиши переключения будут выглядеть и работать, как пиктограммы.
Существует еще функция gtk__notebook_prepend_page (). Она принимает те же параметры, что и функция gtk_notebook_append_page(), и также добавляет в записную книжку новую страницу, но только новая страница становится первой, а не последней.
Страницы записной книжки содержатся в виде упорядоченного списка, и каждая из страниц имеет свой номер расположения. Номер первой страницы — 0, второй — 1 и т.д. Номер расположения можно использовать для вставки страницы между двумя существующими страницами. Например, если записная книжка уже содержит четыре страницы (с номерами 0, 1, 2 и 3), то с помощью следующего вызова функции можно вставить страницу в середину книжки:
gtk_notebook_insert_page(GTKNOTEBOOK(notebook), page, label, 2);
После выполнения этой функции страница, которая имела номер 3, получила номер 4, а страница с номером 2 — номер 3. Новая страница получила номер 2. Вы можете удалить страницу по ее номеру. Например, для удаления страницы номер 2 используется следующая строка:
gtknotebookremove_page(GTK_NOTEBOOK(notebook), 2);
Если вы хотите усилить контроль над изображением на экране, то есть хотите выбрать клавишу переключения из вашей программы, можете вызвать функцию gtk_notebook_set_page (), чтобы выбрать любую из активных страниц. Например, следующая строка активизирует страницу 2:
gtk notebook setpage(GTK_NOTEBOOK(notebook),2);
Следующий вызов функции можно было использовать в предыдущем примере для определения активной страницы:
gint loc;
loc = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
Клавиши переключения могут отсутствовать. Это означает, что пользователь не будет иметь клавиш переключения между страницами. Однако возможность программного перехода между страницами остается, и иногда бывают случаи, когда это необходимо. Например, если программа может работать в нескольких режимах, то окно для каждого из режимов следует организовать в виде записной книжки и переключать активные страницы всякий раз при переключении режимов. По умолчанию все клавиши переключения являются видимыми. Следующее обращение к функции скрывает клавиши:
gtk notebook_set_show_tabs(GTK_NOTEBOOK(notebook),FALSE);
Клавиши переключения можно снова сделать видимыми, задав TRUE вместо FALSE.
Ящик с кнопками
Почти в каждом окне имеется хотя бы одна кнопка, а большинство окон имеет более одной кнопки. Поскольку кнопки нужны так часто, существует специальный контейнер для группировки кнопок. Одним из преимуществ использования ящика с кнопками (button box) является возможность глобального управления параметрами расположения и интервалами. Другими словами, вы можете управлять размещением кнопок во всем вашем приложении с помощью единственной установки. И если вам этого недостаточно, можно задавать план размещения для отдельных ящиков с кнопками, а для других оставлять установки, принятые по умолчанию.
Следующий пример показывает, насколько легко можно использовать ящик с кнопками для создания группы кнопок:
/** hbuttonbox.c **/
linclude <gnome.h> 3
GtkWidget *makeButtonBox();
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
9
int main(int argc,char *argv[]) И <
GtkWidget *window;
GtkWidget *buttonbox;
14
gnome_init("hbuttonbox","1.0",argc,argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_signal_connect(GTK_OBJECT(window),
"delete_event",
GTK_SIGNAL_FUNC(eventDelete),
NULL);
gtk_signal_connect(GTK_OBJECT(window),
"destroy",
GTK_SIGNAL_FUNC(eventDestroy),
NULL);
25
buttonbox = makeButtonBox();
27
gtk_container_add(GTK_CONTAINER(window),buttonbox);
gtk_widget_show_all(window);
gtk_main();
exit(0);
}
GtkWidget *makeButtonBox() {
GtkWidget*buttonbox;
GtkWidget*button;
36
buttonbox= gtk_hbutton_box_new();,
gtk_container_set_border_width(
9GTK_CONTAINER(buttonbox),10);
40
button = gtkbuttonnewwithlabel("OK");
gtkcontaineradd(GTK_CONTAINER(buttonbox),button);
43 44 button = gtk_button_new_with_label("Refresh");
5gtkcontaineradd(GTK_CONTAINER(buttonbox),button);
46 47 button = gtk_button_new_with_label("Clear");
8gtkcontaineradd(GTK_CONTAINER(buttonbox),button);
49 50 button = gtk_button_new_with_label("Cancel");
gtk_container_add(GTK_CONTAINER(buttonbox),button);
52
return(buttonbox);
}
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data) {
return(FALSE);
•}
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data) {
gtk_main_quit();
return(0);
}
Функция makeButtonBox(), которая начинается co строки 33, создает горизонтальный ящик и заполняет его кнопками. Ящик создается в строке 37 путем вызова функции g t k_hbu 11 on_box__new (), которая не требует никаких параметров. Каждая кнопка до-
бавляется в ящик путем обращения к функции gtk_container_add() в строках с 41 по 51. Обращение в строке 38 к функции gtk_container__set_border_width() добавляет интервал в 10 пикселов вокруг набора кнопок. Полученное окно показано на рис. 5.25.
Вертикальный ящик с кнопками может быть создан заменой всего одной буквы. Чтобы получить окно, показанное на рис. 5.26, необходимо заменить строку 37 следующей:
buttonbox=gtk_vbutton_box_new();buttonbox=gtk_vbutton_box_new();Рисунок 5.25.Горизонтальный ящик с кнопкамиРисунок 5.25.Горизонтальный ящик с кнопкамиРисунок 5.26.Вертикальный ящик с кнопкамиРисунок 5.26.Вертикальный ящик с кнопками
buttonbox=gtk_vbutton_box_new();
buttonbox=gtk_vbutton_box_new();
Рисунок 5.25.
Горизонтальный ящик с кнопками
Рисунок 5.25.
Горизонтальный ящик с кнопками
Рисунок 5.26.
Вертикальный ящик с кнопками
Рисунок 5.26.
Вертикальный ящик с кнопками
Ящик с кнопками имеет четыре различные опции размещения, которые могут быть установлены следующими пятью значениями:
GTK_BUTTONBOX_DEFAULT_STYLE GTK_BUTTONBOX_SPREAD GTK_BUTTONBOX_EDGE GTK_BUTTONBOX_START GTK_BUTTONBOX_END
Следующая программа демонстрирует результаты установки каждой из этих опций для ящика с кнопками. Четыре ящика с кнопками, созданные этой программой, причем каждый со своим набором опций размещения, показаны на рис. 5.27.
Рисунок 5.27. Различные варианты размещения горизонтальных ящиков с кнопкамиРисунок 5.27. Различные варианты размещения горизонтальных ящиков с кнопками
Рисунок 5.27. Различные варианты размещения горизонтальных ящиков с кнопками
Рисунок 5.27. Различные варианты размещения горизонтальных ящиков с кнопками
Все опции размещения действуют в случае, когда размеры ящика с кнопками больше минимальных. Опция GTK_BUTTONBOX_SPREAD распределяет кнопки равномерно вдоль всего ящика, вставляет пустое пространство в начале и в конце ряда кнопок. Опция
GTK_BUTTONBOX_EDGE также распределяет кнопки равномерно, но не добавляет пустое пространство в начале или конце. Опция GTK_BUTTONBOX_START вставляет между кнопками используемый по умолчанию интервал и перемещает все кнопки к левому краю. Опция GTK__BUTTONBOX_END также вставляет между кнопками используемый по умолчанию интервал, но перемещает кнопки к правому краю.
Опция GTK_BUTTONBOX_DEFAULT_STYLE указывает на то, что для конфигурирования ящика с кнопками будет использоваться значение по умолчанию. В качестве значения по умолчанию, если только вы его не поменяете, устанавливается GTK_BUTTONBOX_EDGE.
/** hbdemo.c **/
linclude <gnome.h>
3
typedef struct {
gchar *name;
GtkButtonBoxStyle value;
} layoutoption;
8
GtkWidget *makeButtonFrame(layoutoption *option);
GtkWidget *makeButtonBox(layoutoption *option);
GtkWidget *makeDisplay();
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
16
layoutoption option[] = {
{ "DEFAULT_STYLE", GTK_BUTTONBOX_DEFAULT_STYLE },
{"SPREAD", GTKBUTTONBOXSPREAD },
{"EDGE", GTK_BUTTONBOX_EDGE },
{"START", GTKBUTTONBOXSTART },
{"END", GTK_BUTTONBOX_END }
};
24
int main(int argc,char *argv[])
{
GtkWidget *window;
GtkWidget *demoDisplay;
29
gnome_init("hbdemo","1.0",argc,argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk signal connect(GTK OBJECT(window),
"deleteevent",
GTK_SIGNAL_FUNC(eventDelete),
NULL);
gtk_signal_connect(GTK_OBJECT(window),
"destroy",
•38GTK_SIGNAL_FUNC(eventDestroy),
NULL);
40
demoDisplay = makeDisplay();
42
gtkcontainer add(GTK CONTAINER(window),demoDisplay);
gtk_widget_show_all(window);
gtk_main();
exit(0);
}
GtkWidget *makeDisplay()
{
int 1;
GtkWidget *vbox;
GtkWidget *frame;
53
vbox = gtk_vbox_new(FALSE,10);
gtk_container_set_border_width(GTK_CONTAINER(vbox),10);
for(i=0; i<5; i++) {
frame = makeButtonFrame(&option[i]);
gtkboxpackstart(GTKBOX(vbox),frame,
FALSE,FALSE,0);
}
return(vbox);
}
GtkWidget *makeButtonFrame(layoutoption *option)
{
GtkWidget*frame;
GtkWidget*buttonbox;
67
frame = gtkframe_new(option->name);
buttonbox= makeButtonBox(option);
gtk_container_add(GTK_CONTAINER(frame),buttonbox);
return(frame);
}
GtkWidget *makeButtonBox(layoutoption *option)
{
GtkWidget *buttonbox;
GtkWidget *button;
77
buttonbox = gtk_hbutton_box_new();
gtkbuttonboxsetlayout(GTKBUTTONBOX(buttonbox),
option->value);
gtkcontainersetborderwidth(
GTK_CONTAINER(buttonbox),10);
83
button = gtkbutton newwithlabel("OK");
gtkcontaineradd(GTKCONTAINER(buttonbox),button);
86
button = gtkbuttonnewwith label("Refresh");
8gtkcontaineradd(GTK_CONTAINER(buttonbox),button);
89
button = gtk_button_new_with_label("Clear");
gtkcontaineradd(GTK_CONTAINER(buttonbox),button);
92
button = gtkbuttonnewwith label("Cancel");
gtk_container_add(GTK_CONTAINER(buttonbox),button);
95
return(buttonbox);
}
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data) {
return(FALSE);
}
gint eventDestroy(GtkWidget *widget,
GdkEvent ♦event,gpointer data) {
gtk_main_quit();
105return(0);
}
Функция makeDisplay (), которая начинается со строки 48, создает вертикальный ящик, содержащий все отображаемые виджеты. В цикле, который начинается со строки 56 и использует текст и значения, хранящиеся в массиве, объявленном в строке 17, создаются пять обрамляющих кнопки контейнеров — по одному для каждой опции размещения. Для каждого из вариантов размещения в строке 57 создается обрамляющий контейнер, содержащий ящик с кнопками, и сохраняется в вертикальном ящике в строке 58.
Функция makeButtonFrame (), начинающаяся в строке 63, создает обрамляющий контейнер, в метке которого содержится название опции размещения. Ящик с кнопками создается при вызове функции makeButtonBox () в строке 69 и вставляется в обрамляющий контейнер в строке 70.
Функция makeButtonBox (), начинающаяся в строке 73, создает ящик с кнопками и помещает в него четыре кнопки. При обращении в строке 79 к функции gtk_button_box_set_layout () используется значение размещения, передаваемое в качестве аргумента для установки опции размещения.
Те же опции размещения пригодны и для вертикальных ящиков с кнопками (см. рис. 5.28). Программа, которая создавала вертикальные кнопки, практически та же, что и в предыдущем примере, за исключением того, что вместо горизонтального направления используется вертикальное.
Рисунок 5.28. Различные варианты размещения вертикальных ящиков с кнопками
Как было сказано ранее, по умолчанию принят стиль GTK_BUTTONBOX_EDGE. Можно поменять используемый по умолчанию стиль. Новый стиль будет применен ко всем кнопкам, стиль которых специально не указан. Для установки стиля по умолчанию существуют две функции: по одной для каждой ориентации. Например, чтобы установить для вертикальных ящиков с кнопками значение START, а для горизонтальных — SPREAD, необходимо сделать следующее:
gtkvbuttonboxsetlayoutdefault(GTK_BUTTONBOX_START);
gtk_hbutton_box_set_layout_default(GTK_BUTTONBOX_SBREAD);
Вы можете выбрать текущую опцию размещения для каждой ориентации ящиков с кнопками:
gint vLayout; gint hLayout;
vLayout = gtk_vbutton_box_get_layout_default();
hLayout = gtk_hbutton_box_get_layout_default();
Как для вертикальных, так для горизонтальных ящиков с кнопками существует интервал, который по умолчанию устанавливается между кнопками. Для горизонтальных ящиков он равен 30 пикселам, для вертикальных — 10, но эти установки могут быть изменены. Например, чтобы установить вертикальный интервал размером 3 пиксела и горизонтальный— 15 пикселов, необходимо сделать следующее:
gtk_vbutton_box_set_spacing_default(3);
gtk_hbutton_box_set_spacing_default(15);
Вы можете выбрать текущие значения интервалов, которые будут устанавливаться по умолчанию:
gint vSpacing;
gint hSpacing;
vSpacing = gtk_vbutton_box_get_spacing_default();
hSpacing = gtk_hbutton_box_get_spacing_default();
Выводы
Все контейнеры предназначены для размещения в них одного или нескольких виджетов, и, в свою очередь, сами контейнеры являются виджетами. Это означает, что один контейнер может находиться в другом контейнере. Например, вы можете поместить некоторые фиксированные контейнеры внутри таблицы, затем включить таблицу в окно прокрутки так, чтобы пользователь мог перемещаться по таблице, а можете поместить текст в записную книжку, что дает возможность работать с несколькими другими доступными окнами через ряд клавиш переключения. После рассмотрения в этой главе различного вида контейнеров напрашиваются следующие выводы:
’ Виджеты можно размещать и группировать почти в любой конфигурации. Это позволяет вам создать простые и понятные окна.
Большая часть работы по размещению виджетов внутри контейнеров автоматизирована, что позволяет вам очень легко разместить виджеты там, где вы хотите. Для большинства контейнеров все сводится к вставке виджетов, проверке полученного результата и подбору опций для получения необходимого вам вида окна.
>г Функции, которые применяются для помещения виджетов в окно, могут использоваться для нескольких контейнеров и имеют имена, позволяющие легко догадаться об их предназначении.
Примеры и объяснения, приведенные в настоящей главе и в главе 4, снабжают вас информацией обо всех инструментах, необходимых для создания окна с любым расположением, какое бы вы ни придумали. В главе 6 объясняется, каким образом можно приспособить ваши виджеты для отправки сообщений от пользователя в приложение.
140
глава События, сигналы, 6в6Ра™ь'е вызовы
В этой главе
Получение и использование событий, посланных вашей программе от мыши или клавиатуры
г Определение источника событий и маршрута, по которому они пришли к вашей программе
Изучение того, как именовать и нумеровать события, чтобы вы могли знать, чего должна ожидать ваша программа
Выдача ваших собственных сообщений о событиях таким образом, чтобы они появились во входной очереди
f • Использование входной очереди событий для внедрения таймеров и фоновой обработки
Эта глава описывает некоторые проблемы, которые возникают при использовании модели событий. Если программа остается постоянно блокированной, ожидая входную информацию из очереди событий, то нет возможности прочитать данные из файлов или каналов связи. Еще одна проблема возникает из-за того, что, когда программа обрабатывает какие-либо данные, она игнорирует очередь событий и также игнорирует ввод со стороны мыши и клавиатуры.
События поступают через очередь событий, транслируются в сигналы, а сигналы, в свою очередь, вызывают функции обратного вызова. Но поскольку количество сигналов, объявленных в программе, может быть значительно и их объявления могут быть разбросаны по всей программе, то иногда бывает очень сложно их отследить. И очень сложно отследить, какие аргументы каким функциям обратного вызова передаются.
Чтение очереди событий
Очередь событий (event queue) — это основа любого приложения. Очередь событий не только получает информацию от мыши и клавиатуры, но может также использоваться в качестве таймера и как метод взаимодействия между процессами.
После инициализации вашего приложения оно вызывает функцию gtk_main (), которая не выполняет возврата до тех пор, пока ваш процесс не остановится. Это можно легко проверить, вставив перед и после вызова функции gtk_main() два следующих оператора печати:
g_print("The call to gtk_main()\n");
gtk_main();
g_print("The return from gtk_main()\n");
Первая строка появляется сразу же после запуска программы; если быть точным, то сразу же после того, как программа сама завершит инициализацию и будет готова к открытию окна. Вторая строка появляется только при завершении программы. Если ваша программа зависает или некорректно завершается, вторая строка не выводится.
Внешние процессы и устройства используют очередь событий для отправки информации в вашу программу. Но очередь имеет статус ’’только для чтения”, следовательно, если необходимо, чтобы ваша программа обменивалась данными с другими программами или устройствами, она должна пользоваться другим методом.
Существуют различные типы событий. Их количество не имеет никакого значения для приложения, поскольку большая часть работы по обработке событий выполняется внутренним обработчиком событий, который имеется в GTK+. Например, если окно выходит на передний план (становится активным), возникает событие, указывающее на необходимость перерисовать все окно или его часть. Но, как правило, приложение не должно беспокоиться по этому поводу, так как об этом позаботится GTK+. Однако иногда бывает необходимо получить больше информации о входящих событиях. Например, если в вашей программе для рисования линий на экране используется ввод с помощью мыши, то необходимо знать, где находится мышь и нажата ли кнопка мыши. Эта информация включается в информацию о событии и передается вашим функциям обратного вызова.
Последовательность диспетчеризации событий
Происходит событие: например, нажатие клавиши на клавиатуре, и программа реагирует на это событие. Одновременно могут работать несколько программ, поэтому необходимо решить, какая именно программа должна получить информацию о событии и каким образом событие будет передаваться в программу. Ниже представлены основные этапы этого процесса.
Этап 1: Указатель мыши передвигается по экрану и нажимается кнопка мыши. Это вызывает аппаратное прерывание.
Этап 2: Драйвер мыши обрабатывает прерывание и посылает стандартно упакованную ' информацию системе. Информация включает в себя координаты х и у, определяющие положения указателя во время щелчка, а также сведения о том, какая кнопка была нажата. Далее драйвер передает информацию соответствующему процессу, в системе X — это менеджер окон.
Этап 3: Менеджер окон размещает все окна на экране и определяет порядок загрузки стека, так как одни окна закрыты другими окнами. Используя географические координаты, менеджер окон определяет, в каком окне был выполнен щелчок. В случае с клавиатурой этот процесс протекает несколько иначе, поскольку информация о координатах отсутствует. В каждый момент времени только одно окно попадает в фокус, именно это окно и получает информацию о нажатиях клавиш на клавиатуре.
Этап 4: При каждом открытии окна приложение посылает информацию менеджеру окон. И таким образом менеджер окон имеет адрес очереди событий для каждого окна.
Менеджер окон преобразовывает данные в стандартный для X формат и ставит их в очередь, связанную с выбранным окном.
Этап 5: Главный цикл приложения использует низкоуровневую функцию системы X для
чтения событий из очереди. Далее по идентификатору окна, который приходит вместе с сообщением, программа определяет, какой из виджетов должен получить сигнал. Затем GTK+ передает информацию функции, например, gtk_signal_emit(), которая преобразует информацию в сигнал и передает его виджету.
Этап 6: Для каждого виджета существует функция, которая получает все поступающие
сигналы. Информация включается в структуру, которая описывает каждый объект.
Этап?: Виджет просматривает список функций обратного вызова, которые связаны с
определенным сигналом, и вызывает все эти функции. Сам факт, что кнопка мыши была нажата, означает, что сигнал достиг своей конечной цели.
ПРИМЕЧАНИЕ НАУЧНОГО РЕДАКТОРА
Упоминаемая здесь и далее система X — это синоним Х11, или X Window.
Выдача ваших собственных сигналов
Существуют разные способы, с помощью которых можно, имитируя событие, генерировать сигнал, не используя очередь событий. Для создания сигнала можно применять функцию gtk_signal_emit(), но в этом случае необходимо знать внутренний числовой идентификатор сигнала. Может быть, проще будет использовать функцию gtk_signal_emit_by_name (), которой необходимо знать всего лишь текстовое наименование сигнала и указатель на объект, который должен получить сигнал. Приведенный ниже пример демонстрирует, каким образом вы можете послать свой собственный сигнал:*
/*♦ simsignal.c **/
Iinclude <gnome.h>
3
GtkWidget *makeButtonBox();
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
void buttonFirstCallback(GtkWidget *widget,
GdkEvent *event,gpointer data);
void buttonSecondCallback(GtkWidget *widget,
GdkEvent *event,gpointer data);
13
GtkWidget *buttonFirst;
GtkWidget *buttonSecond;
16
int main(int argc,char *argv[])
{
GtkWidget *window;
GtkWidget *buttonbox;
21
22gnome_init("simsignal","1.0",argc,argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_signal_connect(GTK_OBJECT(window), "delete_event",
GTK_SIGNAL_FUNC(eventDelete),NULL);
gtk_signal_connect(GTK_OBJECT(window),"destroy",
GTK_SIGNAL_FUNC(eventDestroy),NULL);
28
buttonbox = makeButtonBox();
30
gtk_container_add(GTK_CONTAINER(window),buttonbox);
gtk_widget_show_all(window);
gtk_main();
exit(0);
}
GtkWidget *makeButtonBox() {
GtkWidget *buttonbox;
38
buttonbox = gtk_hbutton_box_new();
gtk_container_set_border_width(
GTK_CONTAINER(buttonbox), 10);
42
buttonFirst = gtk_button_new_with_label("First");
gtk_container_add(GTKCONTAINER(buttonbox),
buttonFirst);
gtk_signal_connect(GTK_OBJECT(buttonFirst),
"clicked",
GTK_SIGNAL_FUNC(buttonFirstCallback),
NULL);
50
buttonSecond = gtk_button_new_with_label("Second");
gtk_container_add(GTK_CONTAINER(buttonbox),
buttonSecond);
gtksignalconnect(GTK_OBJECT(buttonSecond),
"clicked",
GTKSIGNALFUNC(buttonSecondCallback),
NULL);
58
9return(buttonbox);
}
void buttonFirstCallback(GtkWidget *widget,
GdkEvent *event,gpointer data) {
g_print("Clicked: FirstXn");
}
void buttonSecondCallback(GtkWidget *widget,
GdkEvent *event,gpointer data) {
gtk signal emit by name(GTK_OBJECT(buttonFirst),
"clicked");
g_print("Clicked: SecondXn");
}
71
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data) {
return(FALSE);
}
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data) {
gtk_main_quit();
return(0);
}
Функция makeButtonBox (), начинающаяся в строке 36, создает окно с двумя кнопками. С нажатием каждой кнопки связана соответствующая функция обратного вызова: для кнопки ’’First” используется buttonFirstCallback(), для кнопки ’’Second" — buttonSecondCallback().
Функция buttonFirstCallback(), которая начинается со строки 61, реагирует на сигнал, выдавая строку, идентифицирующую нажатую кнопку. Функция buttonSecondCallback( ) в строке 65 также выдает строку, идентифицирующую саму себя, но, помимо этого, в строке 67 имеется обращение к функции gtk_signal_emit_by_name (), которая генерирует сигнал щелчка, передаваемый buttonFirst. Это означает, что, когда бы ни была нажата вторая кнопка, первая кнопка действует так, как если бы она была нажата.
При работе программы каждый щелчок мышью выводит на экран одну или две строки. Щелчок, производимый второй кнопкой, вынуждает первую кнопку выводить строку до того, как это сделает вторая кнопка. Это происходит потому, что функция обратного вызова вызывается напрямую, а не асинхронно через очередь событий. Часть программы, которая следует после вызова функции gtk_signal_emit_by_name(), должна ждать завершения обработки сигнала и последующего возврата функции.
Сигналы и функции обратного вызова могут быть использованы для обеспечения связей между отдельными частями программы, не требуя добавления некоторого специального кода в код виджета. Если действие виджета определено как обратный вызов, просто выдайте сигнал, который напрямую вызовет функцию обратного вызова. И даже при внесении каких-либо изменений в виджет (например, удаление или добавление функций обратного вызова) все продолжает корректно работать.
ПРИМЕЧАНИЕ
Будьте осторожны при генерации сигналов подключения внутри программы. Функция обратного вызова, которая генерирует свой собственный сигнал, рекурсивна, то есть вызывает сама себя. Кроме того, если функция обратного вызова по имени А генерирует сигнал для обращения к функции обратного вызова В, которая, в свою очередь, генерирует сигнал вызова функции А, — возникает бесконечный цикл, приводящий к краху (зависанию) программы. Такой бесконечный цикл может возникнуть независимо от количества обратных вызовов. Если функция обратного вызова А вызывает функцию обратного вызова В, функция В вызывает С, а функция С вновь вызывает А, то произойдет аварийное завершение программы.
Наименования и идентификаторы сигналов
Чтобы иметь возможность использовать в приложении сигналы, необходимо написать функции обратного вызова, возвращаемые значения и аргументы которых соответствуют возвращаемым значениям и аргументам, определенным для сигнала. К сожалению, не существует общего стандартного определения функции обратного вызова, поэтому иногда бывает сложно выяснить, что требуется. Поскольку вызов функции обратного вызова происходит в процессе выполнения программы, компилятор не может проверить, правильно ли заданы тип возвращаемого значения и число параметров.
В каждом классе виджетов определен свой собственный набор сигналов и каждый виджет наследует сигналы своего родительского класса. Например, виджет GtkButton определяет свои собственные сигналы clicked (по щелчку), pressed (нажатие кнопки или клавиши), released (освобождение ранее нажатой кнопки или клавиши), enter (вход
в пределы кнопки), leave (выход за пределы кнопки) и наследует сигналы от GtkBin, GtkContainer, GtkWidget и GtkObject. В классе GtkBin отсутствуют сигналы, в классе GtkContainer их 5, в классе GtkWidget — 54 и в классе GtkObject — 1. Всего существует 65 сигналов, все из которых доступны внутри виджета GtkButton.
Сигналы определяются динамически во время выполнения. При создании первого объекта какого-либо класса все сигналы, которыми может пользоваться данный класс, добавляются во внутренние таблицы.
Форматы функций обратного вызова
Каждая функция обратного вызова имеет два общих параметра, но многие из функций имеют помимо этих и свои дополнительные параметры. Прототип самой простой функции обратного вызова выглядит следующим образом:.
void cb(GtkWidget *,gpointer);
В других функциях обратного вызова могут быть дополнительные параметры, которые всегда вставляются между этими двумя стандартными параметрами. Вот образец прототипа для функции обратного вызова, которая в качестве параметра принимает GdkEvent:
void cb(GtkWidget *,GdkEvent *,gpointer);
Кроме того, функция обратного вызова может возвращать значение типа void, gint или boolean. Вот прототип для функции обратного вызова “drag-and-drop”, определенной в классе GtkWidget:
gboolean cb(GtkWidget *,GdkDragContext *,gint,gint,guint,gpointer);
ПРИМЕЧАНИЕ НАУЧНОГО РЕДАКТОРА
"Krag-and-drop" — этот термин подразумевает перетаскивание, или перемещение, элементов изображения (пиктограмм, окон) в заданное место при помощи указателя мыши.
За всеми форматами функций обратного вызова уследить достаточно сложно хотя бы по той простой причине, что в исходном коде программы функции обратного вызова определяются не в одном месте, поскольку каждый виджет имеет свой набор сигналов и определений функций обратного вызова. Эти объявления находятся и внутри объектов GTK+, и внутри объектов GNOME (иногда и не только внутри графических виджетов), и внутри других сервисных функций, в которых объявлены их собственные сигналы. И если вы сами создаете виджеты, то будете вводить свои собственные сигналы и функции вместе с библиотеками, пришедшими с их собственными наборами объектов с функциями обратного вызова.
С помощью приведенной ниже программы можно определить иерархию наследования классов и формат функций обратного вызова для любого набора выбранных объектов. Для этого создается каждый из типов объектов (при этом регистрируются данные о сигналах), и далее программа считывает информацию с внутренней таблицы и выводит отсортированный список имен объектов, иерархию наследования объектов, наименования сигналов и прототип функции обратного вызова.
/** signames.с **/
Iinclude <gnome.h>
3
typedef struct SigDescStruct {
struct SigDescStruct «left;
struct SigDescStruct «right;
gchar*signal_name;
gchar*type_name;
gchar*parent_type_name;
gchar*fn;
} SigDesc;
12
static SigDesc «sigdesc = NULL;.
static gchar last_name_printed[100] = "";
15
static void loadsignals();
static void add_siglist(const gchar *signal_name,
const gchar *type_name,
const gchar *parent_type_name,constgchar *fn);
static void add_sigdesc_totree(SigDesc «new,
SigDesc «node);
static void print_signals(SigDesc *sd,FILE «file);
static gchar «inheritance(GtkType type);
24
void signames(FILE «file)
{.
load_signals();
print_signals(sigdesc,file);
}
static void widget_list()
{
gtk_button_new();
33gtk_calendar_new();
34 }
35 int main(int argc,char *argv[])
36 {
37gnome_init("signames","1.0",argc,argv);
38widget_list();
39signames(stdout);
40exit(0);
41 }
static void load_signals()
{
gint i =0;
gint j;
gchar*type_name;
gchar*parent_type_name;
gchar*return_type_name;
gchar*param_name;.
50gcharfn[256);
51GtkSignalQuery*q;
5Z
53while((q= gtk_signal_query(++i)) != NULL) {
54typename = gtk_type_name(q->objecttype);
55return_type_name = gtk_type_name(q->return_val);
56parenttypename = inheritance(q->objecttype);
57sprintf(fn,"%s cb(GtkWidget *",returntypename);
58for(j=0; j<q->nparams; j++) {
59param_name = gtk_type_name(q->params[j]);
60strcat(fn,",");
streat(fn,paramname);
}
6364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912063646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120strcat(f п, ",gpointer)");
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
add_siglist(q->signal_name,type_name,parent_type_name,fn);
}
}
static void add_siglist(const gchar *signal_name, const gchar *type_name, const gchar *parent_type_name,const gchar *fn)
{
SigDesc *new_sigdesc;
new_sigdesc = gmalloc(sizeof(SigDesc));
new_sigdesc->signal_name =
g_malloc(strlen(signal_name)+1);
strcpy(new_sigdesc->signal_name,signal_name);
new_sigdesc->type_name = g_malloc(strlen(type_name) +1); strcpy(new_sigdesc->type_name,type_name);
new_sigdesc->fn = g_malloc(strlen(fn)+l); strcpy(new_sigdesc->fn,fn);
if(parent_type_name == NULL) { new_sigdesc->parent_type_name = NULL;
} else {
new_sigdesc->parent_type_name =
gmalloc(strlen(parent_type_name)+1); strcpy(new_sigdesc->parent_type_name, parent_type_name);
}
new_sigdesc->left = NULL;
new_sigdesc->right = NULL;
if(sigdesc == NULL) { sigdesc = newsigdesc;
} else { add_sigdesc_to_tree(new_sigdesc,sigdesc);
}
}
static void add_sigdesc_to_tree(SigDesc *new,SigDesc *node) {'
int cond;
if((cond = strcmp(new->type_name, node->type_name)) < 0) { if(node~>left == NULL)
node->left = new;
else
addsigdesctotree(new,node->left);
} else if(cond > 0) {
if(node->right == NULL) node->right = new;
else
add_sigdesc_to_tree(new,node->right);
} else if((cond = strcmp(new->signal_name, node->signal_name)) < 0) { if(node->left == NULL) node->left = new;
else
add_sigdesc_to_tree(new,node->left);
} else if(cond > 0) {
121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178if(node->right == NULL) node->right = new; else add_sigdesc_to_tree(new,node->right);
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
}
}
static void print_signals(SigDesc *sd,FILE *file) <
int i;
int j;
gchar string[256];
if(sd 1= NULL) {
print_signals(sd->left,file);
if(strcmp(last-name_printed,sd->type-name)) { fprintf(file,"\n%s(->%s)\n",
sd->type_name,sd->parent_type-name);
strcpy(last-name-printed,sd->type_name);
}
sprintf(string," \"%s\" %s", sd->signal_name,sd->fn);
if(strlen(string) > 63) { for(i=63; i>0; i—) { if(string[i] == ',') { for(j = strlen(string); j > i; j—) string[j+9] = string[j];
string[i+l] = '\n'; for(j=2; j<10; j++) string[j+i] = ' ';
break;
} }
}
fprintf(file,"%s\n",string);
print-Signals(sd->right,file);
}
static gchar *inheritance(GtkType type) {
GtkType parent-type;
gchar *parent-type_name;
static gchar string[256];
string[0] = '\0';
while(l) {
parent-type = gtk-type_parent(type);
parent_type-name = gtk-type-Пате(parent-type); if(parent-type-name == NULL) break;
if(strlen(string) > 1) { strcat(string,"->"); strcat(string,parent-type_name);
} else {
strcpy(string,parent-type_name);
}
type = parent-type;
}
179if(strlen(string) > 1)
180return(string);.
181return("none");
182 }
Функция main(), начинающаяся co строки 35, как и обычно для любого приложения GNOME, вызывает функцию gnome_init{) для инициализации GNOME и GTK+. Далее для инициализации информации о сигналах вызывается функция widget_list(), создающая образцы объектов. Для генерации вывода вызывается функция signames (). В теле самой функции signames (), начинающейся в строке 25, вызывается функция load_signals(), чтобы получить информацию о сигналах и сохранить эти данные в отсортированном списке. И, наконец, для передачи информации о сигналах из отсортированного списка на стандартный вывод вызывается функция print^signaIs ().
Вы можете добавлять или удалять виджеты, включаемые в выходной список, путем обращений, добавляющих или удаляющих виджеты, к функции widget_list() в строке 30. В данном примере используются два обращения: одно — для создания кнопки, другое — для создания календаря. Нет необходимости сохранять возвращаемый виджет, поскольку он необходим классу только для собственной инициализации, определяющей во внутренних таблицах список обратных вызовов.
ПРИМЕЧАНИЕ
Эта программа была написана как отдельная программа, но с небольшими изменениями ее можно откомпилировать и скомпоновать для запуска из вашего приложения. Для этого, удалив функции main() и widget_lisf(), откомпилируйте и скомпонуйте ее с вашей программой. Прямо перед входом в главный цикл вашего приложения после того, как созданы все объекты, добавьте код для открытия файла и вызовите функцию signamesQ, которая выведет информацию об обратных вызовах. Например:
FILE *file;
file = fopen("cbfile","w");
signames(file);
fclose(file); gtk_main();
Функция load_signals(), которая начинается co строки 42, считывает информацию по сигналам и функциям обратного вызова из внутренних таблиц. Каждому новому сигналу присваивается числовой идентификатор. Нумерация начинается с 1. Это означает, что цикл, который начинается со строки 53, пройдет через все идентификационные номера, начиная с 1, пока не будет обнаружен неприсвоенный идентификатор. Функция gtk_signal__query (), которая вызывается в начале цикла, возвращает структуру GtkSignalQuery, содержащую информацию об обратном вызове.
Кое-какая информация доступна в структуре GtkSignalQuery. В строке 54 функция gtk_type_name () по идентификатору типа объекта извлекает наименование объекта. Функция gtk_type_name () в строке 55 возвращает тип имени по функции обратного вызова. Обращение к функции inheritance () в строке 56 возвращает строку для GtkOb ject, содержащую список унаследованных объектов.
Функция inheritance (), начинающаяся в строке 159, для выяснения родословной объекта проходит по всем родительским связям этого объекта. В качестве аргумента передается тип объекта, который и используется как отправной указатель. Обращение к функции gtk_type_parent () в строке 16? возвращает тип идентификатора родитель-
ского объекта, а обращение к функции gtk_type_name () в строке 168 извлекает его имя. После извлечения каждое имя добавляется в строку имен, которая отражает всю иерархию наследования.
В строке 57 начинается создание вызова прототипа функции путем печати строки с возвращаемым значением и первым параметром. Если функции требуются другие параметры помимо двух заданных по умолчанию, то в цикле в строках с 58 по 62 они добавляются в строку. Вызов функции gtk_type_name () в строке 59 используется для определения типа каждого из параметров. Теперь отсутствует лишь одна порция информации. По данным, содержащимся в структуре GtkSignalQuery, нельзя определить, является ли параметр указателем. Эта информация существует, но находится в статическом массиве gtk_signals в исходном файле GTK по имени gtksignals • с, и нет никакой возможности извлечь эту информацию, не меняя gtksignals • с. Существует и другая версия этой же программы под именем signames2. с, в исходном коде которой имеются комментарии, описывающие изменения, которые необходимо выполнить, чтобы она работала.
Функция add_siglist (), которая начинается со строки 68, создает для сигнала новый узел и добавляет его в дерево. В строках с 74 по 91 создается узел и заполняется значениями. В строках с 93 по 97 с помощью функции add_sigdesc_to_tree () узел добавляется к дереву.
Функция add_sigdesc_to_tree(), начинающаяся в строке 99, проходит двоичное дерево и добавляет новый компонент в нужное место. Дерево сначала сортируется по имени типа объекта, генерирующего данный сигнал, а затем — по имени самого сигнала. Таким образом, сигналы располагаются в алфавитном порядке и сгруппированы по типам их объектов.
Вывод создается с помощью функции print^signals (), которая начинается со строки 127. Функция print_signals () рекурсивная и принимает узел дерева в качестве аргумента. Функция выполняет три операции: смотрит налево, печатает текущий узел, а затем смотрит направо. Первую операцию она выполняет, вызывая саму себя в строке 134 с указателем left (налево). Печать выполняется в строках со 135 по 153. В строке 135 функция сравнивает имя последнего напечатанного объекта с именем текущего объекта и печатает его только в том случае, если имена отличаются — так создается заголовок имен объектов для каждой группы сигналов. Если длина строки слишком большая, — в данном примере набор из 64 символов считается слишком длинной строкой, — она разбивается на части после первой запятой левее 63-го символа. В конце функция смотрит направо, вызывая саму себя в строке 155.
Вывод программы выглядит следующим образом:
GnomeClient(->GtkObject)
"connect" void cb(GtkWidget *,gboolean,gpointer)
"die" void cb(GtkWidget *,gpointer)
•"disconnect" void cb(GtkWidget *,gpointer)
"save-complete" void cb(GtkWidget *,gpointer)
"save-yourself" gboolean cb(GtkWidget *,gint,GtkEnum, gboolean,GtkEnum,gboolean,gpointer)
"shutdown-cancelled" void cb(GtkWidget *,gpointer)
GtkButton(->GtkBin->GtkContainer->GtkWidget->GtkObject)
"clicked" void cb(GtkWidget *,gpointer)
"enter" void cb(GtkWidget *,gpointer)
"leave" void cb(GtkWidget *,gpointer)
"pressed" void cb(GtkWidget *,gpointer)
"released" void cb(GtkWidget *,gpointer)
GtkCalendar(->GtkWidget->GtkObject)
"day-selected" void cb(GtkWidget *,gpointer) "day-selected-double-click" void cb(GtkWidget *,gpointer) "month-changed" void cb(GtkWidget *,gpointer) "next-month" void cb(GtkWidget *,gpointer) "next-year" void cb(GtkWidget *,gpointer) "prev-month" void cb(GtkWidget *,gpointer) "prev-year" void cb(GtkWidget *,gpointer)
GtkContainer(->GtkWidget->GtkObject)
"add" void cb(GtkWidget *,GtkWidget,gpointer) "check-resize" void cb(GtkWidget *,gpointer) . "focus" GtkDirectionType cb(GtkWidget *,GtkDirectionType, gpointer)
"remove" void cb(GtkWidget *,GtkWidget,gpointer)
"set-focus-child" void cb(GtkWidget *,GtkWidget,gpointer)
GtkObject (->none)
"destroy" void cb(GtkWidget *,gpointer)
GtkWidget (->GtkObject)
"add-accelerator" void cb(GtkWidget *,guint,GtkAccelGroup, guint,GdkModifierType,GtkAccelFlags,gpointer)
"button-press-event" gboolean cb(GtkWidget *•, GdkEvent, gpointer)
"button-release-event" gboolean cb(GtkWidget *,GdkEvent, gpointer)
"client-event" gboolean cb(GtkWidget *,GdkEvent,gpointer) "configure-event" gboolean cb(GtkWidget *,GdkEvent,gpointer) "debug-msg" void cb(GtkWidget *,GtkString,gpointer) "delete-event" gboolean cb(GtkWidget *,GdkEvent,gpointer) "destroy-event" gboolean cb(GtkWidget *,GdkEvent,gpointer) "drag-begin" void cb(GtkWidget *,GdkDragContext,gpointer) "drag-data-delete" void cb(GtkWidget *,GdkDragContext, gpointer)
"drag-data-get" void cb(GtkWidget *,GdkDragContext, GtkSelectionData,guint,guint,gpointer)
"drag-data-received" void cb(GtkWidget *,GdkDragContext,gint, gint,GtkSelectionData,guint,guint,gpointer)
"drag-drop" gboolean cb(GtkWidget *,GdkDragContext,gint,gint, guint,gpointer)
"drag-end" void cb(GtkWidget *,GdkDragContext,gpointer) "drag-leave" void cb(GtkWidget *,GdkDragContext,guint, gpointer)
"drag-motion" gboolean cb(GtkWidget *,GdkDragContext,gint, gint,guint,gpointer)
"draw" void cb(GtkWidget *,gpointer,gpointer) "draw-default" void cb(GtkWidget *,gpointer) "draw-focus" void cb(GtkWidget *,gpointer) "enter-notify-event" gboolean cb(GtkWidget *,GdkEvent, gpointer)
"event" gboolean cb(GtkWidget *,GdkEvent,gpointer) "expose-event" gboolean cb(GtkWidget *,GdkEvent,gpointer) "focus-in-event" gboolean cb(GtkWidget *,GdkEvent,gpointer) "focus-out-event" gboolean cb(GtkWidget *,GdkEvent,gpointer) "grab-focus" void cb(GtkWidget *,gpointer)
"hide" void cb(GtkWidget ♦,gpointer)
"key-press-event" gboolean cb(GtkWidget *rGdkEvent,gpointer) "key-release-event" gboolean cb(GtkWidget *,GdkEvent, gpointer)
"leave-notify-event" gboolean cb(GtkWidget *,GdkEvent, gpointer)
"map" void cb(GtkWidget *,gpointer)
"map-event" gboolean cb(GtkWidget *,GdkEventrgpointer) "motion-notify-event" gboolean cb(GtkWidget *,GdkEvent, gpointer)
"no-expose-event" gboolean cb(GtkWidget *rGdkEvent,gpointer)
"parent-set" void cb(GtkWidget *,GtkObject,gpointer) "property-notify-event" gboolean cb(GtkWidget *,GdkEvent, gpointer)
"proximity-in-event" gboolean cb(GtkWidget *,GdkEvent, gpointer)
"proximity-out-event" gboolean cb(GtkWidget *,GdkEvent, gpointer)
"realize" void cb(GtkWidget *,gpointer)
"remove-accelerator" void cb(GtkWidget *,GtkAccelGroup,guint,
GdkModifierType,gpointer)
"selection-clear-event" gboolean cb(GtkWidget *,GdkEvent, gpointer).
"selection-get" void cb(GtkWidget *,GtkSelectionData,guint, guint,gpointer)
"selection-notify-event" gboolean cb(GtkWidget *,GdkEvent, gpointer)
"selection-received" void cb(GtkWidget *,GtkSelectionData, guint,gpointer)
"selection-request-event" gboolean cb(GtkWidget *,GdkEvent, gpointer)
"show" void cb(GtkWidget *,gpointer)
"size-allocate" void cb(GtkWidget *,gpointer,gpointer)
"size-request" void cb(GtkWidget *,gpointer,gpointer)
"state-changed" void cb(GtkWidget *,GtkStateType,gpointer)
"style-set" void cb(GtkWidget *,GtkStyle,gpointer)
"unmap" void cb(GtkWidget *,gpointer)
"unmap-event" gboolean cb(GtkWidget *,GdkEvent,gpointer)
"unrealize" void cb(GtkWidget ♦,gpointer)
"visibility-notify-event" gboolean cb(GtkWidget *,GdkEvent, gpointer)
Как и ожидалось, приведенный список содержит элемент для GtkButton и GtkCalendar, поскольку именно эти два объекта инициализируются перед созданием списка. Для каждого объекта приведена иерархия наследования. Например, GtkButton происходит от GtkBin, который, в свою очередь, происходит от GtkWidget, который происходит от GtkOb ject. Это означает, что в вашей программе можно преобразовать GtkButton в любой из этих типов и использовать их сигналы для установки обратных вызовов. То есть, корректные преобразования для объекта GtkButton следующие:
GTK_BUTTON(button)
GTK_BIN(button)
GTK_WIDGET(button)
GTKOBJECT(button)
Для кнопки определено пять сигналов. Сигналы ’’enter” и ’’leave” создают обратные вызовы всякий раз, когда указатель мыши входит в прямоугольник кнопки и покидает его.
Остальные обратные вызовы генерируются при нажатии на кнопки мыши, когда указатель мыши находится в прямоугольнике кнопки. Функции обратного вызова для GtkButton не возвращают никаких значений и принимают по умолчанию только два аргумента.
Поскольку объекты GtkButton и GtkCalendar произошли от других объектов, сигналы для них всех также были инициализированы и попали в список. Объект GnomeClient не находится в родословной ни одного из инициализированных нами объектов. Существует несколько специальных обратных вызовов GNOME, которые инициализируются функцией gnome__init (). Отметьте также, что каждая цепочка наследования тянется от GtkOb ject, то есть, к любому виджету можно обратиться через этот набор обратных вызовов. GtkOb ject — это единственный объект без предка.
Фоновая обработка в течение периода простоя
Если вам необходимо запустить несколько процессов одновременно и в то же время необходимо продолжать реагировать на события мыши, то следует выполнять процессы в фоновом режиме, что достигается с помощью функции простоя (idle Junction). В это время очередь событий пуста и приложение просто ждет возникновения событий.
Проблемой фонового запуска процессов является то, что ваше приложение занято, будучи блокировано в процессе ожидания событий. Решение указанной проблемы — функция, которая позволяет зарегистрировать вашу функцию простоя и вызвать ее из GTK+ в любой подходящий момент (то есть, когда очередь событий пуста). Все это хорошо, но при выполнении функции никакие входящие события не обрабатываются. Однако существует способ передачи время от времени управления от функции к программе в целях проверки и обработки входящих событий.
Следующая программа демонстрирует регистрацию функции простоя и передачу управления от нее к обработке очереди событий.
/♦* idle.с **/
linclude <gnome.h>
3
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
void eventButton(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint idleFunction(gpointer data);
11
int main(int argc,char *argv[])
{
GtkWidget *window;
GtkWidget *button;
16
gnome_init("idle","1.0",argc,argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_signal_connect(GTK_OBJECT(window),
"delete_event",
GTK SIGNAL FUNC(eventDelete),
NULL);
gtk_signal_connect(GTK_OBJECT(window),
"destroy",
GTK_SIGNAL_FUNC(eventDestroy),
26NULL);
27button = gtk_button_new_with_label("Button");
28gtk_signal_connect(GTK_OBJECT(button),
29"clicked",
30GTK_SIGNAL_FUNC(eventButton),
31NULL);
32gtk_container_add(GTK_CONTAINER(window),button);
33gtk_container_set_border_width(GTK_CONTAINER(window),
3425);
35gtk_widget_show_all(window);
36
37gtk_idle_add(idleFunction,NULL);
38
39gtk_main();
40exit(0);
41 }
42 void eventButton(GtkWidget *widget,
43GdkEvent *event,gpointer data)
44 {
45 g_print("Button pressed!\n");
46 }
47 gint idleFunction(gpointer data)
48 {
49gint i;
50static gint counter =1;
51
52for(i=0; i<5; i++) {
53g_print("Counter%d in loop number %d\n",
54counter,i+1);
55sleep(l);
56}
57if(counter++ <5)
58return(TRUE);
59return(FALSE);
60 }
61 gint eventDelete(GtkWidget *widget,
62GdkEvent *event,gpointer data) {
63 return(FALSE);
64 }*
65 gint eventDestroy(GtkWidget *widget,
66GdkEvent *event,gpointer data) {
67gtk_main_quit();
68return(O);
69 }
Отображаемое окно содержит только одну кнопку. Обращение к функции gtk_signal_connect() в строке 28 назначает функцию eventButton() из строки 42 как ту, что будет вызываться каждый раз при щелчке кнопки. Эта функция обратного вызова всего лишь посылает строку сообщения на стандартный вывод.
Функция простоя добавляется с помощью обращения к gtk_idle__add() в строке 37. Первый аргумент — имя функции простоя, второй — указатель на данные; аргументы должны передаваться функции простоя при ее вызове.
Имя функции простоя — idleFunction (), и начинается она со строки 47. Для имитации интенсивной обработки функция простоя ежесекундно вызывает функцию sleep (). Этим достигается тот же эффект, как в случае программы обработки записей БД, большой сортировки-слияния или других трудоемких операций. В программе имеются стати-
ческая переменная counter, которая подсчитывает количество вызовов функции, и счетчик цикла i, с помощью которого перед каждым секундным интервалом ожидания осуществляется печать строки.
Функция простоя вызывается снова и снова так долго, пока возвращает TRUE. И перестает вызываться после возвращения FALSE. Таким способом функция может быть назначена для пошагового выполнения своей задачи, ибо после возврата в систему вызывается вновь.
Запустив эту программу, можно увидеть, что во время работы функции простоя никакие события не обрабатываются. Функция gtk_main () просматривает очередь событий и, ничего не найдя в ней, вызывает функцию простоя и ожидает ее завершения. Если функция возвращает FALSE, она удаляется из списка функций простоя и никогда больше не вызывается. Если же функция возвращает TRUE, она вызывается вновь, как только очередь событий становится пуста. Если щелкнуть кнопкой несколько раз во время работы функции простоя, на первый взгляд ничего не произойдет. Но на самом деле события мыши ставятся в очередь и будут обработаны только после того, как функция простоя передаст управление циклу обработки событий. Такая блокировка приложения влияет не только на кнопку, но и на другие виджеты, на выбор меню наверху окна.
Таймеры
Установив таймеры (timers), можно в будущем генерировать обратные вызовы в определенный момент времени. Такой метод работает при помещении события в очередь входящих событий, а в главном цикле программы это событие начнет обрабатываться только по прошествии определенного периода времени. В приложении может работать несколько таймеров одновременно, и они никоим образом не будут мешать текущей обработке.
Приведенная ниже программа демонстрирует механизм, который используется для запуска и останова таймеров. В программе имеется два таймера: один с интервалом в 1 секунду, а второй — с интервалом 10 секунд. Результаты, представленные на рис. 6.1, получены путем отображения времени каждого обратного вызова, когда бы ни истекло время таймера. Односекундный таймер обновляет текст в верхней строке, а десятисекундный — в нижней. Каждый сигнал десятисекундного таймера запускает или останавливает односекундный таймер. При запуске программы первые 10 секунд ничего не происходит. По истечении этого интервала десятисёкундный таймер обновляет изображение на экране и запускает односекундный таймер. Односекундный таймер последовательно обновляет изображение до тех пор, пока десятисекундный таймер его не остановит.
/** timing.с **/
Mon NOV 8 04.40:36 1999 Mon Nov 8 04:40:25 1999 -Mon NOV 8 04.40:36 1999 Mon Nov 8 04:40:25 1999 -linclude <gnome.h> 3
Mon NOV 8 04.40:36 1999 Mon Nov 8 04:40:25 1999 -
Mon NOV 8 04.40:36 1999 Mon Nov 8 04:40:25 1999 -
GtkWidget *makeDisplay();
gint eventDelete(GtkWidget *widget,
Рисунок 6.1.Запуск и останов таймеровРисунок 6.1.Запуск и останов таймеровGdkEvent *event,gpointer data);
Рисунок 6.1.
Запуск и останов таймеров
Рисунок 6.1.
Запуск и останов таймеров
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
9
gint oneSecondCallback(gpointer data);
gint tenSecondCallback(gpointer data);
12
static gint oneSecondTag;
static gint tenSecondTag;
static GtkWidget ‘oneSecondLabel;
static GtkWidget ‘tenSecondLabel;
17
static gboolean oneSecondRunning = FALSE;
19
int main(int argc,char *argv[])
{
GtkWidget ‘window;
GtkWidget ‘display;
24
25gnome_init("timing","1. 0",argc,argv);1
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_container_set_border_width(GTK_CONTAINER(window),
20);
9gtk_signal_connect(GTKOBJECT(window),"delete_event",
GTK_SIGNAL_FUNC(eventDelete),NULL);
gtk_signal_connect(GTK_OBJECT(window),"destroy",
GTK_SIGNAL_FUNC(eventDestroy),NULL);
display = makeDisplay();
gtk_container_add(GTK_CONTAINER(window),display);
gtk_widget_show_all(window);
gtk_main();
exit(0);
}
GtkWidget ‘makeDisplay() {
GtkWidget ‘box;
41
box = gtk_vbox_new(FALSE,0);
43
oneSecondLabel = gtk_label_new("OneSecond Timer");
gtk box pack start(GTK_BOX(box),oneSecondLabel,
FALSE,FALSE,0);
47
tenSecondLabel = gtk_label_new("Ten Second Timer");
9gtk boxpackstart(GTKBOX(box),tenSecondLabel,
FALSE,FALSE,0);
tenSecondTag = gtk_timeout_add(10000,
(GtkFunction)tenSecondCallback,NULL);
53
return(box);
}
gchar *getTimeString()
{
struct tm *t;
time_t tt;
gchar ‘string;
61»
tt = time(NULL);
t = localtime(&tt);
string = asctime(t);
string[strlen(string)-l] = '\0';
return(string);
}
gint oneSecondCallback(gpointer data)
{
gtk_label_set_text(GTK_LABEL(oneSecondLabel),
getTimeString());
return(TRUE);
}
gint tenSecondCallback(gpointer data)
{
gtk_label_set_text(GTK_LABEL(tenSecondLabel),
getTimeString());
if(oneSecondRunning) {
gtk_timeout_remove(oneSecondTag);
oneSecondRunning = FALSE;
81} else {
82oneSecondTag = gtk_timeout_add(1000,
83(GtkFunction)oneSecondCallback,NULL);
84oneSecondRunning = TRUE;
85}
86return(TRUE);
87 }
88
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data) {
return(FALSE);
}
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data) {
gtk_main_quit();
return(0);
}
Окно, которое создается функцией makeDisplay() в строке 39, содержит две метки в вертикальном ящике. Вызов функции gtk_timeout_add() в строке 51 устанавливает таймер с периодом 10000 миллисекунд (10 секунд). При срабатывании таймер вызывает функцию обратного вызова tenSecondCallback(). Последний аргумент функции (значение NULL) — необязательный указатель на данные, стандартный для всех функций обратного вызова.
Функция getTimeString () в строке 56 отражает принятую договоренность по дате. Она создает строку символов, содержащую текущую дату и время, без использования традиционного \п в конце строки.
Функция обратного вызова oneSecondCallback() в строке 68, вызывая функцию gtk_label_set_text () и используя строку с датой и временем, обновляет текст метки. Возвращаемое значение TRUE говорит системе, что таймер, вызвавший эту функцию, должен быть запущен заново и по прошествии заданного периода времени снова вызвать эту же функцию. Возвращаемое значение FALSE останавливает таймер и обратный вызов происходит только в случае, если это специально запланировано.
Функция обратного вызова) tenSecondCallback() в строке 74 делает то же, что и функция oneSecondCallback(), и, кроме того, запускает или останавливает односекундный таймер. Если односекундный таймер запущен (на что указывает булева переменная oneSecondRunning), то он останавливается, если таймер не запущен, он запускается. Односекундный таймер останавливается с помощью вызова функции gtk_timeout_remove () в строке 79, используя тег, возвращенный в строке 82 функцией gtk__timeout_add(), запустившей таймер.
Чтение данных из файла или сокета
В Linux существует много способов получения программой данных из другого места. Можно иметь программу, считывающую данные из файла, в который записываются результаты работы другой программы. Можно также создать сокет, использовать его для установки TCP/IP соединения и работать через сетевое подключение. Существуют также файлы FIFO (first-in first-out, "первым вошел — первым вышел") и конвейеры. Чтобы программа могла читать данные с одного из этих источников, она должна или заблокироваться и постоянно читать данные, или периодически проверять ввод, не поступили ли данные.
ПРИМЕЧАНИЕ НАУЧНОГО РЕДАКТОРА
Буфер FIFk используется для того, чтобы позволить нескольким одновременно работающим процессам обмениваться информацией друг с другом или с некоторым управляющим процессом.
В операционной системе Unix программный интерфейс доступа к сетевым функциям называется coKeT(socket). Тип сокета тесно связан с привлекаемым сетевым протоколом(ТСР, UKP).
Одной из проблем, связанных с очередью событий, является тот факт, что ваш процесс не может заблокироваться и ожидать получения данных из другого источника. Если необходимо считывать данные с сокета или файла по мере их поступления, нельзя просто заблокировать программу и ждать входную информацию, поскольку программа не сможет обрабатывать события. Программа будет казаться зависшей, так как она не будет реагировать ни на мышь, ни на ввод с клавиатуры. Можно воспользоваться обратным вызовом по таймеру, как было описано в предыдущем разделе, но такое решение имеет два недостатка. Во-первых, будет добавлен еще один процесс, постоянно вызывающий функции, во-вторых, новые данные могут быть обнаружены только после истечения определенного интервала времени, который установлен для таймера.
В библиотеке GDK есть средство, которое может генерировать обратный вызов всякий раз, когда входные данные становятся доступными в сокете или в файле. Этот механизм аналогичен для файлов и сокетов: в обоих случаях ведется обработка, при которой в качестве дескриптора файла используется переменная типа int.
Следующая программа демонстрирует применение этого механизма. Для простоты используется стандартное устройство ввода, которое уже открыто. Программа выводит окно с одной кнопкой. Программа реагирует на нажатие кнопки и в то же время считывает данные со стандартного устройства ввода.
1 /*♦ inputadd.с **/
linclude <fcntl.h>
#include <gnome.h>
4
gint eventDelete(GtkWidget *widget,
GdkEvent ♦event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
void inputsetup();
void inputcallback(gpointer data,gint fd,
GdklnputCondition in);
12
GtkWidget *button;
14
int main(int argc,char *argv[])
{
GtkWidget *window;
18
gnome_init("inputadd","1.O",argc,argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size(GTK_WINDOW(window),
200,200);
gtk_container_set_border_width(GTK_CONTAINER(window),
40);
gtk_signal_connect(GTK_OBJECT(window),"delete_event",
GTK_SIGNAL_FUNC(eventDelete),NULL);
gtk_signal_connect(GTK_OBJECT(window),"destroy",
GTK_SIGNAL_FUNC(eventDestroy),NULL);
button = gtk_button_new_with_label("Button");
gtk_container_add(GTK_CONTAINER(window),button);
gtk_widget_show_all(window);
-
inputsetup();
34
gtk_main();
36
exit(0);
}
void inputsetup()
{
int fd;
42
fd = 0;
fcntl(fd,F_SETFL,O_NONBLOCK);
gdk_input_add(fd,GDKINPUTREAD,
(GdklnputFunction)inputcallback,NULL);
}
void inputcallback(gpointer data,gint fd,
GdklnputCondition in)
{
int i;
gint count;
gchar string[20];
54
55while((count=read(fd,string,20)) > 0) {
for(i=0; i<count; i++)
putchar(string[i]);
}
}
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data) {
return(FALSE);
}
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data) {
gtk_main_quit();
return(0);
}
Функция inputSetup(), начинающаяся в строке 39, с помощью вызова функции gdk_iприt__add ( ) инициализирует ввод данных. Первый аргумент функции gdk_input_add () — внутренний номер дескриптора файла (0 — это дескриптор файла stdin f стандартного входного файла Linux, или файла устройства для чтения данных с клавиатуры).
Второй аргумент функции gdk_input_add() — объект GdklnputCondition. Он принимает значение GDK_INPUT_READ, которое указывает на то, что обратный вызов происходит при появлении входных данных. Объект GdklnputCondition может принимать значение GDK_INPUT_WRITE, которое устанавливается, если необходимо, чтобы программа вызывала функцию обратного вызова при наличии данных, которые следует вывести в файл. Это может иметь смысл при заполнении до отказа буфера сокета, когда он не может принять новые данные, пока не будет освобожден (путем записи содержимого на диск) буфер. При установке значения GDK_INPUT__EXCEPTION функция обратного вызова вызывается только в случае, если с файлом случится нечто исключительное.
Обращение к функции fcntl() в строке 44 устанавливает дескриптор файла в режим запрещения блокировки, в котором просто выполняется возврат функции read (), если нет доступных данных. Если функция обратного вызова считывает данные из файла в режиме, разрешающем блокировку, то она зацикливается и программа зависает.
Функция inputcallback() в строке 48 вызывается всякий раз, когда становятся доступными данные указанного по дескриптору файла. Первый аргумент функции — указатель на данные, который передавался при вызове функции gdk_input_add(). Второй аргумент — дескриптор файла. Третий аргумент — значение GdklnputCondition. Цикл, начинающийся со строки 55, считывает до 20 символов за один раз до тех пор, пока все прочитанные символы не будут отображены на стандартном устройстве вывода. Все, что набирается на клавиатуре, отображается на стандартном устройстве вывода.
ПРИМЕЧАНИЕ
Вам, может быть, не удастся сделать то же самое с обычными файлами. Если вы хотите, чтобы одна программа записывала информацию в файл и одновременно с этим другая программа считывала из него данные, то, наверное, лучше будет использовать таймер, а не описанный выше метод. Хотя данный метод будет работать и в этом случае, но может привести к тому, что ваша функция обратного вызова будет вызываться несколько раз в секунду. Программа, которая определяет статус дескриптора входного файла, несомненно "придет в замешательство" и будет полагать, что данные всегда доступны. Как бы то ни было, данный метод предназначен в основном для сокетов, и в таком случае работает безотказно как при чтении, так и при записи.
Выводы
Основой приложения, написанного в среде GNOME, является его очередь событий. Программа не должна сосредоточиваться (зацикливаться) на обработке очереди событий и игнорировать все остальное, кое-что она может выполнять в фоновом режиме. Не так уж важно, какой метод избрать, главное, чтобы во время обработки принималась во внимание очередь событий. В этой главе рассмотрено следующее:
^ Данные, приходящие из очереди событий, полностью игнорируются, если только приложение не вызывает функцию, устанавливающую обратный вызов, который должен использоваться для обработки данных в очереди. Функция обратного вызова должна иметь соответствующий набор аргументов.
^ Сервисная программа signames выводит список доступных сигналов и аргументов, которые будут переданы функциям обратного вызова. Достоинством этой программы является то, что она выводит список сигналов только для существующих объектов. Ее можно использовать как отдельную программу и как часть приложения.
# Существует возможность проводить обработку данных в периоды простоя. То есть, вы можете задать функцию, которая будет вызываться всякий раз, когда в главном цикле обнаруживается, что очередь событий пуста. .'
# Можно также организовать обработку данных в периоды ожидания событий, установив таймер, который через определенные промежутки времени будет вызывать функцию обработки данных.
g Существует возможность ожидать входные данные из входящего сокета или из файла, одновременно ожидая появления событий в очереди событий. Этот же механизм можно использовать для вывода, и таким образом информация будет записываться в медленном сокете, не задерживая вашего приложения.
Программное обеспечение GNkME/GTK+ — это графический интерфейс пользователя, так что обязательно должен существовать некий способ сортировки и отображения графики. В следующей главе описаны два основных формата хранения графики и приведено несколько примеров, которые различными способами выводят изображения.
6 Зак. 403
162162
162
162
ГЛАВАГЛАВАМонохромные и цветные растровые изображения, курсоры
ГЛАВА
ГЛАВА
В этой главе
ф Сведения о цветных и черно-белых растровых изображениях
® Использование файлов в формате ХРМ для вставки графики непосредственно в программу
6 Использование данных в формате ХВМ для создания черно-белой графики и масок
* Использование файлов в формате ХРМ для хранения графики на диске с последующей загрузкой изображения в программу
ф Создание курсоров из файлов в форматах ХВМ и ХРМ
Эта глава — введение в простые графические объекты и курсоры. Маленькие изображения могут использоваться как пиктограммы, метки для кнопок панели инструментов, кнопки меню, декоративные логотипы для объектов GNkME типа About. Большинство графических объектов отображается в нескольких цветах, но курсоры могут быть отображены только в двух цветах. Нужно многое знать, если вы собираетесь включать графику в вашу программу, и существует ряд способов сделать это. Графика может быть сохранена в файлах, чтобы ваша программа загружала ее динамически, когда требуется отобразить картинку. Вы также можете оттранслировать графическую информацию как часть вашей программы. В результате полученная программа может выполняться без других дополнительных файлов. Вы даже можете отображать значения пикселов, сгенерированные в вашей программе.
Два вида графики
Существует два основных вида графики — монохромные и цветные растровые изображения:
Цветное растровое изображение (pixmap) — прямоугольный массив (матрица) значений пикселов. Каждое значение в массиве представляет цвет для одного пиксела. Цветной растровый рисунок может содержать столько цветов, сколько вы можете в любой момент загрузить в вашу палитру.
Монохромное растровое изображение (bitmap) — прямоугольный массив бит, в котором каждый бит соответствует одному пикселу. В монохромном растровом
изображении может быть только два цвета: каждый пиксел или "включен", или "выключен". Обычно это отображается как черный и белый цвета, но GTK+ дает возможность отобразить монохромный растровый рисунок, используя любые два цвета. Монохромное растровое изображение — в действительности только специальный случай цветного растрового изображения, но используется достаточно часто, поэтому имеет собственный формат файла.
Существует множество графических форматов файлов. К счастью, почти любой графический формат может использоваться приложением GNOME благодаря "универсальной" конвертирующей утилите. Утилита convert, описанная далее в этой главе более подробно, может преобразовывать графический файл из некоторого внешнего формата в отображаемый формат. Например, следующий пример показывает, как конвертировать файл формата JPEG в цветной растровый формат (pixmap), который может быть вставлен непосредственно в вашу программу.
convert rickrack.jpeg rickrack.xpm
Если вы хотите включить монохромный растровый рисунок (не цветной) в вашу программу, можно выполнить преобразование следующим образом:
convert rickrack.jpeg rickrack.xbm
Утилита convert анализирует содержимое входного файла, чтобы определить тип этого файла (она не доверяет расширению файла при вводе), и смотрит на расширение (суффикс) имени выходного файла, чтобы определить, какой графический файл нужно получить. ■
Формат ХРМ
Графический формат ХРМ (XPixMap) — стандарт системы X для сохранения графики как текста ASCII. Этот формат дает возможность использовать текстовый редактор для создания или изменения простых цветных графических изображений. ХРМ не просто представляет собой текст ASCII, его формат — это исходный код на языке С, который вы можете непосредственно вставить в вашу программу.
Справа приведен пример графики в формате ХРМ с четырьмя цветами.
Синтаксически этот файл в формате ХРМ определяется как массив символьных строк. Комментарий в первой строке обязателен, так как он используется утилитами для определения типа файла.
/* ХРМ *//** essPixmap.xpm **/static char *essPixmap[J = { 4 "12 14 4 1", 5 " c None", 6 "X C IFFFFFF", 7 "R c Red", 8 "В c I0000FF", 9 " RRBB ","XXXXXXXXXXXX","XXXXXXXXXXXX","XXRRBB","XXRRBB","XXRRBB","XXXXXXXXXXXX","XXXXXXXXXXXX","RRBBXX","RRBBXX","RRBBXX","XXXXXXXXXXXX","XXXXXXXXXXXX"," RRBB ", 23 };/* ХРМ *//** essPixmap.xpm **/static char *essPixmap[J = { 4 "12 14 4 1", 5 " c None", 6 "X C IFFFFFF", 7 "R c Red", 8 "В c I0000FF", 9 " RRBB ","XXXXXXXXXXXX","XXXXXXXXXXXX","XXRRBB","XXRRBB","XXRRBB","XXXXXXXXXXXX","XXXXXXXXXXXX","RRBBXX","RRBBXX","RRBBXX","XXXXXXXXXXXX","XXXXXXXXXXXX"," RRBB ", 23 };4-я строка содержит четыре числа, которые используются для описания следующих данных. Первое число — 12 пикселов — определяет ширину цветного растрового изображения, второе число — 14 пикселов — определяет его
/* ХРМ */
/** essPixmap.xpm **/
static char *essPixmap[J = { 4 "12 14 4 1", 5 " c None", 6 "X C IFFFFFF", 7 "R c Red", 8 "В c I0000FF", 9 " RRBB ",
"XXXXXXXXXXXX",
"XXXXXXXXXXXX",
"XXRRBB",
"XXRRBB",
"XXRRBB",
"XXXXXXXXXXXX",
"XXXXXXXXXXXX",
"RRBBXX",
"RRBBXX",
"RRBBXX",
"XXXXXXXXXXXX",
"XXXXXXXXXXXX",
" RRBB ", 23 };
/* ХРМ */
/** essPixmap.xpm **/
static char *essPixmap[J = { 4 "12 14 4 1", 5 " c None", 6 "X C IFFFFFF", 7 "R c Red", 8 "В c I0000FF", 9 " RRBB ",
"XXXXXXXXXXXX",
"XXXXXXXXXXXX",
"XXRRBB",
"XXRRBB",
"XXRRBB",
"XXXXXXXXXXXX",
"XXXXXXXXXXXX",
"RRBBXX",
"RRBBXX",
"RRBBXX",
"XXXXXXXXXXXX",
"XXXXXXXXXXXX",
" RRBB ", 23 };
высоту. Следующее число указывает, что при рисовании изображения используются четыре цвета. Последняя цифра задает один символ в качестве тега для каждого из цветов. Более подробно относительно этого читайте дальше.
Строки с 5 по 9 содержат определения цветов. Каждая строка начинается с символа, назначаемого цвету. Использоваться может любой символ ASCII. В строке 5 определяется пробел как цвет по имени None. Это означает, что ни один пиксел не должен быть окрашен, и создает прозрачность, потому что фон не перезаписывается. В строке 6 символу X присваивается значение белого цвета. Шестнадцатеричное значение FFFFFF является RGB-значением (’’красно-зелено-синим”) для белого цвета; в десятичной системе значение равно 255 255 255. В строке 8 использует шестнадцатеричное значение 0000FF, чтобы назначить символ G в качестве зеленого цвета. А в строке 7 используется наименование для назначения цвета символу R: это должно быть одно из RGB-значений, найденных в файле /usr/XllR6/lib/Xll/rgb.txt.
Сам рисунок начинается в строке 9 и продолжается до строки 22. Каждая строка имеет длину 12 символов, так как изображение имеет ширину 12 пикселов и для представления пиксела используется только один символ. Всего имеем 14 таких строк, потому что рисунок имеет высоту 14 пикселов. Каждый пиксел указывается одним из символов, определенных ранее для четырех используемых цветов.
Файл в формате ХРМ может использоваться для хранения огромного с высоким разрешением изображения с большим количеством цветов. Например, в дистрибутиве Linux есть файл с именем logo.gif — изображение пингвина Linux. Вы можете конвертировать файл в формате GIF в файл формата ХРМ следующей командой:
convert logo.gif logo.xpm
Здесь выделено больше, чем включает 24-битная информация о цвете, и это значительно больше цветов, чем может быть представлено отдельными символами. Полный файл в формате ХРМ содержит 560 строк в длину. Вот отрывок из него:
/* ХРМ */ static char *magick[] = { "257 303 251 2", " с GrayO",•
". с #080800000404", "X с #080808080000", "о с Gray3", "О с #101004040404", "+ с #101010100404", "{. с #f0f0b8b80808", "}. с #f8f8b0b00808", "|. с #f8f8b8b80808", , " X с #f0f0b0b01010",
".X с #f0f0b8b81010", "XX с #f8f8b8b81010", "BX с #d8d8d8d8e8e8", "VX с #e0e0e0e0d8d8", "СХ с #f0f0e8e8d8d8", , "ZX с Gray88",
"АХ с Gray91", "SX с #e8e8e8e8fOf0", "DX с #fOf0e8e8ecec", "EX c #fOfOfOf0e8e8",
"GX с Gray94", "НХ с ♦f8f8f8f8f8f8", "JX с None",
Это изображение в формате ХРМ — шириной 257 пикселов и высотой 303 пиксела. Оно содержит 251 цвет и использует 2 символа для представления каждого цвета. Может показаться, что несколько первых символов были определены одиночным символом, но фактически используются два символа, потому что вторым символом служит пробел. Как вы можете видеть, далее в файле используются точка и символы X. Поскольку для определения цвета требуется 2 символа, каждая строка, определяющая ряд значений пикселов, должна быть длиной 514 символов (дважды по 257).
Также обратите внимание, что шестнадцатеричные числа для цветов имеют 12 цифр вместо 6. Это, тем не менее, формат RGB, но каждый цвет — 16-битный (четыре шестнадцатеричных цифры). Для файла в формате ХРМ допустима любая длина — программное обеспечение, читающее файл, подсчитывает цифры, чтобы определить формат. Цвета в файле /usr/XllR6/lib/Xll/rgb.txt и многие цвета, описанные в других местах, определены как три 8-битных значения. Следующая простая программа конвертирует три 8-битных значения в длинные и короткие шестнадцатеричные строки, как того требует формат ХРМ:
/♦ hexcolor ♦/
♦include <stdio.h>
♦include <stdlib.h> char *usage(l = {
"Usage: hexcolor r g b",
* Enter the three RBG color values in the", " range of 0 to 256. The output is both a", " 24-bit and 48-bit hexadecimal number of the", " color that can be used in an XPM file."
int main(int argc,char *argv[])
{ int i; int r,g,b;
if(argc < 4) { for(i=0; i<5; i++) printf("%s\n",usage[i]); exit(l);
}
r = atoi(argv[l]);
g = atoi(argv[2]);
b = atoi(argv[3]);
printf("♦%02X%02X%02X\n",r,g,b);
printf("♦%02X00%02X00%02X00\n",r,g,b);
exit(0);
г
Отображение изображения в формате ХРМ из данных, вставленных в код программы
Поскольку утилита convert может виртуально преобразовывать любой графический файл в файл формата ХРМ и этот формат представляет собой исходный код на языке С, почти любой рисунок может быть вставлен непосредственно в вашу программу. Это главным образом используется для пиктограмм, меток кнопок, маркеров списка и других декоративных элементов. Следующая программа — пример вставки файла формата ХРМ непосредственно в код программы и отображение результата:
/** show_xpm_data.с **/
#include <gnome.h>
3
gint eventDelete(GtkWidget *widget,
GdkEvent ♦event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
■ 8
iinclude "essPixmap.xpm"
10
int main(int argc,char *argv[])
{
GtkWidget*topLevel;
GdkBitmap*mask;
GdkPixmap*pixmap;
GtkWidget*pixmapWidget;
GtkStyle *style;
18
gnome_init("show_xpm_data","1.0",argc,argv);
topLevel = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size(GTK_WINDOW(topLevel),
22200,50);
gtk_widget_show(topLevel);
24
gtk^signalconnect(GTK_OBJECT(topLevel),"delete_event",
* GTK_SIGNAL_FUNC(eventDelete),NULL);
gtk_signal_connect(GTK_OBJECT(topLevel),"destroy",
_GTKSIGNALFUNC(eventDestroy),NULL);
29
style = gtk_widget_get_style(topLevel);
pixmap = gdk_pixmap_create_from_xpm d(topLevel->window,
1 -&mask,&style->bg[GTK_STATE_NORMAL],
(gchar **)essPixmap);
pixmapWidget = gtkpixmapnew(pixmap,mask);
•35gtk_container_add(GTK_CONTAINER(topLevel),
pixmapWidget);
37
gtk_widget_show_all(topLevel);
gtk_main();
exit(0);
}
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data) {
return(FALSE);
}
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data) {
gtk_main_quit();
return(O);
}
Данные в формате XPM вставлены непосредственно в программу с помощью оператора finclude в строке 9.
В строке 30 из окна получен объект GtkStyle. Все, что необходимо от GtkStyle, — это графический контекстный объект (объект GtkGC), который может использоваться для визуализации пикселов. Существует более чем один графический контекст в объекте GtkStyle, для этого примера берется тот, который используется для прорисовки окна в его нормальном состоянии и появляется в строке 32.
ПРИМЕЧАНИЕь
Объект GtkStyle предназначен для содержания всей информации, необходимой для прорисовки окна любого виджета. У многих виджетов есть многочисленные режимы и каждый режим может иметь свой собственный стиль. Например, GtkButton может отслеживать, нажата ли кнопка, отпущена или помечена в градациях серого как недоступная. Объект GtkStyle способен содержать все цвета, графические контексты и даже набор цветных растровых изображений, которые могут визуализировать (выполнять рендеринг) виджет. Обратитесь к главе 11 за примерами на эту тему.
ПРИМЕЧАНИЕ НАУЧНОГО РЕДАКТОРА
Рендеринг (rendering) — это процесс создания реалистических изображений на экране с добавлением цвета, тени и т.п.-
В строке 31 выполняется вызов функции gdk_pixmap_create_f rom_xpin_d(), которая использует данные в формате ХРМ, внедренные в программу, для создания GdkPixmap. Функция создает цветное растровое изображение согласно характеристикам окна, так что topLevel->window внутри виджета topLevel находится по ссылке. Маска — возвращаемое значение, которое содержит один бит для каждого пиксела и
Рисунок 7.1.Отображение данных в формате ХРМ в окне верхнего уровняРисунок 7.1.Отображение данных в формате ХРМ в окне верхнего уровняопределяет, какие пикселы должны быть выведены, а какие — оставлены прозрачными. Последний аргумент в строке 33 — данные в формате ХРМ.
Рисунок 7.1.
Отображение данных в формате ХРМ в окне верхнего уровня
Рисунок 7.1.
Отображение данных в формате ХРМ в окне верхнего уровня
Объект GtkWidget может быть добавлен к контейнеру и таким образом отображаться, в строке 34 для создания виджета выполняется вызов gtk__pixmap__new(). Вызов функции требует цветного растрового изображения и его маски для создания цветного растрового виджета. В строках 35 и 36 к окну верхнего уровня добавляется новый виджет. Окончательный вид показан на рисунке 7. 1.
Отображение из файла изображения в формате ХРМ
Внеся небольшое изменение в предыдущий пример, вы можете загружать изображение в формате ХРМ из файла вместо трансляции его как части программы. Все, что для этого нужно, — другая функция для создания цветного растрового изображения. Удалите оператор include из строки 9. Измените в строке 31 имя функции, убрав окончание
_d, а затем поменяйте в строке 33 последний аргумент на имя файла вместо ссылки на данные. Новое обращение к функции будет выглядеть так:
pixmap = gdk_pixmap_create_from_xpm(topLevel->window,
&mask,&style->bg[GTK_STATE_NORMAL],
"essPixel.xmp");
Вы можете использовать абсолютную или относительную адресацию для имени файла. Изображение на экране будет идентично ранее показанному на рисунке 7.1. Утилита sxpm может использоваться для просмотра графики в файле формата ХРМ. Она также может читать файлы старых форматов ХРМ версий 1 или 2 и преобразовывать их к текущему формату версии 3.
Если программа сообщает о недопустимом файле формата ХРМ, дело может быть в старом формате. Для использования утилиты ваш файл должен быть формата версии 3. Сделайте преобразование следующей командой:
sxpm -nod infile -о outfile
Использование формата ХРМ для оформления кнопки
Кнопка содержит окно точно так же, как и любой другой объект, поэтому она может отображать рисунок так же, как и текст. Следующая программа использует файл формата ХРМ для оформления внешнего вида кнопки:
/** show_xpm_button.с **/
Iinclude <gnome.h> 3
gint eventDelete(GtkWidget *widgetf
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widgetr
GdkEvent *event,gpointer data);
8
int main(int argc,char *argv[])
{.
GtkWidget*topLevel;
GdkBitmap*mask;
GdkPixmap*pixmap;
GtkStyle *style;
GtkWidget*button;
GtkWidget*pixmapWidget;
17
gnome_init("show_xpm_button","1.0",argc,argv);
topLevel = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_container_set_border_width(GTK_CONTAINER(topLevel),
10);
J 2gtk_widget_show(topLevel);
23
gtk_signal_connect(GTK_OBJECT(topLevel),"deleteevent",
GTK_SIGNAL_FUNC(eventDelete),NULL);
gtk_signal_connect(GTK_OBJECT(topLevel),"destroy",
GTK_SIGNAL_FUNC(eventDestroy),NULL);
' 28
style = gtk_widget_get_style(topLevel);
pixmap = gdk pixmap_create_from_xpm(topLevel->window,
&mask,&style->bg[GTK_STATE_NORMAL],,
"island.xpm");.
pixmapWidget = gtk_pixmap_new(pixmap,mask);
34
button = gtk_button_new();
gtk_container_add(GTK_CONTAINER(button),pixmapWidget);
gtk_container_add(GTK_CONTAINER(topLevel),button);
38
gtk_widget_show_all(topLevel);
gtk_main();
exit(0);
}
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data) {
return(FALSE);
}
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data) {
gtk_main_quit();
return(O);
}
Рисунок 7.2.Кнопка с изображением вместо текстаРисунок 7.2.Кнопка с изображением вместо текстаИспользуя тот же метод, как и ранее, в строках с 29 по 33 создается цветное растровое изображение виджета из файла формата ХРМ по имени island«хрт. Пустая кнопка создана в строке 35. Цветное растровое изображение виджета вставлено в кнопку в строке 36, а кнопка включена в окно верхнего уровня в строке 37. Для отображения окна сделан вызов gtk_widget_show_all() в строке 39, результат показан на рисунке 7.2. Вы можете видеть, что вокруг изображения имеется граница (рамка) — это кромка кнопки, меняющая свой вид всякий раз, когда кнопка выбирается с помощью мыши.
Рисунок 7.2.
Кнопка с изображением вместо текста
Рисунок 7.2.
Кнопка с изображением вместо текста
Формат ХВМ
Если нужно только два цвета (обычно черный и белый), то более эффективно хранить изображение с одним пикселом на каждый бита, как это сделано в формате ХВМ (ХВИМар). Формат ХВМ наиболее часто используется для описания курсоров мыши и клавиатуры в X, но может применяться также и для других целей. Подобно формату ХРМ, файл в формате ХВМ — это файл ASCII, который может быть вставлен непосредственно в программу на языке С. Далее следует пример файла в формате ХВМ:
♦define arrow_width 16
♦define arrow_height 16
♦define arrow_x_hot 15
♦define arrow_y_hot 7
static unsigned char arrow_bits[] = {
0x00,0x00,0x00,0x00,OxcO,0x07,0x80,OxOf,0x80,
Oxlf,Oxfc,0x3f,Oxfc,0x7f,Oxfc,Oxff,Oxfc,0x7f,
Oxfc,0x3f,0x80,Oxlf,0x80,OxOf,OxcO,0x07,0x00,
0x00,0x00,0x00,0x00,0x00};
В первых двух строках определяется ширина и высота изображения в пикселах. В следующих двух строках определяются координаты горячей точки (hot spot) — острия указателя. Острие со своими координатами хи у определяет точное расположение пиксела внутри монохромного растрового изображения, которое рассматривается как положение мыши всякий раз, когда рисунок используется в качестве курсора мыши. Описание ост-
рия необязательно, так что эти две строки могут быть опущены. Рисунок 7. 3 показывает вид этого монохромного растрового изображения. Горячая точка, или острие, располагается на кончике стрелки, идущей слева направо.
Для случая графического файла установки бит записаны как значения байт и каждое число задает состояние ’’включено” или "выключено” для восьми пикселов. Причем пикселы отображаются слева направо и затем сверху вниз. Каждый пиксел входит в состав одного массива, так что программа, которая использует его, должна иметь информацию о ширине и высоте изображения.
Рисунок 7.3» Монохромное растровое изображение определяет графику в чернобелых тонахРисунок 7.3» Монохромное растровое изображение определяет графику в чернобелых тонахУтилита для работы с монохромными растровыми изображениями
Рисунок 7.3» Монохромное растровое изображение определяет графику в чернобелых тонах
Рисунок 7.3» Монохромное растровое изображение определяет графику в чернобелых тонах
Существует утилита, которую вы можете использовать для создания файлов монохромной растровой графики и изменения их уже после создания. Чтобы создать новое черно-белое растровое изображение с заданным по умолчанию размером 16x16, вводится только имя команды без аргументов. Если вы хотите создать монохромный растровый рисунок шириной 24 и высотой 32 пиксела, введите следующую команду:
bitmap -size 24x32
Как только монохромный растровый рисунок создан и записан на диск, он может быть снова загружен для редактирования следующей командой:
bitmap arrow.xbm
Окно редактирования стрелки показано на рисунке 7.4. Как видно по массиву управляющих кнопок, вы можете редактировать рисунок множеством способов. Вид фигуры показан в сетке справа, вы можете использовать левую кнопку мыши для установки значения пиксела в 0 и правую — в 1. Ромбообразный пиксел справа указывает острие (hot spot, горячую точку) — может быть только одно острие. Чтобы установить его, выберите кнопку "Set hot spot”, а затем выберите пиксел.
ПРИМЕЧАНИЕ
Рисунок 7.4.Растровый редактор bitmap с загруженным файлом arrow.xbmРисунок 7.4.Растровый редактор bitmap с загруженным файлом arrow.xbmПрограмма bitmap — часть стандартного дистрибутива X. У нее есть кнопки, а ее меню представлено в виде меток, или надписей, на этих кнопках, которые очень отличаются от соответствующих в GNkME. Причина в том, что эта программа была разработана с использованием совершенно иного набора виджетов и утилит. Однако даже в этом случае, если продукты, созданные с помощью различного програм-
Рисунок 7.4.
Растровый редактор bitmap с загруженным файлом arrow.xbm
Рисунок 7.4.
Растровый редактор bitmap с загруженным файлом arrow.xbm
много обеспечения, следуют основным стандартам и протоколам X, они могут выполняться одновременно на одном и том же компьютере.
Отображение курсора в формате ХВМ
Существует ряд стандартных курсоров, поддерживаемых X. Всякий раз, когда указатель мыши входит в пределы окна, курсор автоматически изменяет свое изображение на заданное для этого окна. Если вы создаете окно и не определяете курсор, принимается курсор родительского окна. Это означает, что можно устанавливать курсор для окна верхнего уровня и изменение курсора вступит в силу для всех остальных окон и виджетов, которые вы включаете в главное окно.
Делать это просто с любым окном. Следующий фрагмент кода показывает, как установить курсор для окна верхнего уровня:
GdkCursor *cursor
gtk_widget_show(topLevel);
cursor = gdk_cursor_new(GDK_FLEUR);
gdk_window_set_cursor(topLevel->window,cursor);
Выбран курсор по имени GDK__FLEUR и установлен для окна верхнего уровня. Для этого необходимо сначала вызвать функцию gtk__widget_show(), потому что окно должно быть реализовано прежде, чем оно может принимать определение курсора.
Кроме того, применение предопределенного курсора может помочь стандартизировать впечатление и ощущение от использования вашего приложения. Существует много предопределенных курсоров, и если вы не делаете чего-нибудь необычного, то всегда сможете найти то, что ищете. В качестве помощника для просмотра различных курсоров можно использовать следующую программу, которая переключается с одного курсора на другой:-
/** cursail.с **/
' 2 #include <gnome.h>
.
void setCursor();
GtkWidget *makeBox();
gint eventDelete(GtkWidget *widget,1
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
•
GtkWidget *topLevel;,
GtkWidget *nameLabel;
GdkCursor *cur = NULL;
14
gint cursorindex = 0;
struct cursorStruct {
gchar *name;
18GdkCursorType type;
19 } cursor[] = {
20{ "GDKXCURSOR", GDKXCURSOR},
21{ "GDKARROW", GDKARROW },
22{ "GDK_BASED_ARROW_DOWN", GDKBASEDARROWDOWN },
23{"GDK_BASED_ARROW_UP", GDK_BASED_ARROW_UP },
24{"GDK_BOAT", GDK_BOAT },
25{"GDKBOGOSITY", GDK_BOGOSITY },
26{"GDK_BOTTOM_LEFT_CORNER", GDK_BOTTOM_LEFT_CORNER },
27{"GDK_BOTTOM_RIGHT_CORNER",GDK_BOTTOM_RIGHT_CORNER },
28{"GDK_BOTTOM_SIDE", GDK_BOTTOM_SIDE },
29{"GDK_BOTTOM_TEE", GDK_BOTTOM_TEE},
30{"GDK_BOX_SPIRAL", GDK_BOX_SPIRAL},
31{"GDK_CENTER_PTR", GDK_CENTER_PTR},
32{"GDK_CIRCLE", GDK_CIRCLE },
33{"GDK_CLOCK", GDK_CLOCK },
34{"GDK_COFFEE_MUG", GDK_COFFEE_MUG},
35{"GDKCROSS", GDK_CROSS },
36{"GDK_CROSS_REVERSE", GDK_CROSS_REVERSE},
37{"GDKCROSSHAIR", GDK_CROSSHAIR },
38{"GDK_DIAMOND_CROSS", GDK_DIAMOND_CROSS},
39{"GDK_DOT", GDK_DOT },
40{"GDK_DOTBOX", GDK_DOTBOX },
41{"GDKJ)OUBLE_ARROW", GDK_DOUBLE_ARROW },
42{"GDK_DRAFT_LARGE", GDK_DRAFT_LARGE },
43{"GDK_DRAFT_SMALL", GDK_DRAFT_SMALL },
44{"GDK_DRAPED_BOX", GDK_DRAPED_BOX },
45{ "GDK_EXCHANGE", GDK__EXCHANGE },
46{ "GDK_FLEUR", GDK_FLEUR },
47
{
"GDKGOBBLER", GDK_GOBBLER },
48
{
"GDKGUMBY", GDK_GUMBY },
49
{
"GDK_HAND1", GDK_HAND1 },
50
<
"GDK_HAND2", GDK_HAND2 },
51
<
"GDK_HEART", GDK_HEART },
52
<
"GDK_ICON", GDK_ICON },
53
{
"GDKIRONCROSS", GDKIRONCROSS },
54
{
"GDK_LEFT_PTR", GDK_LEFT_PTR },
55
<
"GDK_LEFT_SIDE", GDK_LEFT_SIDE },
56
{
"GDK_LEFT_TEE", GDK_LEFT_TEE },
57
<
"GDK_LEFTBUTTON", GDK_LEFTBUTTON },
58
<
"GDK_LL_ANGLE", GDKLLANGLE },
59
{
"GDK_LR_ANGLE", GDK_LR_ANGLE },
60
{
"GDK_MAN", GDK_MAN },
61
{
"GDK_MIDDLEBUTTON", GDK_MIDDLEBUTTON },
62
<
"GDK_MOUSE", GDKMOUSE },
63
<
"GDK_PENCIL", GDK_PENCIL },
64
<
"GDK_PIRATE", GDK^PIRATE },
65
<
"GDK_PLUS", GDKPLUS },
66
<
"GDK_QUESTION_ARROW", GDK_QUESTION_ARROW },
67
"GDK_RIGHT_PTR", GDK_RIGHT_PTR },
68
<
"GDK_RIGHT_SIDE", GDK_RIGHT_SIDE },
69
{
"GDK_RIGHT_TEE", GDK_RIGHT_TEE },
70
<
"GDK_RIGHTBUTTON", GDKRIGHTBUTTON },
71е
<
"GDK_RTL_LOGO", GDK_RTL_LOGO },
72
"GDK_SAILBOAT", GDK_SAILBOAT },
73
<
"GDK_SB_DOWN_ARROW", GDK_SB_DOWN_ARROW },
74
<
"GDK_SB_H_DOUBLE_ARROW", GDK_SB_H_DOUBLE_2^ROW
75
<
"GDK_SB_LEFT_ARROW", GDK_SB_LEFT_ARROW },
76
{
"GDK_SB_RIGHT_ARROW", GDK_SB_RIGHT_ARROW },
77
{
"GDKSBUPARROW, GDK_SB_UP_ARROW },
78
<
"GDK_SB_V_DOUBLE_ARROW", GDK_SB_V_DOUBLE_ARROW
79
<
"GDK_SHUTTLE", GDK_SHUTTLE }?
80
<
"GDK_SIZING", GDK_SIZING },
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
{ "GDK_SPIDER", GDK_SPIDER },
{ "GDK^SPRAYCAN", GDK_SPRAYCAN },
{ "GDK_STAR", GDK_STAR },
{ "GDK_TARGET", GDKJTARGET },
{ "GDK_TCROSS", GDKTCROSS },
{ "GDK_TOP_LEFT_ARROW", GDK_TOP_LEFT_ARROW },
{ "GDK_TOP_LEFT_CORNER", GDK_TOP_LEFT_CORNER },
{ "GDK_TOP_RIGHT_CORNER", GDK_TOP_RIGHT_CORNER },
{ "GDKJTOP_SIDE", GDK_TOP_SIDE },
{ "GDK_TOP_TEE", GDK_TOP_TEE },
{ "GDKTREK", GDK_TREK },
{ "GDK_UL_ANGLE", GDK_UL_ANGLE },
{ "GDK_UMBRELLA", GDK_UMBRELLA },
{ "GDK_UR_ANGLE", GDK_UR_ANGLE },
{ "GDK_WATCH", GDK_WATCH },
{ "GDK_XTERM", GDK_XTERM },
int main(int argc,char *argv[]) {
GtkWidget *box;
gnome_init("cursail","1.0",argc,argv);
topLevel = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_container_set_border_width(GTK_CONTAINER(topLevel), 50);
gtk_window_set_default_size(GTK_WINDOW(topLevel), 400,0);
gtk_signal_connect(GTK_OBJECT(topLevel),"deleteevent", GTK_SIGNAL_FUNC(eventDelete),NULL);
gtk_signal_connect(GTK_OBJECT(topLevel),"destroy", GTK_SIGNAL_FUNC(eventDestroy),NULL);
box = makeBox();
gtk_container_add(GTK_CONTAINER(topLevel),box);
gtk_widgetshowa11(topLevel);
setcursor();
gtk_main();
exit(0);
void next(GtkWidget *widget,gpointer data ) {
int size = sizeof(cursor)/sizeof(struct cursorStruct); if(++cursorIndex < size)
setCursor();
else
cursorIndex—;
}
void previous(GtkWidget *widget,gpointer data ) {
if(—cursorindex >= 0)
setCursor()
else
138138cursorlndex++cursorlndex++
138
138
cursorlndex++
cursorlndex++
139 >
140 void setCursor()
141 {
142if(cur != NULL)
143gdk_cursor_destroy(cur);
144cur = gdk_cursor_new(cursor[cursorIndex]-type);
145gdk_window_set_cursor(topLevel->window,cur);
146gtk_label_set_text(GTK_LABEL(nameLabel),
147cursor[cursorlndex].name);
148 }
149
150 GtkWidget *makeBox()
151 {
152GtkWidget*buttonBox;
153GtkWidget*box;
154GtkWidget*button;
155
156buttonBox= gtk_hbox_new(TRUE,10);
157
158 button = gtk_button_new_with_label("Previous");
159 gtk_box_pack_start(GTKJBOX(buttonBox),button,
160FALSE,FALSE,0);
161gtk_signal_connect(GTK_OBJECT(button),"clicked",
162GTK_SIGNAL_FUNC(previous),NULL);
163
164button = gtk_button_new_with_label("Next");
165gtk_box_pack_start(GTKJBOX(buttonBox),button,
166FALSE,FALSE,0);
167gtk_signal_connect(GTK_OBJECT(button),"clicked",
168GTK_SIGNAL_FUNC(next),NULL);
169
170 box = gtk_vbox_new(FALSE,0);
171
172 nameLabel * gtk_label_new("");
173gtkboxpackstart(GTKJBOX(box),nameLabel,
174FALSE,FALSE,0);
175gtk_box_pack_start(GTKJBOX(box),buttonBox,
176FALSE,FALSE,0);
177
178 return(box);
179 }
180
181 gint eventDelete(GtkWidget *widget,
182GdkEvent *event,gpointer data) {
183 return(FALSE);
184 }
185 gint eventDestroy(GtkWidget *widget,
186GdkEvent *event,gpointer data) {
. 187gtk_main_quit();
188return(0);
189 }
Эта программа отображает окно, показанное на рисунке 7.5. В нем отображается имя курсора и непосредственно сам курсор. Окно имеет две кнопки, которые могут использоваться для перемещения вперед и назад по списку, меняя и отображаемое имя, и курсор. Отображаемое имя — это то, которое может использоваться для создания курсора через вызов gdk_cursor_new().
из встроенных курсоровиз встроенных курсоровВ строках с 16 по 97 определяется массив структур, содержащих имена и числовые значения курсоров. В структуре символьная строка name применяется для отображения имени, используемого в вызове gdk_cursor_new(), a type — энумератор, используемый для идентификации курсора в системе.
из встроенных курсоров
из встроенных курсоров
В строках с 117 по 119 создается отображаемое окно, добавляется к окну верхнего уровня, затем вызывается setCursor () для установки курсора текущим в таблице. Заданный по умолчанию индекс равен 0. Помните, что курсор для любого
окна не может быть изменен до тех пор, пока не будет произведено обращение к gtk_widget_show_all().
Функция makeBox(), начинающаяся в строке 150, использует ящики для создания
схемы размещения. Горизонтальный ящик используется для включения двух кнопок, а вертикальный ящик — для метки и горизонтального ящика. Каждой кнопке назначена функция обратного вызова: кнопка ’’Previous” вызывает previous (), а кнопка ’’Next” вызывает next ().
Функция обратного вызова next(), начинающаяся в строке 125, увеличивает значение индекса курсора на единицу, если курсор не последний в массиве. Число членов в
массиве подсчитывается путем деления размера полного массива на размер одного члена. Функция обратного вызова previous () уменьшает индекс на единицу, если индекс больше, чем 0. В обеих функциях, если значение индекса увеличено, вызывается setCursor () для замены текущего курсора.
Функция setCursor (), начинающаяся в строке 140, заменяет текущий курсор другим курсором из массива, адресуемым индексом. Если курсор уже создан, он уничтожается прежде, чем будет создан новый. Если в вашей программе применяется несколько курсоров, вы можете создать их один раз и затем многократно использовать при необходимости. Для создания объекта GdkCursor вызывается gdk_cursor_new(). Использование этого нового курсора в обращении к gdk_window_set_cursor() делает новый курсор доступным окну верхнего уровня и его потомкам. Курсор также изменяется для кнопок и метки (надписи). Наконец, текст надписи модифицируется с помощью обращения к gtk_label_set_text (), так как отображается имя курсора.
ПРИМЕЧАНИЕ
Все встроенные курсоры определены в списке именованных переменных в файле gtk/gdk/gdkcursors.h, который включается файлом gtk/gdk/gfktypes.h, где он используется как тело энумератора. Список курсоров достаточно стабилен: большая их часть существует в X в течение нескольких лет. Однако возможно, что будут созданы некоторые новые элементы и, если это случится, вы должны будете обновить список имен и значений, включенных в эту программу.
Создание курсора
Создать ваш собственный курсор просто. Утилита bitmap может использоваться для создания курсора и маски, которая будет необходима вместе с ним. Затем эти два монохромных растровых рисунка могут быть преобразованы непосредственно в текущий курсор.
Курсор обычно черно-белый. У него или черное тело с белой отделкой, окружающей его, или белое тело с черной отделкой. Таким образом, курсор может быть помещен поверх любого цвета, включая черный или белый, и все еще будет видимым. Такие курсоры обычно маленькие, чтобы быть менее навязчивыми. Но не существует ничего, ограничивающего ваш выбор черно-белыми курсорами, и можно выбрать любые два любимых вами цвета. Следующий пример создает большой, имеющий форму перекрестия курсор, красного цвета с черной отделкой.
Пиксел может быть представлен в курсоре тремя способами. Он может быть выведен в одном из двух цветов или оставлен прозрачным (не прорисованный пиксел позволяет видеть через него фон). Опция прозрачности лежит в основе маскировки монохромных растровых изображений.
Эти два монохромных растровых изображения одинакового размера. Если бит маски, относящийся к пикселу, установлен в 0, то пиксел не прорисовывается, то есть прозрачен. Если бит маски — 1, пиксел выводится в одном из двух цветов в зависимости от значения бита в другом монохромном растровом изображении.
Утилита bitmap, описанная ранее, может использоваться для создания курсора. И эскиз курсора и его маска — монохромные растровые изображения. Для этого примера эскиз курсора показан на рисунке 7.6, а его маска — на рисунке 7.7. Эскиз курсора очень похож на заданный по умолчанию курсор главного окна с горячей точкой в его центре.
Рисунок 7.6.Черные и белые пикселы курсораРисунок 7.6.Черные и белые пикселы курсораРисунок 7.7.Маска, определяющая контур курсораРисунок 7.7.Маска, определяющая контур курсора
Рисунок 7.6.
Черные и белые пикселы курсора
Рисунок 7.6.
Черные и белые пикселы курсора
Рисунок 7.7.
Маска, определяющая контур курсора
Рисунок 7.7.
Маска, определяющая контур курсора
• Два монохромных растровых изображения, созданные утилитой, выглядят следующим образом:
/* xbitmap.xbm */
♦define xbitmap_width 24
♦define xbitmapheight 24
♦define xbitmapxhot 12
♦define xbitmapyhot 11
static unsigned char xbitmapbits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00,
0x3c,
0x7c,
0x00,
0x3e,
Oxfc,
0x00,
0x3f,
Oxfc,
0x81,
0x3f,
0xf8,
0xc3,
Oxlf,
OxfO,
Oxff,
OxOf,
OxeO,
Oxff,
0x07,
OxcO,
Oxff,
0x03,
0x80,
Oxff,
0x01,
0x80,
Oxff,
0x01,
0x80,
Oxff,
0x01,
0x80,
Oxff,
0x01,
OxcO,
Oxff,
0x03,
OxeO,
Oxff,
0x07,
OxfO,
Oxff,
OxOf,
0xf8,
0xc3,
Oxlf,
Oxfc,
0x81,
0x3f,
Oxfc,
0x00,
0x3f,
0x7c,
0x00,
0x3e,
0x3c,
0x00,
0x3c,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00};
/* xmask.xbm ♦/
♦define xmask_width 24
♦define xmask_height 24
static unsigned char xmask_bits[] = {
0x00,
0x00,
0x00,
0x3e,
0x00,
0x7c,
0x7e,
0x00,
0x7e,
Oxfe,
0x00,
0x7f,
Oxfe,
0x81,
0x7f,
Oxfe,
0xc3,
0x7f,
Oxfc,
0xe7,
0x3f,
0xf8,
Oxff,
Oxlf,
OxfO,
Oxff,
OxOf,
OxeO,
Oxff,
0x07,
OxcO,
Oxff,
0x03,
0x80,
Oxff,
0x01,
0x80,
Oxff,
0x01,
OxcO,
Oxff,
0x03,
OxeO,
Oxff,
0x07,
OxfO,
Oxff,
OxOf,
0xf8,
Oxff,
Oxlf,
Oxfc,
0xe7,
0x3f,
Oxfe,
0xc3,
0x7f,
Oxfe,
0x81,
0x7f,
Oxfe,
0x00,
0x7f,
0x7e,
0x00,
0x7e,
0x3e,
0x00,
0x7c,
0x00,
0x00,
0x00}
В следующем примере программы используются эти монохромные растровые изображения для создания курсора и назначения его в качестве курсора мыши, появляющегося в любое время в окне верхнего уровня приложения:
/** xbmcursor.c **/
♦include <gnome.h>
3
gint eventDelete(GtkWidget *widget,
GdkEvent ♦event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
8
♦include "xbitmap.xbm"
♦include "xmask*xbm"
11
static GdkColor oneColor * {0,OxFFFF,0x0000,0x0000};
static GdkColor zeroColor = {0,0x0000,0x0000,0x0000};
14
int main(int argc,char *argv[])-
{
GtkWidget*topLevel;
GdkCursor*cursor;
GdkBitmap*bitmap;
GdkBitmap*mask;
21
22gnome_init("xbmcursor","1.0",argc,argv);
topLevel = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size(GTK_WINDOW(topLevel),
25150,150);
26
gtk_signal_connect(GTK_OBJECT(topLevel), "delete_event",
GTK_SIGNAL_FUNC(eventDelete),NULL);
gtk_signal_connect(GTK_OBJECT(topLevel),"destroy",
GTK_SIGNAL_FUNC(eventDestroy),NULL);
31
gtk_widget_show_all(topLevel);
зз
bitmap= gdk_bitmap_create_from_data(NULL,xbitmap_bits,
xbitmap_width,xbitmap_height);
mask =gdk_bitmap_create_from_data(NULL,xmask_bits,
xmask_width,xmask_height);
cursor= gdk_cursor_new_from_pixmap(
bitmap,mask,
&oneColor,&zeroColor,
xbitmap_x_hot,xbitmap_y_hot);
gdk_window_set_cursor(topLevel->window,cursor);
43
gtk_main();
exit(0);'
}
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data) {
return(FALSE);
}
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data) {
gtk_main_quit();
return(O);
}
Для использования в программе эти два монохромных растровых изображения должны быть преобразованы в объекты GdkBitmap. Это осуществляется вызовом gdk_bitmap_create_from_data() в строках с 34 по 37. Первым аргументом этой функции может быть объект GdkWindow, но он необязателен в нашем случае, потому что в качестве значения по умолчанию принято корневое окно. Другие три аргумента — значения, которые определяют размещение монохромного растрового изображения.
Объект GdkCursor создан путем обращения к gdk_cursor_new_from_pixmap() в строке 38. Первые два аргумента — объекты GdkBitmap, созданные из монохромных растровых изображений, размещенных резидентно в ОЗУ (в оперативном запоминающем устройстве, или в оперативной памяти). Третий и четвертый аргументы — это два цвета, которые нужно использовать в изображении курсора. Цвета в примере, определенные в строках 12 и 13, — красный и черный. При этом oneColor описан как красный, а zeroColor — черный. Когда маска установлена в 1, а монохромный растровый рисунок — в 0, пиксел будет черный. Если маска и рисунок установлены в 1, цвет — красный. Два последних аргумента — координаты х и у горячей точки (острия).
Вызов gdk__window_s е incurs or () в строке 42 делает вновь созданный курсор отображаемым всякий раз, когда указатель мыши находится в пределах окна.
Создание курсора из данных формата ХРМ
Курсор также может быть создан из данных в формате ХРМ, но вы не должны учитывать информацию о цвете. В следующем примере это делается выбором одного из символов ХРМ для представления черного цвета и другого — для белого цвета. Курсоры обычно черно-белые, но, как показано в этом примере, вы можете выбирать любые два цвета, которые любите. Все пикселы, которые ни черные, ни белые, остаются прозрачными.
Содержимое файла sancha.xpm выглядит следующим образом:
/♦ ХРМ */
/♦* sancha.xpm ♦♦/
static char *sancha[] = { "24 24 5 1", " с none", "В с Black", "W с White", "г с Red", "у с Yellow", "гrWWWWWWWWWWWWWWrг",
"ГrWBBBBBWWBBBBBWrг",
"гrWBBBBBWWBBBBBWrг",
"ГrWBBBBBWWBBBBBWrг",
"гrWBBBBBWWBBBBBWrг",
"гrWBBBBBBWWBBBBBBWrг",
"rrrWBBBBBBWWBBBBBBWrгг",
"rrrrWBBBBBBWWBBBBBBWrrrr", "rrrrrWBBBBBBBBBBBBWrrrrr", "rrrrrrWBBBBBBBBBBWrrrrrr", "rrrrrrrWBBBBBBBBWrrrrrrr", "rrrrrrrrWBBBBBBWrrrrrrrr", "rrrrrrrrrWBBBBWrrrrrrrrr", "yyyyyyyyyyWBBWyyyyyyyyyy", "yyyyyyyyyWBBBBWyyyyyyyyy", "yyyyyyyyWBBBBBBWyyyyyyyy", "yyyyyyyWBBBBBBBBWyyyyyyy", "yyyyyyWBBBBBBBBBBWyyyyyy", "yyyyyWBBBBBBBBBBBBWyyyyy", "yyyyWBBBBBBBBBBBBBBWyyyy", "yyyWBBBBBBBBBBBBBBBBWyyy", "WWWBBBBBBBBBBBBBBBBBBWWW", "WBBBBBBBBBBBBBBBBBBBBBBW", "WBBBBBBBBBBBBBBBBBBBBBBW", "WWWWWWWWWWWWWWWWWWWWWWWW", };
Это определение в формате ХРМ содержит пять цветов. Рисунок состоит из центральной черной области, обрисованной белым; фон с каждой стороны — красный и желтый. Наверху прозрачная область. Изображение показано на рис. 7.8.
Рисунок 7.8. Рисунок в формате ХРМ, преобразованный в курсор
Рисунок 7.9.Курсор, созданный из графических данных в формате ХРМРисунок 7.9.Курсор, созданный из графических данных в формате ХРМВ следующем примере два из цветов ХРМ (В и W) выбраны для представления положения видимого пиксела. Другие цвета (г, у и пробел) — прозрачные. Окно с таким курсором показано на рисунке 7.9.
Рисунок 7.9.
Курсор, созданный из графических данных в формате ХРМ
Рисунок 7.9.
Курсор, созданный из графических данных в формате ХРМ
/** xpmcursor.c *♦/
tinclude <gnome.h>
3
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
GdkCursor *newCursorFromXPM(gchar *xpm[),
gchar blackLetter,GdkColor*blackColor,
gchat whiteLetter,GdkColor*whiteColor,
gint xHot,gint yHot);
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
* 62
63
64
65
66
67
68
69
Iinclude "sancha.xpm"
GdkColor green = {0,0x0000,OxFFFF,0x0000};
GdkColor black = {0,0x0000,0x0000,0x0000};
int main(int argc,char *argv[]) {
GtkWidget *topLevel;
GdkCursor «cursor;
gnome_init("xpmcursor","1.0",argc,argv);
topLevel = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_default_size(GTK_WINDOW(topLevel), 150,150);
gtk_signal connect(GTK_OBJECT(topLevel),"delete_event", GTKSIGNALFUNC(eventDelete),NULL);
gtk_signal_connect(GTK_OBJECT(topLevel),"destroy", GTKJSIGNALFUNC(eventDestroy),NULL);
gtk_widget_show_all(topLevel);
cursor = newCursorFromXPM(sancha, 'B',(black,'W',(green, 12,13);
gdk_window_set_cursor(topLevel->window,cursor);
gtk_main(); exit(0);
}
GdkCursor *newCursorFromXPM(gchar *xpm[], gchar blackLetter,GdkColor «blackColor, gchar whiteLetter,GdkColor «whiteColor, gint xHot,gint yflot) { gint height; gint width; gint colors; gint pchars; gint x; gint y;
GdкBitmap *bitmap;
GdkBitmap «mask;
GdkCursor «cursor;
guchar «bitmapData;
guchar «maskData; gint byteindex = 0; gint bitCount = 0;
sscant(xpm[0],"%d %d %d %d", (height,(width,(colors,(pchars);
g_assert(pchars ~ 1);,
bitmapData = (guchar * )g_maHoc((width ♦ height) /8); maskData = (guchar *)g_maHoc((width * height) / 8);
70717071for(y=(colors+4); у < (height+4); y++) { for(x=0; x<width; x++) {
70
71
70
71
72
if(xpm[y][x] == whiteLetter) {
73
maskData[byteIndex] |= 0x80;
74
bitmapData[byteindex] |= 0x80;
75
} else if(xpm[y)[x] == blackLetter) {
76
maskData[byteindex] | = 0x80;
77
}
78
if(++bitCount == 8) {
79
bytelndex++;
80
bitCount = 0;
81
} else {
82
maskData[byteindex] >* 1;
83
bitmapData[byteindex] >= 1;
84
}
85
}
86
}
87
bitmap = gdk_bitmap_create_from_data(NULL,bitmapData
88
width,height);
89
mask = gdk_bitmap_create_from_data(NULL,maskData,
90
width,height);
91
cursor = gdk_cursor_new_from_pixmap(bitmap,mask.
92
whiteColor,blackColor,
93
xHot,yHot);
94
g_free(bitmapData);
95
g_free(maskData);
96
return(cursor);
97 }
98 gint eventDelete(GtkWidget *widget,
99
GdkEvent ♦event,gpointer data) {
100
return(FALSE);
101 }
102 gint eventDestroy(GtkWidget *widget,
103
GdkEvent *event,gpointer data) {
104
gtk_main_quit();
105
return(0);
106 }
Данные в формате ХРМ включаются в строке 13. Два цвета, которые будут использоваться для курсора, определены в строках 15 и 16. В этом примере черный курсор обрисован зеленым цветом. Объект курсора создан вызовом функции в строке 35. Первый аргумент функции — файл в формате ХРМ. Следующие два аргумента определяют символ и фактический цвет, который должен стать "черным” цветом. И следующие два аргумента определяют символ и фактический цвет, который должен стать ’’зеленым” цветом. Два последних аргумента — координаты х и у острия курсора.
Преобразование данных формата ХРМ в GdkCursor выполнено функцией newCursorFromXPM(), начинающейся со строки 43. Первая символьная строка в массиве ХРМ содержит набор чисел, который считывается в строке 63 и используется далее. В строке 65 проверяется, что каждый цвет представлен простым (несмешанным) цветом, потому что эта функция не может обрабатывать более чем один символ на цвет. Размещение монохромных растровых изображений выполняется в строках 67 и 68. Функция g_malloc() вызывает са!1ос() для фактического выделения памяти, таким образом возвращаемые данные обнуляются.
Цикл, начинающийся со строки 70, использует значение у как индекс для каждой из строк входного массива. Внутренний цикл, начинающийся со строки 71, повторяется для каждого символа в строке. В строке 72, если пиксел должен быть окрашен "белым” цве-
том, устанавливается старший бит и монохромного растрового изображения, и маски. В строке 75, если пиксел должен быть окрашен ’’черным” цветом, устанавливается старший бит маски. В строках с 78 по 84 используется счетчик бит для определения, действительно ли текущий байт уже заполнен. Если байт заполнен, индекс увеличивается до следующего байта, в противном случае биты в пределах байта сдвигаются в целях освобождения места для следующего бита.
Монохромные растровые изображения созданы в строках 87 и 89. Эти изображения используются для создания курсора в строке 91. Строки с 94 по 96 освобождают распределенную память и возвращают GdkCursor вызывающей программе.
ПРИМЕЧАНИЕ
Имя функции, создающей курсор из пары монохромных растровых изображений, такое, как если бы она использовала цветное растровое изображение вместо монохромного. И хотя это два различных формата, одна и та же программа может использоваться для работы с каждым из них и наблюдается только небольшое несовпадение имен объектов.
Выводы
Существует намного больше графических изображений, чем упомянуто здесь, но эта глава предоставила достаточно сведений для начала, так что вы можете создавать кнопки с рисунком для панелей инструментов и изменять вид курсора для вашего приложения. В этой главе изложены следующие сведения:
? Два основных типа графики приложения GNOME — монохромное и цветное растровые изображения. Монохромное растровое изображение не содержит никакой информации о цвете: оно только определяет для каждого пиксела значение 1 или 0. У цветного растрового изображения может быть любое количество цветов.
# И цветное растровое изображение, известное как формат ХРМ, и монохромное рас. тровое изображение, известное как формат ХВМ, могут быть вставлены непосредственно в вашу программу или динамически загружено во время выполнения.
У многих виджетов имеется возможность отображения цветных растровых изображений вместо однородных цветов их фона.
О Вам понадобится два монохромных растровых изображения для определения курсора, так как монохромное изображение имеет два цвета, а здесь нужен еще и третий для представления прозрачных пикселов.
Гй Существует большой набор встроенных курсоров, которые можно использовать для стандартизации вида вашего приложения.
Цветные растровые изображения, представленные в этой главе, будут использоваться для оформления меню и панелей инструментов, представленных в следующей главе. Один из основных принципов графического интерфейса пользователя — наличие графики, которая дает возможность пользователю немедленно опознать цель кнопки, выполнить выбор пункта меню или объекта панели инструментов.*
глава Меню и панели ф инструментов
В этой главе
Использование механизмов GNkME для быстрого создания меню и панелей инструментов
X Использование рекомендуемого стандартного формата меню для стандартизации приложений GNkME
Использование кнопок, переключателей, радиокнопок, подменю и подчиненных панелей инструментов, пиктограмм, текста и всплывающих диалоговых окон
Меню (menu) — иерархическая группировка кнопок, которые могут использоваться для выдачи команд. Почти то же самое представляет собой и панель инструментов (toolbar). Различие между ними в том, что в меню используется текст в качестве меток(надписей) кнопок, а в панели инструментов в качестве меток кнопок применяются графические объекты. К тому же в меню остаются скрытыми некоторые из его частей, в то время как на панели инструментов все остается видимым. Меню и панели инструментов могут быть ориентированы горизонтально или вертикально. Поскольку панели инструментов и меню в основном представляют собой одно и то же, GNkME использует одну и ту же технологию определения в обоих случаях. И хотя между ними существуют некоторые различия, но во многих случаях код определения для создания меню также может использоваться для создания панели инструментов.
Область программирования, описанная в этом издании, традиционно была одной из наименее изящных областей в разработке приложений системы X. Система меню работала очень хорошо с самых ранних дней X, но это никоим образом нельзя отнести на счет интуиции программиста. GNkME упрощает этот процесс, предоставляя программисту возможность определения всей необходимой информации в массивах, которые организованы таким же образом, как и меню, выводимые на экран дисплея.
Способы создания меню
Меню состоит из строки или столбца кнопок. Мы привыкли к виду меню, появляющемуся как горизонтальная строка кнопок вверху окна. Выбор одной из этих кнопок приводит к появлению вертикального столбца кнопок. Каждая кнопка в меню вызывает другой столбец кнопок меню или функцию обратного вызова внутри программы. Эти два основных действия при использовании кнопки для выбора являются базисом для всех one-
раций с меню. Хотя кнопки также могут быть использованы для создания переключателей и группы радиокнопок.
Меню имеет иерархическую форму: одни подменю внутри других подменю внутри главного меню. GNOME обеспечивает структурой по имени GnomeUIInf о, которую вы можете использовать для создания пунктов меню. Член массива структур GnomeUIInf о определяет кнопку или другой пункт меню. Пункты меню связаны в последовательность, которая соответствует порядку их появления в массиве. Если у меню есть подменю, то оно содержит адрес массива, хранящего описание пунктов подменю.
Следующая программа создает окно с меню, как показано на рисунке 8.1. Это обычное иерархическое меню, расположенное сверху окна, которое, как показано на рисунке, допускает отображение подменю, подменю внутри упомянутого подменю и т.д. Меню, созданное в этом примере, — отрывное меню (tear-off menu), как принято по умолчанию. Кнопку в левом конце меню, используя левую кнопку мыши, можно перемещать в любое место на рабочем столе, как это показано на рис. 8.2. Используйте кнопку для свободного перемещения меню в любое место экрана дисплея. Для возвращения меню в окно просто перетащите его назад к верху или к основанию окна, где оно и закрепится. Когда вы закрываете приложение, GNOME отслеживает положение меню для каждого вашего входа в систему, так что следующий раз, когда запускается приложение, меню появляется там, куда вы его поместили.
Рисунок 8.1.Пример простого меню, созданного из таблицРисунок 8.1.Пример простого меню, созданного из таблицД Gnome Арр Menu р@Нх
Рисунок 8.1.
Пример простого меню, созданного из таблиц
Рисунок 8.1.
Пример простого меню, созданного из таблиц
Close the current file
Рисунок 8.2.
Простое меню, оторванное от своего родителя
Строка состояния GnomeApp, отображенная внизу окна, необязательна. Текст, который появляется в строке состояния, описан в массиве структур GnomeUIInfo и отображается всякий раз, когда мышь перемещается через вершину одной из кнопок. Строка состояния может использоваться приложением для постоянного отображения текущего состояния программы: здесь используется архитектура push/pop (толкните и отправьте), так что строка может использоваться одновременно различными элементами вашейпрограммы.
/♦♦ gnomeappmenu.с **/
Iinclude <gnome.h> 3
static void fileOpen(GtkObject *,gpointer);
static void fileclose(GtkObject *,gpointer);
static void fileBxit(GtkObject *,gpointer);
static void editCut(GtkObject *,gpointer);
static void editPaste(GtkObject *,gpointer);
static void editCopy(GtkObject *,gpointer);
static void editDelete(GtkObject *,gpointer);
static void editMoveUp(GtkObject *,gpointer);
static void editMoveDown(GtkObject *,gpointer);
13
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent ♦event,gpointer data);
18
GnomeUIInfo fileMenu[] = {
{GNOME_APP_UI_ITEM,"Open",
"Open an existing file",
fileOpen,NULL,NULL,
GNOME__APP PIXMAP_NONE,
NULL,0,0,NULL },
{GNOME_APPJJI_ITEM,"Close",
"Close the current file",
fileclose,NULL,NULL,
GNOMEAPPPIXMAPNONE,
NULL,0,0,NULL },
GNOMEUIINFO_SEPARATOR,
{GNOME_APP_UI_ITEM,"E_xi t",
"Close the window and cease",
fileExit,NULL,NULL,
GNOME_APP_PIXMAP_NONE,
NULL,0,0,NULL },
36
GNOMEUIINFO^END
};
39
GnomeUIInfo editMoveMenu[] = {
{ GNOMEAPPUIITEM,"Up",
"Move selection up",
editMoveUp,NULL,NULL,
GNOME_APP_PIXMAP_NONE,
NULL,0,0,NULL },
{ GN0ME_APP_UI_ITEM,"D_OWn",
"Move selection down",
editMoveDown,NULL,NULL,
GNOMEAPPPIXMAPNONE,
NULL,0,0,NULL },
GNOMEUIINFO_END
};
53
GnomeUIInfo editMenu[] = {
{ GNOME_APP_UI_ITEM,"_Cut",
"Delete and copy selection to clipboard",
editCut,NULL,NULL,
GNOME_APP_PIXMAP_NONE,
NULL,0,0,NULL },
{ GNOME_APP_UI_ITEM,"Cop_y",
"Copy selection toclipboard",
editCopy,NULL,NULL,
GNOME_APP_PIXMAP_NONE,
NULL,0,0,NULL },
{ GNOME_APP_UI_ITEM,"_Paste",
"Paste selection from clipboard",
editPaste,NULL,NULL,
GNOME_APP_PIXMAP_NONE,
NULL,О,О,NULL },
GNOMEUIINFO_SUBTREE("_Move",editMoveMenu),
{ GNOME_APP_UI_ITEM,"_Delete",
"Delete the current selection",
editDelete,NULL,NULL,
GNOME_APP_PIXMAP_NONE,
NULL,0,0,NULL },
GNOMEUIINFO END
};
78
GnomeUIInfo mainMenu[] = {
GNOMEUIINFO_SUBTREE("_File",fileMenu),
GNOMEUIINFO_SUBTREE( "Edit" ,editMenu),
GNOMEUIINFO END
};
84
int main(int argc,char *argv[])
{
GtkWidget *app;
GtkWidget ♦statusbar;
89
gnome_init("gnomeappmenu","1.0",argc,argv);
app = gnome_app_new("appmenu","Gnome App Menu");
gtk_window_set_default_size(GTK_WINDOW(app),200,200);
gtk_signal_connect(GTKOBJECT(app),"deleteevent",
GTK_SIGNAL_FUNC(eventDelete),NULL);
gtk_signal_connect(GTK_OBJECT(app),"destroy",
GTK__SIGNAL_FUNC( event Des troy),NULL);
97
gnome_app_create_menus(GNOME_APP(app),mainMenu);
99
statusbar = gtk_statusbar_new();
gnome_app_install_statusbar_menu_hints(
GTK_STATUSBAR(statusbar),mainMenu);
gnomeappsetstatusbar(GNOMEAPP(app),statusbar);
104
gtk_widget_show_all(app);
106
gtk_main();
exit(0);
}
static void fileOpen(GtkObject *object,gpointer data) {
gnome__ok__dialog("\"File/Open\" selected.");
}
static void fileClose(GtkObject *object,gpointer data) {
gnome_ok_dialog("\"File/Close\" selected.");
}
static void fileExit(GtkObject *object,gpointer data) {
gtk_main_quit();
}
static void editCut(GtkObject *object,gpointer data) {
gnomeokdialog("\"Edit/Cut\" selected.");
}
static void editCopy(GtkObject *object,gpointer data) {
gnome_ok_dialog("\"Edit/Copy\" selected.");
}
125 static void editPaste(GtkObject *object,gpointer data) {
126gnome_ok_dialog("\"Edit/Paste\" selected.");
127 }
128 static void editDelete(GtkObject *object,gpointer data) {
129 gnome_ok_dialog("\"Edit/Delete\" selected.");
130 }
131 static void editMoveUp(GtkObject *object,gpointer data) {
132gnomeokdialog("\"Edit/Move/Up\" selected.");
133 }
134 static void editMoveDown(GtkObject *object,gpointer data) {
135 gnome_ok_dialog("\"Edit/Move/DownV selected.");
136 }
137 gint eventDelete(GtkWidget *widget,
138GdkEvent *event,gpointer data) {
139return(FALSE);
140 }
141 gint eventDestroy(GtkWidget *widget,
142GdkEvent *event,gpointer data) {
143gtk_main_quit();
144return(O);
145 }
Описание главного меню начинается в строке 79 массивом из трех структур GnomeUIInfo. В начале структуры есть поле типа, которое используется для определения содержания структуры. Данные для каждого члена массива могут быть описаны полем в поле или в макросе, как в этом примере. Таблица 8.1 в следующем разделе описывает все поля структуры. Первый и второй элементы, находящиеся в массиве, относятся к подменю. Для разрешения ссылок подменю должны появиться в исходном коде перед их родительскими меню — у языка С нет упреждения (предварительного просмотра, или просмотра наперед).
Макрос GNOMEUIINFO_SUBTREE, используемый в строках 80 и 81, предоставляет все значения для структуры за исключением имени, отображенного в меню, и адреса подменю, кнопка которого всплывает. Использование макроса следующее:
{ GNOMEAPPUISUBTREE,"JFile", NULL, fileMenu,NULL,NULL, GNOME_APP_PIXMAP_NONE, NULL,0,0,NULL },
Третий элемент массива в строке 82 является макросом GNOMEUIINFOJEND, который необходим как признак конца массива для программы, создающей меню. :
Пункты в столбце меню File описаны в массиве, начинающемся в строке 19. Есть пять членов массива. Первый член массива типа GNOME__APP_UI_ITEM определяет кнопку Open, при выборе которой вызывается функция fileOpen (). Второй член массива — кнопка Close, сконфигурированная для вызова f ileClose(). Третий член — разделитель, показанный на рисунке 8.2. Последние два члена — кнопка Exit, которая вызывает f ileExit(), и необходимый признак конца по имени GNOMEUIINFOJEND.
Меню Edit, определенное в массиве, начинающемся в строке 54, содержит кнопки, которые выполняют функции обратного вызова, и одну кнопку, которая вызывает подменю. Это подменю описано точно таким же образом, что и главное меню. Процесс создания подменю может продолжаться на столько уровней, на сколько вам нужно. На рис. 8.1 показан вид окна с выбранным подменю.
Прототипы функций обратного вызова описаны в строках с 4 по 12, а сами функции определены в строках со 103 по 130. Точно так же, как сигнальные функции обратного вызова, обсужденные в предыдущих главах, эти функции обратного вызова имеют два заданных по умолчанию аргумента. Первый из них — GtkOb ject, вызывающий функцию, и второй — указатель на данные, который определен как часть структуры GnomeUIInf о.
Эти меню требуют окна приложения GNOME. Обращение в строке 90 к функции gnome_app_new() создает окно, которое является расширением верхнего уровня окна GTK. Эти расширения служат как элементы типа системы меню и строки состояния и в качестве некоторых других элементов, которые будут обсуждаться позже. Меню созданы вызовом gnome_app_create_menus () в строке 97. Один такой вызов функции создает целостное дерево меню и присоединяет его к окну приложения.
В названиях пунктов меню имеются определенные для них клавиши-акселераторы, которым предшествует ключевой символ с символом подчеркивания. Затем эти символы могут использоваться с клавишей meta или alt для непосредственного перехода к пункту меню. Например, в строке 41 определяется название кнопки меню как " Up'’, в результате чего Meta-U (или Alt-U, в зависимости от системы) будет ее акселератором. Использование клавиши-акселератора вызывает непосредственный выбор пункта меню так, как если бы вы использовали мышь для его нахождения и выбора.
Акселераторы должны быть уникальны. Всякий раз, когда нажимается акселератор, в дереве меню ищется соответствие; если оно найдено, то выбирается соответствующий пункт меню. Если имеются два или более пунктов меню, использующих один и тот же символ как акселератор, поиск в дереве меню заканчивается на первом найденном пункте и любые другие полностью игнорируются.
Типы меню и макросы
Как можно видеть из предыдущего примера, GNOME обеспечивает метод заполнения полей для создания меню. Та же самая технология и те же структуры могут использоваться для создания панелей инструментов, что подробно изложено в главе 9. Вы должны знать, какие поля должны быть заполнены, какие значения могут использоваться для их заполнения и какую функцию необходимо вызвать для создания и активизации меню или панели инструментов.
Меню состоит из набора массивов GnomeUIInfo. Каждый член каждого массива — самостоятельный компонент — не имеет никаких связей с его соседними членами кроме как совпадение позиции. Сохраненные в полях значения определяют тип компонента и его конфигурацию. В таблице 8.1 перечислены поля и описаны значения, которые могут быть в каждом из них. Видно, что некоторые поля используются для нескольких целей: их содержание может изменяться в зависимости от типа определяемого компонента.
Таблица 8.1. Поля GnomeUIInfo
#
Тип данных
Область применения
Описание
1
GnomeUIInfo! у ре
везде
Определяет тип компонента. Вы можете найти список типов в табл. 8.2.
2
gchar *label
везде
Строка символов, используемая в качестве метки.
Таблица 8.1. (продолжение)
#
Тип данных
Область применения
Описание
3
gchar *hint
меню
Строка символов, используемая в качестве
сообщения строки состояния.
3
панель инструментов
Подсказка, всплывающая при прохождении мыши через кнопку.
4
gpointer moreinfo
пункт переключатель радиокнопка
Указатель на функцию обратного вызова, которая сработает при активизации пункта меню.
4
первая радиокнопка
Указатель на массив структур GnomeUlinfo, используемых в качестве членов группы
радиокомпонентов.
4
поддерево
Указатель на поддерево, которое является
другим массивом структур GnomeUlinfo.
4
пункт справки
Определяет раздел справки для загрузки. Если установлен в HULL, предполагается идентификатор приложения.
A 4:-.. A ».'. АЛ A.-. :-■/■• S'.--..ZA•■УЧ A-.W.4 -V.*.#. ,АЧ # S,
.,.ЛЧЛ ZZZ..-. V V VA*V Ч’/А- ..Ч..-.V№. #. . WW
A- АА АГА-АА ЛОЛЛА . -V..V.»«V,VWr А А V» A-ASS A aSS-AZA-ZAA ZA *A-ZА АЧЧЧА’АЧА. .АЧ А МЧА ASSS-.-Z. S-AS WW#. AVAS Ч Z SSW А ЛА -Z «А S • VA А А 'А ’-AV «А
4
данные для
Адрес структуры GnomeUIBuilcieiKata.
построителя
5
gpointer user_data
везде
Пользовательский указатель для передачи функции обратного вызова в качестве второго аргумента.
w ■-•#.-. --.•.-.- -#»• •. -
ZAv.vV -z.-z.-.- A A A-.-. .-AVA-.-A-A A A- • -. . .-.-.■.-.-.-.4 .V - -W -Z.-.-Z •.-А-.-.-.-.ЧЧ A ••4-
*-•Ч-Ач WZ4•A-.s-A-Z.4-.- •. .•. А-А Л-ААЧ ЧЧ.-Z.-Ss-ASVA
6
gpointer unused_data
-
Зарезервировано.
7
GnomeUIPixmapT у pe pixmap—type
везде
Тип цветного растрового изображения. Это GNkME_APP_PIXMAP_NkNE, GNkME_APP _Р1ХМ AP_STkCK , GNkME_APP_PIXMAP_KATA или GNkME_APP_PIXMAP_FILENAME.
8
gpointer pixmap_Jnfo
везде
Указатель на информацию цветного растрового изображения. Если поле 7 определяет указатель как КАТА, то это адрес внутри программы данных в формате ХРМ. Если определяет FILENAME — это указатель на строку символов, содержащую имя файла. Если STkCK — это указатель на название
семейства пиктограмм.
9
guint accelerator_key
Клавиша-акселератор. Нуль означает отсутствие такой клавиши.
10
GtkModifierT у pe
Маска клавиш-модификаторов для акселера
ac_mods
тора.
11
GtkWidget *widget
везде
Создающая функция хранит здесь виджет, так что ваша программа может получить его, чтобы изменить свой вид и действия.
Каждая структура GnomeUIInfo определяется как имеющая определенный тип. В табл. 8.2 перечисляются возможные значения для поля типа.
Таблица 8.2. Типы элементов GnomeUIInfo
Тип
Описание
GNkME_APP_ULENKkFINFk
Специальный элемент, который используется как
GNkME_APP_UI_ITEM
признак конца каждого массива.
Обычный пункт меню или пункт меню с радиокнопкой, если используется внутри группы радиокнопок.
GNkME_APP_ULTkGGLEITEM GNkME_APPJJI_RAKIkITEMS GNkME_APP_UI_SUBTREE
Отмечаемая кнопка.
Группа радиокнопок.
Поддерево. Включает указатель на другой массив структур GnomeUIInfo.
GNkME_APP_ULSEPARATkR
Для меню это разделительная строка. Для панели
GNkME_APP_UI_HELP
GNkME_APP_UI_BUILKER_KATA
инструментов — пустое пространство, пробел. Список разделов (тем) для меню справки. Создающая меню функция считывает информацию этого члена массива для конфигурирования меню.
GNkME_APPJJIJTEM_CkNFIGURABLE
Конфигурируемый пункт меню. Этот тип полностью игнорирует любые установочное значения, сделанные предварительно элементом GNkME_APP_UI_BUILKER_KATA.
GNkME_APP_ULSUBTREE_STkCK
То же, что и GNkME_APP_UI_SUBTREE, за исключением метки и строк подсказки, которые будут отыскиваться в каталоге gnome-libs.
ПРИМЕЧАНИЕ НАУЧНОГО РЕДАКТОРА
Отмечаемая кнопка — это маленькая прямоугольная область, на которой появляется отметка при выборе ее пользователем. Обычно такие кнопки образуют группу, позволяя выбрать одну из числа предлагаемых.
В таблице 8.3 перечислены макросы, определенные в gnome-app-helper .h, которые могут использоваться для создания меню. В этих макросах нет ничего особенного, они просто расширены в набор значений, отформатированных должным образом для инициализации структуры GnomeUIInfo, но их использование упростит запись вашей программы и облегчить ее чтение. Существуют тысячи возможных макросов с различным числом полей в структуре; если вашему приложению нужно еще что-то, чего здесь нет, вы, конечно, можете создать это самостоятельно.
Таблица 8.3. Макросы, используемые для создания меню и панелей инструментов
Имя макроса
GNkMEUIINFk ENK
GNkMEUIINFk_HELP (app_name)
GNkMEUIINFkJTEM (label, tooltip, callback, xpm_data)
GNkMEUIINFk JTEM_KATA (label, toolti p, callback, user_data, xpm_data)
GNkMEUIINFk JTEM_STkCK (label, tooltip, callback)
GNkMEUIINFk JTEM_STkCK (label, tooltip, callback, stocked)
GNkMEUIINFk_RAKIkITEM (label, tooltip, callback, xpm__data)
GNkMEUIINFk_RAKIkITEM_KATA (label, tooltip, callback, user_data, xpm_data)
GNkMEUIINFk_SEPARATkR
GNkMEUIINFk^SUBTREE (label, tree)
GNkMEUIINFk_SUBTREE_HINT (label, hint, tree)
GNkMEUIINFk_SUBTREE_STkCK (label, tree, stock_id)
Описание
Тип GNkME_APPJJI_ENKkFINFk. Завершает массив структур Gnomellllnfo и должен присутствовать в каждом массиве.
Тип GNkME_APP_UI_HELP. Содержит разделы справки, означенные именем приложения.
Тип GNkME_APP_UI_ITEM. Компонент нарисован с использованием xpmdata в качестве пиктограммы. Функции label, tooltip и callback должны быть заданы.
Тип GNkME APP UI ITEM. Компонент нарисован с использованием xpm__data в качестве пиктограммы. Функции label, tooltip, callback и user_data должны быть заданы.
Тип GNkME_APP_UI_ITEM. Компонент нарисован без пиктограммы. Функции label, tooltip и callback должны быть заданы.
Тип GNkME_APP_UI__ITEM. Компонент нарисован с использованием имеющейся пиктограммы, указанной stockid. Функции label, tooltip и callback должны быть заданы.
Тип GNkME_APP_UI_JTEM. Вставляет радиокомпонент, использующий xpm data как его пиктограмму. Функции label, tooltip и callback должны быть заданы.
Тип GNkME_APP_UI_ITEM. Вставляет радиокомпонент, использующий xpm_data как его пиктограмму. Функции label, tooltip, callback и user data должны быть заданы.. . ;
Тип GNkME_APP_UI_SEPARATkR. В меню вставляет пустую строку. Для панели инструментов вставляет пустое пространство (пробел).
Тип GNkME_APP_UI_SUBTREE. tree — адрес первого элемента массива структур, GnomeUMMo. Функция label должна быть задана.
Тип GNkME_APP_UI_SUBTREE. tree т- адрес : первого элемента массива структур GnomeUlInfp. - Функция label — это метка для компонента (пункта), hint — это текст, используемый для строки состояния. Функции label и hint должны быть заданы.
Тип GNkME_APP_UI_SUBTREE. tree — адрес первого элемента массива структур GnomeUHnfo. Функция label — это метка для компонента (пункта), stock__id — пиктограмма, используемая для прорисовки компонента (пункта).
Таблица 8.3. (продолжение)
Имя макроса Описание
GNkMEUIINFk_TkGGLEITEM (label, tooltip, callback, xpm_data)
Тип GNkME_APP_UI_TkGGLEITEM. Это отмечаемая кнопка, нарисованная с xpm_data в качестве пиктограммы. Функции label, tooltip и callback должны быть заданы.
GNkMEUIINFk_TkGGLEITEM_KATA (label, toolti p, callback, user_data, xpm_data)
Тип GNkME_APP_UI_TkGGLEITEM. Это отмечаемая кнопка, нарисованная с xpm_data в качестве пиктограммы. Функции label, tooltip, user^data и callback должны быть заданы.
Формат меню по стандарту GNOME
Использование стандартной организации меню имеет ряд преимуществ. Поскольку расположение стандартное, даже пользователи, мало знакомые с вашим приложением, могут быстро найти то, что им нужно, а опытные пользователи не должны вспоминать разные размещения меню. Многие из стандартных форматов развивались с течением времени. Все мы привыкли находить меню File слева, а меню Edit (редактировать) рядом с ним. Мы также ожидаем, что в меню File находятся Save (сохранить) и Exit (выйти). Вдобавок мы ожидаем найти меню Help (помощь) справа, а всплывающее окно About (о программе) в меню Help.
Было бы необычным приложение, для которого необходимы все стандартные пункты меню, так же, как будет редкостным приложение, для которого не нужно было бы добавлять собственные пункты меню. Однако использование стандартного размещения значительно упрощает (особенно для новичка) задачу полной организации меню.
Следующий код — стержневая ветвь программы, которая не делает ничего более кроме того, что определяет набор меню с элементами в стандартных положениях.
/** stdmain.с **/
iinclude <gnome.h> 3
GtkWidget *createMenus(GtkWidget *app); 5
gint eventDelete(GtkWidget *widget, 7GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget, 9GdkEvent *event,gpointer data);
10
int main(int argc,char *argv[J)
{
GtkWidget *app;
* 14GtkWidget ♦statusbar;
15-
gnome_init("stdmain","1.0",argc,argv);
app = gnome_app_new("stdmain",
"Gnome Menu Layout");
gtk_window_set_default_size(GTK_WINDOW(app),200,300);
gtk_signal_connect(GTKOBJECT(app),"delete_event",
GTK_SIGNAL_FUNC(eventDelete),NULL);
gtk_signal_connect(GTK_OBJECT(app),"destroy",
3GTKSIGNALFUNC(eventDestroy),NULL);
24
25statusbar = createMenus(app);
26
27gtk_widget_show_all(арр);
28
29gtk_main();
30exit(0);
31 }
32 gint eventDelete(GtkWidget *widget,
33GdkEvent *event,gpointer data) {
34 return(FALSE);
35 }
36 gint eventDestroy(GtkWidget *widget,
37GdkEvent *event,gpointer data) {
gtk_main_quit();
return(O);
}
Вызов createMenus () в строке 25 создает все меню и устанавливает строку состояния внизу окна. Строка состояния отображает всплывающую подсказку (hint, или tooltip) всякий раз, когда мышь находится внутри пункта меню. Виджет строки текущего состояния возвращен, так что он доступен, если другие части приложения желают использовать его.
Следующий фрагмент определяет размещение меню и предоставляет функцию, которая может использоваться для создания меню и присоединения его к окну GnomeApp. Были разработаны некоторые специальные макросы для создания этих компонентов меню, так что компоненты не только расположены в тех же позициях, как и в других приложениях, но даже для их оформления используются те же самые пиктограммы.
1 2345 678910 11121314151617181920212223242526271 2345 678910 1112131415161718192021222324252627/** stdmenu.c *♦/ ♦include <gnome.h>
1 2
3
4
5 6
7
8
9
10 11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
1 2
3
4
5 6
7
8
9
10 11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
const gchar data[] = "Dummy callback data";
static void helpAbout(GtkWidget *widget,gpointer data)
GtkWidget *aboutBox;
const gchar *writtenBy[] = { "Arthur Griffith", "Lance Peterson", NULL
};
aboutBox = gnome_about_new("Gnome Menu Layout", "0.0",.
"(C) 1999 the Free Software Foundation", writtenBy, "This source code can be used as a starting " '"point to create a Gnome application.",
NULL);
gtk_widget_show(aboutBox);
}
static void dummycallback(GtkObject *object, gpointer data) {
gnome_ok_dialog("Not implemented...");
}.
28
GnomeUIInfo dummyMenu[] = {
{ GNOME_APP_UI_ITEM,"Dummy",
"A placeholder menu entry",
dummyCallback,NULL,NULL,
GNOME_APP_PIXMAP_NONE,
NULL,0,0,NULL },
GNOMEUIINFO END
};
37
GnomeUIInfo fileMenu[] = {
GNOMEUIINFO_MENU_NEW_ITEM("New Window",
"Open a new application window",
dummycallback,data),
GNOMEUIINFO_MENU_NEW_SUBTREE(dununyMenu),
GNOMEUIINFOSEPARATOR,
GNOMEUIINFO_MENU_OPEN_ITEM(dummyCallback,data),
GNOMEUIINFO_MENU_SAVE_ITEM(dummyCallback,data),
GNOMEUIINFO_MENU_SAVE_AS_ITEM(dummyCallback,data),
GNOMEUIINFO_MENU_REVERT_ITEM(dummyCallback,data),
GNOMEUIINFO_MENU_PRINT ITEM(dummyCallback,data),
GNOMEUIINFO_MENU_PRINT_SETUP_ITEM(dummyCallback,data),
GNOMEUIINFO_SEPARATOR,
GNOMEUIINFO_MENU_CLOSE_ITEM(dummyCallback,data),
2GNOMEUI INFO_MENU_EXIT_ITEM (dummyCallback, data),
GNOMEUIINFO END
};
55
GnomeUIInfo editMenuf] = {
GNOMEUIINFO_MENU_UNDO_ITEM(dummyCallback,data),
GNOMEUIINFO_MENU_REDO_ITEM(dummyCalIback,data),
GNOMEUIINFO^SEPARATOR,
GNOMEUIINFO_MENU_CUT_ITEM(dummyCalIback,data),
GNOMEUIINFO_MENU_COPY_ITEM(dummyCallback,data),
GNOMEUIINFO_MENU_PASTE_ITEM(dummyCallback,data),
GNOMEUIINFO_MENU_CLEAR_ITEM(dummyCalIback,data),
GNOMEUIINFO_MENU_SELECT_ALL_ITEM(dummyCallback,data),
GNOMEUIINFO_SEPARATOR,
GNOMEUIINFO_MENU_FIND_ITEM(dummyCallback,data),
GNOMEUIINFO_MENU_FIND_AGAIN_ITEM(dummyCallback,data),
GNOMEUIINFO_MENU_REPLACE_ITEM(dummyCallback,data),
9GNOMEUIINFO_MENU_PROPERTIES_ITEM(dummyCallback,data),
GNOMEUIINFO_END
};
72
GnomeUIInfo gameMenu[] = {
GNOMEUIINFO_MENU_NEW_GAME_ITEM(dummyCalIback,data),
#75GNOMEUIINFO_MENU_PAUSE_GAME_ITEM(dummyCallback,data),
76GNOMEUIINFO_MENU_RESTART_GAME_ITEM(dummyCallback,data),
7 7GNOMEUIINFO_MENU_UNDO_MOVE_ITEM(dummyCallback,data),
GNOMEUIINFO_MENU__HINT_ITEM(dummyCallback,data),
GNOMEUIINFO_MENU_SCORES_ITEM(dummyCallback,data),
GNOMEUI I NFO_MENU_END__GAME_I ТЕМ(dummyCallback,data),
GNOMEUIINFO_END
}-,
83
GnomeUIInfo settingsMenu[] * {
GNOMEUIINFO_MENU_PREFERENCES_ITEM(dummyCallback,data),
GNOMEUIINFO END
};
.
GnomeUIInfo windowsMenu[] = {
GNOMEUIINFO_MENU_NEW_WINDOW_ITEM(dummyCallback,data),
GNOMEUIINFO_MENU_CLOSE_WINDOW_ITEM(dummyCallback,data),
GNOMEUIINFO END
};
94
GnomeUIInfo helpMenu[] = {
GNOMEUIINFOHELP("stdmain"),
GNOMEUIINFO_MENU_ABOUT_ITEM(helpAbout,data),
GNOMEUIINFO_END
};
100
GnomeUIInfo mainMenu[] = {
GNOMEUIINFO_SUBTREE("_File",fileMenu),
GNOMEUIINFO_SUBTREE("_Edit",editMenu),
GNOMEUIINFO_SUBTREE("_View".dummyMenu),
GNOMEUIINFOSUBTREE("Game",gameMenu),
GNOMEUIINFO_SUBTREE("[custom]",dummyMenu),
GNOMEUIINFO_SUBTREE("Settings".settingsMenu),
GNOMEUIINFO_SUBTREE("Windows".windowsMenu),
GNOMEUIINFO_SUBTREE("Help".helpMenu),
GNOMEUIINFO END
};
112
113 GtkWidget *createMenus(GtkWidget *app)
114 { 1
115 GtkWidget *statusbar;
116
117gnome_app_create_menus(GNOME_APP(app),mainMenu);
118
statusbar = gtk_statusbar_new();
gnome_app_install_statusbar_menu_hints(
GTK_STATUSBAR(statusbar),mainMenu);
gnomeappsetstatusbar(GNOMEAPP(app),statusbar);
123
return(statusbar);
}
В строке 4 содержатся фиктивные данные, которые должны передаваться всем функциям обратного вызова. Вместо них вы можете изменить программу для передачи указателя NULL.
Чтобы избежать необходимости записи прототипов для функций обратного вызова, их поместили в начале файла. Функция helpAbout(), которая начинается в строке 6, создает окно About согласно стандарту GNOME. Другая функция обратного вызова, начинающаяся в строке 24, названа dummyCallback() и используется как заполнитель для всех пунктов меню, которые требуют обратных вызовов: появляется сообщение, что выбранный пункт меню не был выполнен.
Подменю, описанное в строках с 29 по 36, фиктивное (лишь макет), его нужно использовать в местах, где необходимо подменю. Не существует стандартного определения относительно его содержания.
Полное меню определено в строках с 38 по 111. Строки со 101 по 111 определяют порядок появления пунктов меню верхнего уровня. Меню File и Edit должны быть
обычны. Меню View (просмотр) специфично для приложения и должно использоваться для переключения между различными способами просмотра данных (изменение масштаба изображения, цветов или порядка сортировки). Меню Game присутствует только в игровой программе. Меню, отмеченное меткой [custom], указывает место, где приложения должны добавить свое собственное меню (одно или несколько). Меню Settings (установки) используется для конфигурирования приложения, в нем могут быть кнопки- переключатели, но оно обязательно должно иметь выбор предпочтительных установок (Preferences); меню Windows контролирует, какое окно отображается в настоящее время.
Входы в меню определяются макросами, которые были разработаны главным образом для этой цели. Например, макрос GNOMEUIINFO_MENU_COPY_ITEM() в строке 61 был разработан для создания элемента меню со словом Сору (копировать) и использует стандартную пиктограмму сору. Три из этих меню показаны на рисунках с 8.3 по 8.5.
Gnome Menu LayoutGnome Menu LayoutFile I Edit View Game [custom] Settings Windows HelpО New Window О New/^ Open .F3Q SaveCtl*S$ Save As...^ RevertО Pnnt Setup... x CloseCthW4J ExitCtl+QFile I Edit View Game [custom] Settings Windows HelpО New Window О New/^ Open .F3Q SaveCtl*S$ Save As...^ RevertО Pnnt Setup... x CloseCthW4J ExitCtl+QSave the current fileSave the current file| file Edit] View Game (custom] Settings Windows Help .** Undo«♦ RedoCtl+Ry- CutCtkX^ copyCtUC■M PasteOkVClear Select All «у Find...F6^ Find Again Shft+F6 ♦^ Replace. F7 {^ Properties . Copy the selection| file Edit] View Game (custom] Settings Windows Help .** Undo«♦ RedoCtl+Ry- CutCtkX^ copyCtUC■M PasteOkVClear Select All «у Find...F6^ Find Again Shft+F6 ♦^ Replace. F7 {^ Properties . Copy the selection
Gnome Menu Layout
Gnome Menu Layout
File I Edit View Game [custom] Settings Windows Help
О New Window О New/
^ Open .F3
Q SaveCtl*S
$ Save As...
^ Revert
О Pnnt Setup... x CloseCthW
4J ExitCtl+Q
File I Edit View Game [custom] Settings Windows Help
О New Window О New/
^ Open .F3
Q SaveCtl*S
$ Save As...
^ Revert
О Pnnt Setup... x CloseCthW
4J ExitCtl+Q
Save the current file
Save the current file
| file Edit] View Game (custom] Settings Windows Help .** Undo
«♦ RedoCtl+R
y- CutCtkX
^ copyCtUC
■M PasteOkV
Clear Select All «у Find...F6
^ Find Again Shft+F6 ♦^ Replace. F7 {^ Properties . Copy the selection
| file Edit] View Game (custom] Settings Windows Help .** Undo
«♦ RedoCtl+R
y- CutCtkX
^ copyCtUC
■M PasteOkV
Clear Select All «у Find...F6
^ Find Again Shft+F6 ♦^ Replace. F7 {^ Properties . Copy the selection
Рисунок 8.4.Вид стандартного меню EditРисунок 8.4.Вид стандартного меню Edit5j(5j(File Edit View Game | (custom] Settings Windows HelpFile Edit View Game | (custom] Settings Windows HelpNew game Ctl+NA, Pause game Restart game** Undo move Ctl+Z Hint^ Scores .End gameNew game Ctl+NA, Pause game Restart game** Undo move Ctl+Z Hint^ Scores .End gamePause the gamePause the gameРисунок 8.5.Вид стандартного меню GameРисунок 8.5.Вид стандартного меню Game
Рисунок 8.4.
Вид стандартного меню Edit
Рисунок 8.4.
Вид стандартного меню Edit
5j(
5j(
File Edit View Game | (custom] Settings Windows Help
File Edit View Game | (custom] Settings Windows Help
New game Ctl+N
A, Pause game Restart game
** Undo move Ctl+Z Hint
^ Scores .
End game
New game Ctl+N
A, Pause game Restart game
** Undo move Ctl+Z Hint
^ Scores .
End game
Pause the game
Pause the game
Рисунок 8.5.
Вид стандартного меню Game
Рисунок 8.5.
Вид стандартного меню Game
Рисунок 8.3.
Вид стандартного меню File
Строки с 39 по 43 определяют пункты меню, которые предусматривают опцию (опции) New. Это обычно используется, как в Netscape, для открытия нового окна приложения. Если имеется только одна опция New, то должен использоваться макрос, начинающийся в строке 39. В случае более чем одной опции New нужно разместить их в подменю, как в строке 42. В текущем приложении применяется только одна из этих двух опций.
• Есть специальный пункт меню, определенный в строке 96. Этот макрос генерирует код, необходимый для создания меню Help, внося в список различные разделы подсказки, доступные для этого приложения. Список ак-
туальных разделов извлекается непосредственно из справочных файлов, как это позже
описано в этой главе. Рис. 8.6 демонстрирует вид меню для приложения, которое имеет два раздела, описанные в файлах справки (помощи).
Inclows Help]Overview TheJFopic File vy About..Inclows Help]Overview TheJFopic File vy About..Рисунок 8.6. Меню Help c двумя разделамиРисунок 8.6. Меню Help c двумя разделамиФункция, начинающаяся в строке ИЗ, создает совокупность меню вместе со строкой состояния приложения. Меню создаются и присоединяются к окну в строке 117. Строка состояния создается в строке 119, а вызов gnome_app_install_menu_hints() в строке 120 подготавливает строку состояния для отображения сообщения, обнаруженного в описаниях меню. Строка состояния присоединяется к окну приложения путем обращения к gnome_app_set_statusbar () в строке 122.
Inclows Help]
Overview TheJFopic File vy About..
Inclows Help]
Overview TheJFopic File vy About..
Рисунок 8.6. Меню Help c двумя разделами
Рисунок 8.6. Меню Help c двумя разделами
Файлы подсказки
Файлы подсказки, или справки, или помощи (help), написаны на HTML, и их отображает браузер (browser) — программа просмотра. Для этого вы помещаете файлы HTML вместе с индексным файлом в определенный каталог. Когда ваше приложение запущено, он читает индексный файл справочного раздела и создает из него меню.
ПРИМЕЧАНИЕ
В текущей версии GNkME для отображения текста подсказки используется Web-браузер Netscape. В будущем планируется разработать для GNkME собственный механизм отображения файлов HTML для работы конкретно со справочной системой.
В предыдущем примере в строке 96 это достигнуто использованием макроса GNOMEUIINFO_HELP () как части описания справочного меню. Вы должны всегда включать этот макрос в меню справки, потому что выбор из меню может быть сделан только тогда, когда существует текст подсказки, определенный для приложения. К тому же используемое имя — это обычно имя приложения, потому что эти названия, как правило, уникальны и, надо надеяться, просты для запоминания.
В предыдущем примере и программа, и справочные файлы названы stdmain. Это означает, что программа ищет файлы подсказки в следующем каталоге:
/usr/share/gnome/help/stdmain/C
Каталог С принят по умолчанию, но может существовать текст справки, написанный на нескольких языках и каждый со своим собственным каталогом. Например, набор описаний для меню справки и файлов на немецком языке мог бы быть сохранен в следующем каталоге:
/usr/share/gnome/help/stdmain/de
Используемый язык определяется текущим вариантом национальных настроек, как это обсуждается в главе 23. Файл, используемый вашим приложением для создания меню, находится в этом каталоге и назван topic.dat. В этом файле одна строка соответствует каждому компоненту меню. Файл topic.dat для предыдущего примера программы выглядит следующим образом:
helpshow.html_0verview
helpshow.htmlftopicfile The _Topic File
ПРИМЕЧАНИЕ НАУЧНОГО РЕДАКТОРА
URL — Uniform Resource Locator — унифицированный локатор ресурсов. URL — указатель на объект в Internet, содержит информацию о местонахождении объекта, о его имени и способе получения.
Каждая строка начинается с URL локального файла справки, или помощи, и заканчивается именем, которое будет отображено в меню. Имена могут быть записаны таким же образом, как и для любого элемента меню. Разрешаются пробелы, а символ подчеркивания применяется для указания ’’быстрого”, или ’’горячего” (shortcut), символа. В этом примере оба URL указывают на различные места одного и того же справочного файла, но вы также можете адресовать разные файлы.
ПРИМЕЧАНИЕ НАУЧНОГО РЕДАКТОРА
"Быстрый”, или "горячий”, символ — это символ, при нажатии которого на клавиатуре происходит выполнение какой-нибудь команды или функции.
Вы можете видеть, насколько просто изменить справочную информацию, так как само приложение при этом не затрагивается. Вы можете делать это не только с вашими приложениями, а также можете добавить специальный элемент "Му Notes” (’’Мои Примечания”) в меню справки и использовать его для аннотирования любого приложения. В предыдущем примере, когда сделан выбор из меню, браузер Netscape выводит информацию, как это показано на рис. 8.7.
File Edit View Go Communicator
..; ^' Bookmarks ^ Location: ^FileVusr/share/gnoMe/help/stdMain/C/heL Vs^T What’s Related
Help Stdmahi^
This is an example of an HTML page being used as a help file. Because the help I is formatted as HTML it can include anything that can be included in a web; |
page. It is a simple matter to have your help file link to a remote location so the ; | user has easy access to the latest information. For example, this link to get the ; { latest updates on the text and examples in this book.
J File Edit View Game [custom] gettings Windows HelpJ File Edit View Game [custom] gettings Windows Help-№-№This application is very simple, so there isn’t much to the text of the help file, but the window of the appliation is shown at the left.
J File Edit View Game [custom] gettings Windows Help
J File Edit View Game [custom] gettings Windows Help
-№
-№
Всплывающее меню
Такое меню обычно не видно, а вызывается оно при помощи щелчка правой кнопкой мыши где-нибудь в пределах окна. Меню из следующего примера показано на рис. 8.8.
/♦♦ gnomepopup.с **/
#include <gnome.h>
3
static void dummyCallback(GtkObject *,gpointer);
5
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
Рисунок 8.7.Текст подсказки GNOME, написанный на HTMLРисунок 8.7.Текст подсказки GNOME, написанный на HTMLShowReduce ■Expand .Edit f ••—^ Cui Ctl+X ^sCopy Ctl+C ^ Paste ctl+v DeleteShowReduce ■Expand .Edit f ••—^ Cui Ctl+X ^sCopy Ctl+C ^ Paste ctl+v DeleteРисунок 8.8.Всплывающее менюРисунок 8.8.Всплывающее менюGdkEvent *event,gpointer data);
Рисунок 8.7.
Текст подсказки GNOME, написанный на HTML
Рисунок 8.7.
Текст подсказки GNOME, написанный на HTML
Show
Reduce ■
Expand .
Edit f ••—
^ Cui Ctl+X ^sCopy Ctl+C ^ Paste ctl+v Delete
Show
Reduce ■
Expand .
Edit f ••—
^ Cui Ctl+X ^sCopy Ctl+C ^ Paste ctl+v Delete
Рисунок 8.8.
Всплывающее меню
Рисунок 8.8.
Всплывающее меню
10
GnomeUIInfo showMenu[] = {
GNOMEUIINFO_ITEM("Next",NULL,dummyCallback,NULL),
GNOMEUIINFO_ITEM("Previous",NULL,dummyCallback,NULL),
GNOMEUIINFO_ITEM("Zoom In",NULL,dummyCallback,NULL),
GNOMEUIINFO_ITEM("Zoom Out",NULL,dummyCallback,NULL),
GNOMEUIINFO END
17
18
GnomeUIInfo editMenu[] = {
GNOMEUIINFO_MENU_CUT_ITEM(dummyCallback,NULL),
GNOMEUIINFO_MENU_COPY_ITEM(dummyCallback,NULL),
GNOMEUIINFO_MENU_PASTE_ITEM(dummyCallback,NULL),
GNOMEUIINFO_ITEM("Delete".NULL,dummyCallback,NULL),
GNOMEUIINFO END
};
26
GnomeUIInfo mainMenu[] = {
GNOMEUIINFO_SUBTREE("Show",showMenu),
GNOMEUIINFO_ITEM("Reduce",NULL,
dummyCallback,NULL),
GNOMEUIINFO_ITEM("Expand",NULL,
dummyCallback,NULL),
GNOMEUIINFO_SUBTREE("Edit",editMenu),
GNOMEUIINFO_END
};
36
int main(int argc,char *argv[])
<.
GtkWidget *window;)
GtkWidget *menu;\
41
gnome_init("gnomepopup","1.0",argc,argv);
window = gnomeappnew("gnomepopup","Popup");
gtk_container_set_border_width(GTK_CONTAINER(window),
80);
gtk_signal_connect(GTK_OBJECT(window),"deleteevent",
GTKSIGNALFUNC(eventDelete),NULL);
gtksignalconnect(GTK_OBJECT(window),"destroy",
GTK_SIGNAL_FUNC(eventDestroy),NULL);
50
menu = gnome_popup_menu_new(mainMenu);
2gnome_popup_menu_attach(menu,window,NULL);
gtk_widget_show_a11(window);
54
gtk_main();
exit(0);
}
static void dummyCallback(GtkObject *object,gpointer data)
{
gnomeokdialog("Not implemented");
}
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data) {
return(FALSE);
}.
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data) {
68gtk_main_quit();
69return(O);
70 }
Описания меню в строках с 11 по 35 используют те же самые макросы и инициализаторы, что и предыдущие примеры. Различие начинается в строке 51с вызовом gnome_popup_menu_new ( ), создающим меню. Обращение к функции gnome_popup_menu_attach() в строке 52 связывает в окне меню и правую кнопку мыши. Как вы можете видеть на рисунке 8.8, меню появляется так же, как и видимое меню, за исключением того, что блок главного меню отображен вертикально, а не горизонтально.
Создание панели инструментов
В следующем примере создается и отображается панель инструментов (1оо1Ъаг).Технология создания панели инструментов в основном такая же, как и при создания меню. Весь массив структур GnomeUIInfо заполнен информацией, необходимой для каждой кнопки панели, а для создания панели инструментов и присоединения ее к окну вызывается функция. Панель инструментов действует подобно меню в том смысле, что также отображается как список чувствительных к мышке прямоугольников и ждет щелчка мыши для выполнения функции обратного вызова.
/** toolbar.с **/
iinclude <gnome.h>
3
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
8
static void toolbarNew(GtkObject *,gpointer);
static void toolbarOpen(GtkObject *,gpointer);
static void toolbarSave(GtkObject *,gpointer);
static void toolbarSaveAs(GtkObject *,gpointer);
13
static GnomeUIInfo toolbarFile[] = {
{ GNOME_APP_UI_ITEM,"New",
"Create a new file",toolbarNew,NULL,NULL,
GNOME_APP_PIXMAP_STOCK,GNOME_STOCK_PIXMAPNEW,
0,0,NULL },
{ GNOME_APP_UI_ITEM,"Open",
"Open an existing file",toolbarOpen,NULL,NULL,
GNOME_APP_PIXMAP_STOCK,GNOME_STOCK_PIXMAP_OPEN,
0,0,NULL },
{ GNOME_APP_UI_ITEM,"Save",
"Save the current file",toolbarSave,NULL,NULL,
GNOME_APP_PIXMAP_STOCK,GNOME_STOCK_PIXMAP_SAVE,
260,0,NULL },
{ GNOME_APP_UI_ITEM,"Save as",
"Save to a new file",toolbarSaveAs,NULL,NULL,
9GNOMEAPPPIXMAPSTOCK,GNOME_STOCK_PIXMAP_SAVE_AS,
300,0,NULL },
GNOMEUIINFO_END
};
33
34 int main(int argc,char *argv[])
35 {
36 GtkWidget *app;
37
38gnome_init("toolbar","1.0",argc,argv);
39app = gnome_app_new("toolbar",
40"Gnome Toolbar Layout");
41gtk_window_set_default_size(GTK_WINDOW(app),300,200);
42gtk_signal_connect(GTK_OBJECT(app),"delete_event",
43GTK_SIGNAL_FUNC(eventDelete),NULL);
44gtk_signal_connect(GTK_OBJECT(app),"destroy",
45GTK_SIGNAL_FUNC(eventDestroy),NULL);
46
4 7gnome_app_create_toolbar(GNOME_APP(app),toolbarFile);
48
49gtk_widget_show_all(app);
50gtk_main();
51exit(0);
52 }
53 static void toolbarNew(GtkObject *object,gpointer data)
54 {
55 gnome_ok_dialog("New");
56 }
57 static void toolbarOpen(GtkObject *object,gpointer data)
58 {
59 gnome_ok_dialog("Open");
60 }
61 static void toolbarSave(GtkObject *object,gpointer data)
62 {
63 gnome_ok_dialog("Save");
64 }
65 static void toolbarSaveAs(GtkObject *object,gpointer data)
66 {
67 gnome_ok_dialog("Save as");
68 }
69 gint eventDelete(GtkWidget *widget,
70GdkEvent *event,gpointer data) {
71 return(FALSE);
72 }.
73 gint eventDestroy(GtkWidget *widget,
74GdkEvent *event,gpointer data) {
75gtk_main quit();
76return(0);
77 }
Панель инструментов определена в виде массива в строках с 14 по 32. Имена тегов и все обратные вызовы работают так же, как и в случае меню. Каждый элемент в этом массиве использует цветную растровую пиктограмму из семейства пиктограмм GNOME, примечание (аннотацию) и текст подсказки. Имеющиеся пиктограммы описываются в следующем разделе.
Обращение к функции gnome_app_create_toolbar() в строке 47 использует массив для создания панели инструментов и прикрепления ее к окну.
На рис. 8.9 панель инструментов показана сверху окна в заданной по умолчанию конфигурации. Всплывающая подсказка (tooltip, или hint) отображается всякий раз, когда указатель мыши находится на кнопке панели инструментов. Панель инструментов может быть оторвана и помещена в любом месте экрана, как показано на рис. 8.10. Панель инстру-
ментов также можно закреплять сверху, у основания, с левой или правой сторон окна в отличие от меню, которое можно закреплять только сверху и снизу.
££Рисунок 8.9.Заданная по умолчанию конфигурация панели инструментовРисунок 8.9.Заданная по умолчанию конфигурация панели инструментов^ G ^Open 'Save Save as^ G ^Open 'Save Save asРисунок 8.10..Панель инструментов может быть перемещена в любое место экранаРисунок 8.10..Панель инструментов может быть перемещена в любое место экрана
£
£
Рисунок 8.9.
Заданная по умолчанию конфигурация панели инструментов
Рисунок 8.9.
Заданная по умолчанию конфигурация панели инструментов
^ G ^
Open 'Save Save as
^ G ^
Open 'Save Save as
Рисунок 8.10..
Панель инструментов может быть перемещена в любое место экрана
Рисунок 8.10..
Панель инструментов может быть перемещена в любое место экрана
Рисунок 8.11 отображает вертикальную панель инструментов, закрепленную с левой стороны окна.
Если вы предпочитаете не включать текст как часть отображаемой панели инструментов, используйте NULL там, где обычно определяете строку. Такое изменение для вышеупомянутой программы создает окно с более узкой панелью инструментов, подобно показанной на рис. 8.12.
Рисунок 8.11.Закрепление панели инструментов на боковой стороне преобразует ее к вертикальному размещениюРисунок 8.11.Закрепление панели инструментов на боковой стороне преобразует ее к вертикальному размещениюРисунок 8.12.Панель инструментов без отображаемого текстаРисунок 8.12.Панель инструментов без отображаемого текста
Рисунок 8.11.
Закрепление панели инструментов на боковой стороне преобразует ее к вертикальному размещению
Рисунок 8.11.
Закрепление панели инструментов на боковой стороне преобразует ее к вертикальному размещению
Рисунок 8.12.
Панель инструментов без отображаемого текста
Рисунок 8.12.
Панель инструментов без отображаемого текста
Семейство пиктограмм
Использование семейства пиктограмм — другой способ стандартизировать ваше приложение так, чтобы оно работало подобно другим приложениям GNOME. Причем в GNOME имеется ряд готовых пиктограмм. На рис. 8.13 показан стандартный набор пиктограмм, сохраненных на диске в виде файлов формата PNG, которые имеют те же названия, что и метки (надписи), показанные на рисунке.
Следующая программа создает изображение, показанное на рисунке 8.13.
/** showstock.с **/'
linclude <gnome.h>
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
8
gchar *stock[] = {
GNOME_STOCK_PIXMAP_NEW,
GNOME_STOCK_PIXMAP_OPEN,
GNOME_STOCK_PIXMAP_CLOSE,
GNOME__STOCK_PIXMAP_REVERT,
GNOME_STOCK_PIXMAP_SAVE,
GNOME_STOCK_PIXMAP_SAVE_AS,
GNOME_STOCK_PIXMAP_CUT,
GNOME_STOCK_PIXMAP_COPY,
GNOME_STOCK_PIXMAP_PASTE,
GNOME_STOCK_PIXMAP_CLEAR,
GNOME_STOCK_PIXMAP_PROPERTIES,
GNOME_STOCK_PIXMAP_PREFERENCES,
GNOME_STOCK_PIXMAP_HELP,
GNOME_STOCK_PIXMAP_SCORES,
GNOME__STOCK_PIXMAP_PRINT,
GNOME_STOCK_PIXMAP_SRCHRPL,
GNOME_STOCK_PIXMAP_SEARCH,
GNOME_STOCK_PIXMAP_BACK,
GNOME_STOCK_PIXMAP_FORWARD,
GNOME_STOCK_PIXMAP_FIRST,
GNOME_STOCK_PIXMAP_LAST,
GNOME_STOCK_PIXMAP_HOME,
GNOME_STOCK_PIXMAP STOP,
gnome_stock_pixmap2refresh,
GNOME_STOCK_PIXMAP_UNDO,
GNOME_STOCK_PIXMAP_REDO,
GNOME_STOCK_PIXMAP_TIMER,
GNOME_STOCK_PIXMAP_TIMER_STOP,
GNOME_STOCK_PIXMAP_MAIL ,
GNOME_STOCK_PIXMAP_MAIL_RCV,
GNOME_STOCK_PIXMAP_MAIL_SND,
GNOME_STOCK_PIXMAP_MAIL_RPL,
GNOME STOCK_PIXMAP_MAIL_FWD,
GNOME~STOCK_PIXMAP_MAIL_NEW,
GNOME_STOCK_PIXMAP_TRASH,
GNOME_STOCK_PIXMAP_TRASH_FULL,
GNOME_STOCK_PIXMAP_UNDELETE,
GNOME_STOCK_PIXMAP_SPELLCHECK,
GNOME_STOCK_PIXMAP_MIC,
GNOME_STOCK_PIXMAP_LINE_IN,
GNOMESTOCKPIXMAPCDROM,
GNOME_STOCK_PIXMAP_VOLUME,
GNOME_STOCK_PIXMAP_MIDI,
GNOMESTOCKPIXMAPBOOKRED,
GNOME_STOCK_PIXMAP_BOOK_GREEN,
GNOME_STOCK_PIXMAP_BOOK_BLUE,
6GNOME_STOCK_PIXMAP_BOOK_YELLOW,
GNOMESTOCKPIXMAPBOOKOPEN,
GNOME_STOCK_PIXMAP_ABOUT,
GNOME_STOCK_PIXMAP_QUIT,
GNOME_STOCK_PIXMAP_MULTIPLE,
GNOME_STOCK_PIXMAP_NOT,
GNOME_STOCK_PIXMAP_CONVERT,
GNOME_STOCK_PIXMAP_JUMP_TO,
GNOME_STOCK_PIXMAP_UP,
GNOMESTOCK_PIXMAP_DOWN,
GNOME_STOCK_PIXMAP_TOP,
GNOME_STOCK_PIXMAP_BOTTOM,
GNOME_STOCK_PIXMAP_ATTACH,
GNOME_STOCK_PIXMAP_INDEX,
GNOME_STOCK_PIXMAP_FONT,
GNOME_STOCK_PIXMAP_EXEC,
GNOME_STOCK_PIXMAP_ALIGN_LEFT,
GNOME_STOCK_PIXMAP_ALIGN_RIGHT,
GNOMESTOCKPIXMAP_ALIGN_CENTER,
GNOME_STOCK_PIXMAP_ALIGN_JUSTIFY,
GNOME_STOCK_PIXMAP_TEXT_BOLD,
7GNOME_STOCK_PIXMAPJTEX T_ITALIC,
GNOME_STOCK_PIXMAP_TEXT_UNDERLINE,
GNOME_STOCK_PIXMAP_TEXT_STRIKEOUT,
GNOME_STOCK_PIXMAP_TEXT_INDENT,
GNOME_STOCK_PIXMAP_TEXT_UNINDENT,
GNOME_STOCK_PIXMAP_EXIT,
GNOMESTOCKPIXMAPCOLORSELECTOR,
GNOME_STOCK_PIXMAP_ADD,
GNOME_STOCK_PIXMAP_REMOVE,
GNOME_STOCK_PIXMAP_TABLE_BORDERS,
GNOME_STOCK_PIXMAP_TABLE_FILL,
GNOME_STOCK_PIXMAP_TEXT_BULLETED_LIST,
GNOME_STOCK_PIXMAP_TEXT_NUMBERED_LIST
};
91
static GnomeUIInfo iconinfo = {
GNOME_APP_UI_ITEM,NULL,NULL,NULL,NULL,NULL,
GNOMEAPPPIXMAPSTOCK,NULL,0,0,NULL
};
static GnomeUIInfo endinfo = GNOMEUIINFO_END;
static GnomeUIInfo toolbarlnfo[10]; 98 99 int main(int argc,char *argv[]) 100 { 101ints;
intt;
intcount;
inttotal_size;
GtkWidget *app;
106
107gnome_init("showstock","1.0",argc,argv);
app = gnome_app_new("showstock",
"Gnome Stock Icons");
gtksignalconnect(GTKOBJECT(app),"deleteevent",
.GTK_SIGNAL_FUNC(eventDelete),NULL);
gtk_signal_connect(GTK_OBJECT(app),"destroy",
GTK_SIGNAL_FUNC(eventDestroy),NULL);
114
115
116total_size = sizeof(stock)/sizeof(gchar*);
117s=0;
118while(s < total_size) {
119for(t=0, count=0; count<9; t++, count++) {
120memcpy(6toolbarlnfo[t],
121&iconlnfo,sizeof(iconinfo));
122toolbarInfo[t].label = stock[s];
123toolbarlnfo[t].pixmap_info=stock[s];
124memcpy(&toolbarInfо[t+l]t
125&endlnfo,sizeof(endinfo));
126if(strlen(stock[s]) > 12)
127count++;
128if(++s >= total size)
129break;
130}
131gnome_app_create_toolbar(GNOME_APP(app),
132toolbarinfo);
133gtk_widget_show_all(app);
134}
135
136gtk_main();
137exit(0);
138 }
139 gint eventDelete(GtkWidget *widget,
140GdkEvent *event,gpointer data) {
141return(FALSE);
142 }
143 gint eventDestroy(GtkWidget *widget,
144GdkEvent *event,gpointer data) {
145gtk_main_quit();
146return(O);
147 }
1
О ^*& О ^ ^ 9> <6
New Open Close Revert Save Save As Cut Copy Paste
ъ@ Ф?aо &&
ClearPropertiesPreferencesHelpScoresPrintSearch/ReplaceSearch
<*
Back Forward Flrtt last Home Stop Refresh Undo Redo
^ о Q q ^^
Timer Timer StoppedMailReceive Mail Send Mail Reply to Mail Forward Mail
О 8^.^ 'V$9@«
New MailTrashTrash Full Undelete Spellchecker Microphone Line InCdromVolume
ess@!9,@!Q<4j<a ^
MidiBook Red Book Green Book Blue Book Yellow Book Open AboutQuitMultiple
0 «4 <PAVS 29Й
NotConvert Jump ToUpDownTopBottomAttachIndex
^^^^*mi вzv
FontExecLeftRightCenterJustifyBoldItalicUnderline
■^frxr"8flR<t4
Strikeout Text Indent Text UnindentQuitColor SelectAddRemove Table Borders
Tai
lie FillText Bulleted List Text Numbered List
Рисунок 8.13. Семейство пиктограмм GNOME
Каждая символьная строка в массиве строк, который начинается со строки 9, идентифицирует пиктограмму. Заголовочный файл GNOME под названием gnome-stock.h со-
держит определения для каждой символьной строки, которая именует пиктограмму. Вы можете просто вставить строку в кавычках, что запретит компилятору анализировать ее тип. Определения имен выглядят следующим образом:
♦define GNOME_STOCK_PIXMAP_NEW"New"
♦define GNOME_STOCK_PIXMAP_OPEN"Open"
♦define GNOME_STOCK_PIXMAP_CLOSE"Close"
Все имена пиктограмм включены в единый массив, начинающийся в строке 96. Чтобы были отображены включенные в панель инструментов пиктограммы, используется массив имен. Массив GnomeUIInfo в строке 97 используется в качестве конструктивного размещения для описаний панели инструментов. Структура GnomeUIInfo в строке 92 является информационным элементом для пиктограммы, но в структуре опущены метка и имя. Структура GnomeUIInfo в строке 96 — стандартный признак конца массива.
Цикл с оператором while, начинающийся в строке 118, выполняется один раз для каждой созданной панели инструментов. Внутренний цикл, определенный в строке 119, выполняется один раз для каждой пиктограммы, вставляемой в текущую панель инструментов. Вызов memcpy() в строке 120 копирует в массив элемент пиктограммы. Затем в строках 122 и 123 вставляются строки идентификаторов пиктограмм; это вовсе не обязательно, но в этом примере имя пиктограммы и текст метки одинаковы. Вызов memepy () в строке 124 копирует признак конца в следующую позицию в массиве, превращая его в узаконенное определение панели инструментов.
Отображаемые размеры пиктограмм панели инструментов одинаковы, то есть каждая пиктограмма панели инструментов увеличивается в горизонтальном и вертикальном направлениях до размеров максимальной. Как вы можете видеть на рис. 8.13, текст метки (надписи) делает часть пиктограмм очень широкими. Счетчик count, указывающий число добавленных к панели инструментов пиктограмм, для лучшего отображения в окне корректируется в строке 127 всякий раз, когда имя элемента превышает 12 символов.
Удаление текстового примечания (аннотации) внизу пиктограмм резко сокращает размер панелей. На рис. 8.14 показан результат удаления из программы строки 123, приведший к пиктограммам без текстовых подписей. Из рисунка также видно, что каждая панель инструментов может быть установлена и ориентирована отдельно: панель инструментов можно закреплять сверху или внизу горизонтально, слева или справа вертикально или помещать в любое место экрана в горизонтальной или вертикальной ориентации.
» » » -а да» l
к
&
<3 ▻ и м 0 ® ф
© оф))
Рисунок 8.14.
Панели инструментов могут быть установлены независимо друг от друга
Нестандартные пиктограммы
Вы можете взять пиктограмму откуда угодно. Абсолютно любое имеющееся изображение можно использовать в качестве пиктограммы панели инструментов. Как только вы преобразуете изображение в файл формата ХРМ, можно вставлять его непосредственно в программу или загружать во время ее выполнения. В следующей программе применяются три различных метода образования пиктограмм для панели инструментов.
1
/** toolbarcustom
.с
“/
2
♦include
<gnome.h>
3
4
static i
char
♦modulate[]
=
{
5
25
24 :
2 1",
6
*
i
С j
None",
7
B (
с i
Black",
8
*
9
в
10
в
11
В
в
•
12
*
В
в
в
13
в
В
в
в
в
14
в
В
В В
в
в
в
в
*
15
в
в
В В
в
в
в
в
16
*
в
в
В в
в
в
в
в
в
17
в
в
в в
в
в
в
в
в
*
18
*
в
в
В
в в
в
в
в
в
в
в
*
19
*
в
в
В
в в в
в
в
в
в
в
в
20
в
в
В
в в в
в
в
в
в
в
в
21
в
в
В
в в
в
в
в
в
в
в
22
в
в
в в
в
в
в
в
в
*
23
в
в
в в
в
в
в
в
в
*
24
в
в
в в
в
в
в
в
в
25
в
в
в, в
в
в
в
в
26
в
в
в
в
в
в
в
27
в
в
в
в
в
*
28
в
в
в
29
в
в
*
30
в
31
в
И
32 };
33
34 gint eventDelete(GtkWidget *widget,
35GdkEvent ♦event,gpointer data);
36 gint eventDestroy(GtkWidget *widget,
37GdkEvent ♦event,gpointer data);
38
39 static GnomeUIInfo toolbarFile[] = {
40{ GNOME_APP_UI_ITEM,MRedeksM,
41"Create a new file",NULL,NULL,NULL,
42GNOME_APP_PIXMAP_FILENAME,"redeks.xpm",
430,0,NULL },
44{ GNOME_APP_UI_IТЕМ,"Open",
45"Open an existing file",NULL,NULL,NULL,
46GNOME_APP_PIXMAP_STOCK,GNOME_STOCK_PIXMAP_OPEN,
470,0,NULL },
48{ GNOME APP UI ITEM,"Modulate",
49"Create a new file",NULL,NULL,NULL,
50GNOME_APP_PIXMAP_DATA,(modulate,
510,0,NULL },
52{ GNOME_APP_UI_ITEM,"Save",
53"Save the current file",NULL,NULL,NULL,
54GNOME_APP_PIXMAP_STOCK,GNOMB_STOCK_PIXMAP_SAVE,
550,0,NULL },
56 GNOMEUIINFO END.
57 };
58
59 int main(int argc,char *argv[])
60 {
61GtkWidget *app;
62
63gnome_init("toolbarcustom","1.0",argc,argv);
64app = gnome_app_new("toolbarcustom",
65"Custom Toolbar Icons");
66gtk_window_set_default_size(GTK_WINDOW(app),300,200);
67gtk_signal_connect(GTK_OBJECT(app),"deletееvent",
68GTK_SIGNAL_FUNC(eventDelete),NULL);
69gtk_signal_connect(GTK_OBJECT(app),"destroy",
70GTK_SIGNAL_FUNC(eventDestroy),NULL);
71
72gnomeappcreatetoolbar(GNOME_APP(app),toolbarFile);
73
74gtk_widget_show_all(app);
75gtk_main();
76exit(0);
77 }
78 gint eventDelete(GtkWidget *widget,
79GdkEvent *event,gpointer data) {
80return(FALSE);
81 }
82 gint eventDestroy(GtkWidget *widget,
83GdkEvent *event,gpointer data) {
84gtk_main_quit();'
85return(0);
86 }
Описание панели инструментов, начинающееся в строке 39, составлено из двух пользо
вательских пиктограмм и двух пиктограмм семейства GNOME. Определенные в строках 44 и 52 пиктограммы Open и Save — готовые пиктограммы из стандартного семей
ства. Полученное окно показано на рис. 8.15.
X^ I*RedeksOpen ModulateX^ I*RedeksOpen ModulateРисунок 8.15.Для панелей инструментов можно использовать пользовательские пиктограммы и пиктограммы из существующего семействаРисунок 8.15.Для панелей инструментов можно использовать пользовательские пиктограммы и пиктограммы из существующего семействаСтрока 48 — описание пиктограммы Modulate для панели инструментов. GNOME_APP_PIXMAP_DATA — тип ее цветного растрового изображения, что означает графический объект для пиктограммы, откомпилирован- ныйжак часть программы, как в этом примере, или определенный как массив символьных строк. Если данные включенны в программу таким образом, в вашей программе даже можно определять значения пикселов. Данные, хранящиеся в формате ХРМ, как описано в главе 7, и объявленные в этой программе как массив строк, начинаются в строке 4. Изображение шириной 25
X^ I*
RedeksOpen Modulate
X^ I*
RedeksOpen Modulate
Рисунок 8.15.
Для панелей инструментов можно использовать пользовательские пиктограммы и пиктограммы из существующего семейства
Рисунок 8.15.
Для панелей инструментов можно использовать пользовательские пиктограммы и пиктограммы из существующего семейства
пикселов и высотой 24 пиксела имеет только два цвета — прозрачный фон и черные вертикальные линии.
Строка 40 содержит описание пиктограммы Redeks из панели инструментов. Так же, как и пиктограмма Modulate, она использует данные формата ХРМ. Но ее тип определен как GNOME_APP_PIXMAP_FILENAME, и она читает графические данные из поименованного файла на диске. В этом примере файл назван redeks .xpm и имеет следующее содержание: определение пиктограммы шириной 25 пикселов и высотой 24 пиксела, содержащей три цвета (красный, черный и прозрачный).
/* ХРМ */ static char *redeks[] = { "25 24 3 1", " с None", "В с Black", "R с Red",
" ввв ввв " BRRB BRRB " BRRRBB BBRRRB " BRRRRRBB BBRRRRRB " BRRRRRRRBB BBRRRRRRRB
" BBRRRRRRRBBBRRRRRRRRBB
" BBRRRRRRRRRRRRRRBB
" BBRRRRRRRRRRRRBB
"BBRRRRRRRRBB
"BBRRRRBB
"BBRRRRRRRRBB
" BBRRRRRRRRRRRRBB
" BBRRRRRRRRRRRRRRBB
" BBRRRRRRRBBBRRRRRRRRBB
"BRRRRRRRBBBBRRRRRRRB
"BRRRRRBBBBRRRRRB
"BRRRBBBBRRRB
"BRRBBRRB
"BBBBBB
}
Запрещение и разрешение доступа к пунктам меню
Пункт меню динамически может быть сделан доступным и недоступным. Когда он недоступен, то становится блеклым и не реагирует на мышь. Эта технология часто используется для предотвращения доступа пользователя к функциям, которые не могут быть выполнены в текущих условиях. Например, кнопка Save может быть недоступна, если отсутствуют данные для записи на диск.
Следующая программа создает простое меню с тремя кнопками. Верхняя и нижняя кнопки могут использоваться для разрешения и запрещения средней.
/♦♦ mdisable.c ♦♦/
Iinclude <gnome.h>
3
static void dummyCallback(GtkObject *,gpointer);
static void enableProperties(GtkObject *,gpointer);
static void disableProperties(GtkObject *,gpointer);
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent ♦event,gpointer data);
'
Idefine PROP_INDEX 1
GnomeUIInfo enableMenu[] = {
GNOMEUIINFO_MENU_NEW_ITEM("Enable Properties",
"Enable the Properties menuselection",
enableProperties,NULL),
GNOMEUIINFO_MENU_PROPERTIES_ITEM(dummycallback,NULL),
GNOMEUIINFO_MENU_NEW_ITEM("Disable Properties",
"Disable the Properties menuselection",
disableProperties,NULL),
GNOMEUIINFO_END
};
23
GnomeUIInfo mainMenu[] = {
GNOMEUIINFO_SUBTREE("Enable/Disable",enableMenu),
GNOMEUIINFO END
};
28
int main(int argc,char *argv[])
{
GtkWidget *app;
32
gnome_init("mdisable","1.0",argc,argv);
app = gnome_app_new("mdisable","Menu Disable");
35gtk_window_set_defaultsize(GTK_WINDOW(app),200,100);
6gtk_signal_connect(GTK_OBJECT(app),"delete__event",
GTK_SIGNAL_FUNC(eventDelete),NULL);
gtk_signal_connect(GTK_OBJECT(app),"destroy",
GTK_SIGNAL_FUNC(eventDestroy),NULL);
40
gnome_app_create_menus(GNOME_APP(app),mainMenu);
42
gtk_widget_show_all(app);
gtkjnain();
exit(0);
}
static void dummyCallback(GtkObject *object,gpointer data)
{
gnomeok dialog("The dummy callback executed.");
}“
static void disableProperties(GtkObject *object,
gpointer data) {
gtk_widget_set_sensitive(
•GTKJWIDGET(enableMenu[PROP_INDEX].widget),
FALSE);
}
static void enableProperties(GtkObject *object,
gpointer data) {
gtk_widget_set_sensitive(
GTK_WIDGET(enableMenu[PROP_INDEX].widget),
TRUE);
}
63 gint eventDelete(GtkWidget *widget, 64GdkEvent *event,gpointer data) {
65return(FALSE);
66 }
67 gint eventDestroy(GtkWidget *widget,
68GdkEvent *event,gpointer data) {
69gtk_main_quit();
70return(O);
71 }
Массив, объявленный в строках с 13 по 21, описывает меню с тремя кнопками, показанное на рис. 8.16. У первой кнопки имеется функция обратного вызова enableProperties(), а у третьей кнопки — disableProperties().
Функция обратного вызова disableProperties (), описание которой начинается со строки 51, отключает вторую кнопку меню. Функция gtk_widget_set_sensitive() вызывается с двумя аргументами. Первый аргумент — виджет, который включается в массив меню во время вызова gnome_app_create_menus (). Второй аргумент — булево значение FALSE, которое делает пункт меню недоступным, как это показано на рис. 8.17. enableProperties () — функция обратного вызова третьей кнопки, которая начинается со строки 57, также вызывает gtk_widget_set_sensitive(), но с булевым значением TRUE, которое восстанавливает активное состояние кнопки.
Enable/Disable |/> Enable Properties^ Properties..(> Disable PropertiesEnable/Disable |/> Enable Properties^ Properties..(> Disable PropertiesРисунок 8.16.Меню с тремя доступными кнопкамиРисунок 8.16.Меню с тремя доступными кнопкамиEnable/Disable | ♦> Enable Properties
Enable/Disable |
/> Enable Properties
^ Properties..
(> Disable Properties
Enable/Disable |
/> Enable Properties
^ Properties..
(> Disable Properties
Рисунок 8.16.
Меню с тремя доступными кнопками
Рисунок 8.16.
Меню с тремя доступными кнопками
О Disable Properties
Рисунок 8.17.
Трехкнопочное меню с одной недоступной кнопкой
ПРИМЕЧАНИЕ
Индекс пункта меню, который будет адресован, описан как именованная константа в строке 12. Если позже меню изменяется путем вставки новых пунктов или удаления старых, описанная константа, которая появляется тут же с массивом, должна напомнить вам, что следует обновить ее значение. Это прием самозащиты, который может предохранить от некоторых проблем в будущем, вызванных, по-видимому, случайными пунктами меню, ставшими недоступными.
Запрещение и разрешение доступа к элементам панели инструментов
Элемент панели инструментов может быть сделан недоступным и доступным динамически. Когда элемент недоступен, он становится блеклым и не реагирует на мышь. Следующая программа создает простую с тремя кнопками панель инструментов, в которой кнопка в центре может быть разрешена и запрещена кнопками с каждой стороны.
/** tbdisable.c **/
Iinclude <gnome.h>
3
static void dummyCallback(GtkObject *,gpointer);
static void enableProperties(GtkObject *,gpointer);
static void disableProperties(GtkObject ♦,gpointer);
7
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
12
#define DISPROP_INDEX 1
static GnomeUIInfo enableToolbar[] = {
{GNOME_APP_UI_ITEM,"Enable Properties",
"Enable the Properties toolbar selection",
enableProperties,NULL,NULL,
GNOME_APP_PIXMAP_STOCK,GNOME_STOCK_PIXMAP_NEW,
0,0,NULL },
{GNOME_APP_UI_ITEM,"Properties",
"Configure application properties",
dummycallback,NULL,NULL,
GNOME_APP_PIXMAP_STOCK,GNOME_STOCK_PIXMAP_PROPERTIES,
0,0,NULL },
{GNOME_APP_UI_ITEM,"Disable Properties",
"Disable the Properties toolbar selection",
disableProperties,NULL,NULL,
GNOME APP PIXMAP STOCK,GNOME STOCK PIXMAP SAVE AS,
0,0,NULL },
GNOMEUIINFO_END
};
32
int main(int argc,char *argv[])
{
GtkWidget *app;
36
gnome_init("tbdisable","1.0",argc,argv);
app = gnome_app_new("tbdisable","Toolbar Disable");
gtksignalconnect(GTK_OBJECT(app),"delete_event",
GTK_SIGNAL_FUNC(eventDelete),NULL);
gtk_signal_connect(GTK_OBJECT(app),"destroy",
* GTKSIGNALFUNC(eventDestroy),NULL);
43
gnome_app_create_toolbar(GNOME_APP(app),enableToolbar);
gtk_widget_show_all(app);
46
gtk_main();
exit(0);
}
static void dummycallback(GtkObject *object,gpointer data)
{
gnome_ok_dialog("The dummy callback executed.");
}
’static void disableProperties(GtkObject *object,
gpointer data) {
gtkwidgetsetsensitive(
GTK_WIDGET(enableToolbar[DISPROPINDEX].widget),
FALSE);
}
static void enableProperties(GtkObject *object,
gpointer data) {
62 gtk_widget_set_sensitive(
63GTK_WIDGET(enableToolbar[DISPROP_INDEX].widget),
64TRUE);
65 }
66 gint eventDelete(GtkWidget *widget,
67GdkEvent ♦event,gpointer data) {
68return(FALSE);
69 }
70 gint eventDestroy(GtkWidget *widget,
71GdkEvent *event,gpointer data) {
gtk_main_quit();
return(O);
}
Массив, объявленный в строках с 14 по 30, описывает панель инструментов, показанную на рис. 8.18. У левой кнопки имеется функция обратного вызова enableProperties(), а у правой кнопки — disableProperties().
Разрешающий и запрещающий код для компонента панели инструментов такой же, как и для пункта меню. Функция обратного вызова disableProperties(), начинающаяся в строке 54, отключает среднюю кнопку панели инструментов. Функция gtk_widget_set_sensitive() вызывается с двумя аргументами. Первый аргумент — виджет, включаемый в массив меню во время вызова gnome_app_create_menus (). Второй аргумент — булево значение FALSE, которое делает компонент панели инструментов недоступным, как это показано на рис. 8.19. Функция обратного вызова левой кнопки под названием enableProperties(), начинающаяся в строке 60, также вызывает gtk_widget_set_sensitive(), но с булевым значением TRUE, которое восстанавливает активное состояние компонента панели инструментов.
О ^^Enable Properties Properties Disable PropertiesРисунок 8.18.Панель инструментов со всеми разрешенными компонентамиО ^^Enable Properties Properties Disable PropertiesРисунок 8.18.Панель инструментов со всеми разрешенными компонентамиОEnable PropertiesОEnable PropertiesDisable PropertiesDisable PropertiesРисунок 8.19.Панель инструментов с одним недоступным компонентомРисунок 8.19.Панель инструментов с одним недоступным компонентом
О ^^
Enable Properties Properties Disable Properties
Рисунок 8.18.
Панель инструментов со всеми разрешенными компонентами
О ^^
Enable Properties Properties Disable Properties
Рисунок 8.18.
Панель инструментов со всеми разрешенными компонентами
О
Enable Properties
О
Enable Properties
Disable Properties
Disable Properties
Рисунок 8.19.
Панель инструментов с одним недоступным компонентом
Рисунок 8.19.
Панель инструментов с одним недоступным компонентом
Сокрытие и отображение пунктов меню
То, что меню описано статически определенным массивом структур GnomeUIInfo, предохраняет вашу программу от динамического включения и удаления элементов меню. Скрытый пункт меню не отображается, а остальная часть меню выглядит так, как если бы в массиве не было скрытого компонента. Таким образом, чтобы изменить меню, вы просто скрываете и показываете отдельные компоненты (пункты) меню.
В следующем примере создается меню с тремя кнопками. Верхняя кнопка вызывает исчезновение из меню средней кнопки, а нижняя кнопка заставляет среднюю кнопку появиться снова.
/** mhide.c **/
finclude <gnome.h>
3
static void dummyCallback(GtkObject *,gpointer);
static void showProperties(GtkObject *,gpointer);
static void hideProperties(GtkObject *,gpointer);
.
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
12
Idefine PROPERTIES_INDEX 1
GnomeUIInfo showMenu[] = {
GNOMEUIINFO_MENU_NEW_IТЕМ("ShowProperties",
"Show the Properties menuselection",
showProperties,NULL),
GNOMEUIINFO_MENU_PROPERTIES_ITEM(dummyCallback,NULL),
GNOMEUI INFO__MENU_NEW_ITEM("HideProperties",
"Hide the Properties menuselection",
hideProperties,NULL),
GNOMEUIINFO END
};
24
GnomeUIInfo mainMenu[] = {
GNOMEUIINFO_SUBTREE("Show/Hide",showMenu),
GNOMEUIINFOJSND
};
29
int main(int argc,char *argv[])
{
GtkWidget *app;
33
gnome_init("mhide","1.0",argc,argv);
app = gnome_app_new("mhide","Menu Hide");
gtk_window_set_default_size(GTK_WINDOW(app),200,100);
gtk_signal_connect(GTK_OBJECT(app),"delete_event",
GTK_SIGNAL_FUNC(eventDelete),NULL);
gtk_signal_connect(GTK_OBJECT(app),"destroy",
GTK_SIGNAL_FUNC(eventDestroy),NULL);
41
gnome_app_create_menus(GNOMEAPP(app),mainMenu);
.
gtk_widget_show_all(app);
gtk_main();
exit(0);
}
static void dummyCallback(GtkObject *object,
gpointer data) {
gnome_ok_dialog("The dummy callback executed.");
}
static void showProperties(GtkObject *object,
gpointer data) {
gtk_widget_show(
GTK_WIDGET(showMenu[PROPERTIES_INDEX].widget));
}
static void hideProperties(GtkObject *object,
gpointer data) {
gtk_widget_hide(
GTKWIDGET(showMenu[PROPERTIESINDEX].widget));
}
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data) {
return(FALSE);
}
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data) {
gtk_main_quit();
return(O);
}
Меню с тремя кнопками определено в виде массива в строках с 14 по 23. Меню создано и присоединено к главному окну путем обращения в строке 42 к gnome_app_create_menus (). Когда меню появляется вначале, все три его кнопки видимы и оно выглядит, как показано на рис. 8.20.
В случае выбора нижней кнопки меню выполняется функция обратного вызова hideProperties(), которая начинается со строки 57. Вызов gtk_widget_hide () в строке 59 делает вторую кнопку невидимой. Меню смыкается, закрывая пустое пространство, и выглядит так, как показано на рис. 8.21. В случае выбора верхней кнопки меню выполняется функция обратного вызова showProperties (), которая начинается со строки 52 и вызывает gtk__widget_show(), вновь делая вторую кнопку видимой. Отображение кнопки, которая уже отображена (или сокрытие уже сокрытой), не дает никакого эффекта.
Show/Hide"]О Show Properties О Hide PropertiesShow/Hide"]О Show Properties О Hide PropertiesShow/Hide I (> Show Properties (>• Properties... 0- Hide Properties
Show/Hide"]
О Show Properties О Hide Properties
Show/Hide"]
О Show Properties О Hide Properties
Рисунок 8.20.Трехкнопочное меню со всеми отображенными пунктамиРисунок 8.20.Трехкнопочное меню со всеми отображенными пунктамиРисунок 8.21.Трехкнопочное меню с одной скрытой кнопкойРисунок 8.21.Трехкнопочное меню с одной скрытой кнопкой
Рисунок 8.20.
Трехкнопочное меню со всеми отображенными пунктами
Рисунок 8.20.
Трехкнопочное меню со всеми отображенными пунктами
Рисунок 8.21.
Трехкнопочное меню с одной скрытой кнопкой
Рисунок 8.21.
Трехкнопочное меню с одной скрытой кнопкой
Сокрытие и отображение элементов
панели инструментов
Так как панель инструментов описана статически как массив структур GnomeUIInf о, то можно выбрать, какой компонент отображать, а какой — нет. Когда некий компонент панели инструментов не отображен, то в этом случае панель инструментов конфигурирует сама себя так, как если бы скрытый компонент не был включен в определяющий массив.
В следующем примере создается панель инструментов с тремя кнопками. Правая кнопка заставляет среднюю кнопку исчезнуть, а левая кнопка заставляет среднюю кнопку появиться снова.
/** tbhide.c **/
linclude <gnome.h>
3
static void dummyCallback(GtkObject *,gpointer);
static void showProperties(GtkObject *,gpointer);
static void hideProperties(GtkObject *,gpointer);
7
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
12
Idefine PROPERTIES_INDEX 1
static GnomeUIInfо showToolbar[] = {
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
*64
65
66
67
68
69
70
71
{ GNOME_APP_UI_ITEM,"Show Properties", "Enable the Properties toolbar selection", showproperties,NULL,NULL, GNOME АРР PIXMAP STOCK,GNOME STOCK PIXMAP NEW, 0,0,NULL },
{ GNOME_APP_UI_ITEM,"Properties", "Configure application properties", dummyCallback,NULL,NULL, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_PIXMAP_PROPERTIES, 0,0,NULL },
{ GNOME_APP_UI_ITEM,"Hide Properties", "Hide the Properties toolbar selection", hideProperties,NULL,NULL, GNOME APP PIXMAP STOCK,GNOME STOCK PIXMAP SAVE AS, 0,0,NULL },
GNOMEUIINFO_END };
int main(int argc,char *argv[]) {
GtkWidget *app;
gnome_init("tbhide","1.0",argc,argv);
app = gnome_app_new("tbhide","Toolbar Hide");
gtk_signal_connect(GTK_OBJECT(app),"deleteevent", GTK_SIGNAL_FUNC(eventDelete),NULL);
gtk_signal_connect7GTK_OBJECT(app),"destroy", GTK_SIGNAL_FUNC(eventDestroy),NULL);
gnome_app_create_toolbar(GNOME_APP(app),showToolbar); gtk_widget_show_all(app);
gtk_main();
exit(0);
}
static void dummyCallback(GtkObject *object,gpointer data) {
gnome_ok_dialog("The dummy callback executed.");
}
static void showproperties(GtkObject *object,gpointer data) {
gtk_widget_show(
GTKWIDGET(showToolbar[PROPERTIES_INDEX].widget));
}
static void hideProperties(GtkObject *object,gpointer data) {
gtk_widget_hide(
GTK_WIDGET(showToolbar[PROPERTIES_INDEX] .widget)).; } gint eventDelete(GtkWidget *widget, GdkEvent *event,gpointer data) {
return(FALSE);
}
gint eventDestroy(GtkWidget *widget, • GdkEvent *event,gpointer data) { gtk_main_quit();
return(0);
7272}}
72
72
}
}
Панель инструментов с тремя кнопками определена в виде массива в строках с 14 по 31. Панель инструментов создана и присоединена к главному окну с помощью вызова gnome_app_create_toolbar() в строке 42. Вначале, когда появляется панель инструментов, у нее видны все три кнопки, что и отображается на рис. 8.22.
В случае выбора правой кнопки выполняется функция обратного вызова hideProperties (), которая начинается в строке 59. Вызов gtk_widget_hide() в строке 61 заставляет среднюю кнопку исчезнуть с экрана дисплея, панель инструментов немедленно смыкается, заполняя пустое место, и выглядит так, как на рис. 8.23. В случае выбора левой кнопки выполняется функция обратного вызова showProperties (), начинающаяся в строке 54, и вызывает gtk_widget_show(), снова делая среднюю кнопку видимой. Отображение кнопки, которая уже отображена (или сокрытие уже скрытой), не дает никакого эффекта.
Рисунок 8.22.Трехкнопочная панель инструментов со всеми отображенными элементамиРисунок 8.22.Трехкнопочная панель инструментов со всеми отображенными элементамиРисунок 8.23.Трехкнопочная панель инструментов с одним скрытым элементомРисунок 8.23.Трехкнопочная панель инструментов с одним скрытым элементом
Рисунок 8.22.
Трехкнопочная панель инструментов со всеми отображенными элементами
Рисунок 8.22.
Трехкнопочная панель инструментов со всеми отображенными элементами
Рисунок 8.23.
Трехкнопочная панель инструментов с одним скрытым элементом
Рисунок 8.23.
Трехкнопочная панель инструментов с одним скрытым элементом
Радиокнопки в меню
Вы можете включить прямо в меню набор радиокнопок. Одна и только одна радиокнопка может быть выбрана в любой момент. Следующая программа создает меню, содержащее три радиокнопки.
/** mradio.c ♦*/
Iinclude <gnome.h>
3
static void duminyCallback(GtkOb ject *,gpointer);
static void radioOne(GtkObject *,gpointer);
static void radioTwo(GtkObject *,gpointer);
static void radioThree(GtkObject *,gpointer);
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
13
GnomeUIInfo menuRadioList[] = {
GNOMEUIINFO_RADIOITEM("Radio One",
"The first radio button",
radioOne,NULL),
GNOMEUIINFO_RADIOITEM("Radio Two",
"The second radio button",
radioTwo,NULL),
GNOMEUIINFO_RADIOITEM("Radio Three",
"The third radio button",
radioThree,NULL),
GNOMEUIINFO END
};
26
27 GnomeUIInfo radioMenu[] = {
28GNOMEUIINFO_MENU_REDO_ITEM(dummyCalIback,NULL),
GNOMEUIINFOSEPARATOR,
GNOMEUIINFORADIOLIST(menuRadioList),
GNOMEUIINFO_SEPARATOR,
GNOMEUIINFO_MENU_CUT_ITEM(dummyCallback,NULL),
GNOMEUIINFOEND
};
35
GnomeUIInfo mainMenu[] = {
GNOMEUIINFO_SUBTREE("RadioButtons",radioMenu),
GNOMEUIINFO END
};.
40 41 int main(int argc,char *argv[]) 42 {
43GtkWidget *app;
44
45gnome_init("mradio","1.0",argc,argv);
46app = gnome_app_new("mradio","Menu Radio Buttons");
47gtk_window_set_default_size(GTK_WINDOW(app),200,100);
gtk_signal_connect(GTK_OBJECT(app),"delete_event",
GTK_SIGNAL_FUNC(eventDe1ete),NULL);
gtk_signal_connect(GTK_OBJECT(app),"destroy",
GTK_SIGNAL_FUNC(eventDestroy),NULL);
52
gnome_app_create_menus(GNOME_APP(app),mainMenu);
54
gtk_widget_show_all(app);
gtk_main();
exit(0);
}
static void dummyCallback(GtkObject *object,gpointer data)
{
gnome_ok_dialog("The dummy callback executed.");
}
static void radioOne(GtkObject *object,gpointer data)
{
if(GTK_CHECK_MENU_IТЕМ(object)->active)
gnome_ok_dialog("The radio one button is on.");
else
gnome_ok_dialog("The radio one button is off.");
}
static void radioTwo(GtkObject *object,gpointer data)
{
if(GTK_CHECK_MENU_ITEM(object)->active)
gnome_ok_dialog("The radio two button is on.");
else
gnome_ok_dialog("The radio two button is off.");
}
static void radioThree(GtkObject *object,gpointer data)
{
if(GTK_CHECK_MENU_IТЕМ(object)->active)
gnome_ok_dialog("The radio three button is on.");
else
gnome_ok_dialog("The radio three button is off.");
}
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data) {
return(FALSE);
87 }
88 gint eventDestroy(GtkWidget *widget,
89GdkEvent *event,gpointer data) {
90gtk_main_quit();
91return(O);
92 }
Опускающаяся часть меню описана в массиве radiomen в строках с 27 по 34. На
бор радиокнопок включен через макрос GNOMEUIINFO_RADIOLIST() в строке 30. Радиокнопки должны быть описаны как единый блок, так как они взаимодействуют друг с другом. Всякий раз, когда выбрана одна из них, выбор других отменяется.
Отдельные кнопки описаны в массиве структур GnomeUIInfo в строках с 14 по 25.
Каждая из них определена макросом GNOMEUIINFO_RADIOITEM(). Используется иной признак окончания, чем тип GNOME_APP_UIJENDOF_INFO; все члены массива должны иметь тип GNOME_APP_U1_1ТЕМ, который используется макросом GNOMEUIINFO_RADIOITEM().
Все необходимое для создания радиокнопок включено в описанные массивы, так что
меню, как обычно, создается вызовом gnome_app_create_menus () в строке 53. Результирующее меню показано на рис. 8.24.
RadloButtonsl/♦ Redo CthR* Radio One v Radio Two v Radio Three ^ cut Cfl+XРисунок 8.24.Набор радиокнопок вменюRadloButtonsl/♦ Redo CthR* Radio One v Radio Two v Radio Three ^ cut Cfl+XРисунок 8.24.Набор радиокнопок вменюКаждая кнопка меню имеет свою собственную функцию обратного вызова (определены в строках 63, 70 и 77), а каждая функция обратного вызова имеет два возможных выбора. Всякий раз, когда сделан обратный вызов, функция должна проверить, выбрана ли кнопка или выбор отменяется. Когда кнопка выбрана, значение active в виджете отлично от нуля и доступны два обратных вызова. Вновь выбранная кнопка выдает обратный вызов со значением active, отличным от нуля. Кнопка, которая была переключена, становится отмененной и посылает обратный
RadloButtonsl
/♦ Redo CthR
* Radio One v Radio Two v Radio Three ^ cut Cfl+X
Рисунок 8.24.
Набор радиокнопок вменю
RadloButtonsl
/♦ Redo CthR
* Radio One v Radio Two v Radio Three ^ cut Cfl+X
Рисунок 8.24.
Набор радиокнопок вменю
вызов со значением active, установленным в нуль. Если пользователь выбирает кноп
ку, которая уже является активной, есть только один обратный вызов и значение active
отлично от нуля.
Радиокнопки на панели инструментов
Вы также можете включать набор радиокнопок как часть панели инструментов. Они выглядят так же, как и обычные кнопки, за исключением того, что одна и только одна радиокнопка может быть выбрана в любой момент. Она остается выбранной до тех пор, пока не выбрана другая. Следующая программа создает панель инструментов, содержащую три радиокнопки.
/*♦ tbradio.c **/
linclude <gnome.h>
3
linclude "tbxpm.h"
static void dummyCallback(GtkObject *,gpointer);
static void radioOneToolbar(GtkObject *,gpointer);
static void radioTwo,Toolbar(GtkObject *,gpointer);
static void radioThreeToolbar(GtkObject *,gpointer); 10
gint eventDelete(GtkWidget ^widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
15
GnomeUIInfo radioList[] = {
GNOMEUIINFO_RADIOITEM("Radio One",
"The first radio button",
radioOneToolbar,downXPM),
GNOMEUIINFO_RADIOITEM("Radio Two","
"The second radio button",
2radioTwoToolbar,attachXPM),
GNOMEUIINFO_RADIOITEM("Radio Three",
"The third radio button",
radioThreeToolbar,propertiesXPM),
GNOMEUIINFO_END
};
28
static GnomeUIInfo radioToolbar[] = {
{ GNOME_APP_UI_ITEM,"New",
"Create a new file",dummycallback,NULL,NULL,
GNOME_APP_PIXMAP_STOCK,GNOME_STOCK_PIXMAP_NEW,
0,0,NULL },
GNOMEUIINFO SEPARATOR,
GNOMEUIINFO~RADIOLIST(radioList),
GNOMEUIINFOSEPARATOR,
{ GNOME_APP_UI_IТЕМ,"Saveas",
"Save to a new file",dummycallback,NULL,NULL,
GNOME APP PIXMAP STOCK,GNOME STOCK PIXMAP SAVE AS,
0,0,NULL },
GNOMEUIINFO END
};
43
int main(int argc,char *argv[])
{
GtkWidget *app;
47
gnome_init("tbradio","1.0",argc,argv);
app = gnomeapp_new("tbradio","Toolbar Radio Buttons");
gtk_signal_connect(GTK_OBJECT(app),"deleteevent",
GTKSIGNALFUNC(eventDelete),NULL);
gtk signalconnect(GTKOBJECT(app),"destroy",
GTK_SIGNAL_FUNC(eventDestroy),NULL);
.
gnomeappcreatetoolbar(GNOMEAPP(app),radioToolbar);
gtk_widget_show_all(app);
57
gtk_main();
exit(0);
.60 }
static void dummyCallback(GtkObject *object,gpointer data)
{
gnomeokdialog("The dummy callback executed.");
}
static void radioOneToolbar(GtkObject *object,
gpointer data) {
if(gtk_toggle_button_get_active(
8GTK_TOGGLE_BUTTON(object)))
gnome_ok_dialog("The radio one button is on.");
70 else
71gnome_ok_dialog("The radio one button is off.");
72 }
73 static void radioTwoToolbar(GtkObject *object,
74gpointer data) {
75if(gtk_toggle_button_get_active(
7 6GTK_TOGGLE_BUTTON(object)))
77gnome_ok_dialog("The radio one button is on.");
78 else
79gnome_ok_dialog("The radio one button is off.");
80 }
81 static void radioThreeToolbar(GtkObject *object,
82gpointer data) {
83if(gtk_toggle_button_get_active(*
8 4GTKTOGGLEBUTTON(object)))
85gnome_ok_dialog("The radio one button is on.");
86 else
87gnome_ok_dialog("The radio one button is off.");
88 }
89 gint eventDelete(GtkWidget *widget,
90GdkEvent *event,gpointer data) {
91return(FALSE);
92 }
93 gint eventDestroy(GtkWidget *widget,
94GdkEvent *event,gpointer data) {
95gtk_main_quit();
96return(O);'
97 }
Панель инструментов определена в массиве radioToolbar в строках с 29 по 42. Набор радиокнопок включается в строке 35 с помощью макроса GNOMEUIINFO_RADIOLIST(). Радиокнопки, как и в меню, должны быть описаны как единый блок из-за того, что они взаимодействуют друг с другом. Всякий раз, когда выбрана одна из них, выбор других отменяется.
Отдельные кнопки описаны в массиве GnomeUIInfo в строках с 16 по 27. Три графические пиктограммы для кнопок (attachXPM, downXPM и propertiesXPM) хранятся в формате ХРМ в заголовочном файле tbxpm.h, включенном в строке 4. Каждая кнопка определена с помощью макроса GNOMEUIINFO_RADIOITEM(). Используется признак окончания иного типа, чем GNOME_APP_UI_ENDOF_INFO; все члены массива должны иметь тип GNOME_APP_UI__ITEM, который используется макросом GNOMEUIINFO_RADIOITEM().
Все необходимое для создания радиокнопок включено в описанные массивы, так что меню, как обычно, создается вызовом gnome_app__create_toolbar () в строке 55. Результирующая панель инструментов с выбранной первой кнопкой показана на рис. 8.25 и выбранной второй кнопкой — на рис. 8.26.
Рисунок 8.25.Первая кнопка, выбранная в наборе радиокнопок панели инструментовРисунок 8.25.Первая кнопка, выбранная в наборе радиокнопок панели инструментовРисунок 8.26.Вторая кнопка, выбранная в наборе радиокнопок панели инструментовРисунок 8.26.Вторая кнопка, выбранная в наборе радиокнопок панели инструментов
Рисунок 8.25.
Первая кнопка, выбранная в наборе радиокнопок панели инструментов
Рисунок 8.25.
Первая кнопка, выбранная в наборе радиокнопок панели инструментов
Рисунок 8.26.
Вторая кнопка, выбранная в наборе радиокнопок панели инструментов
Рисунок 8.26.
Вторая кнопка, выбранная в наборе радиокнопок панели инструментов
Каждая кнопка меню имеет свою собственную функцию обратного вызова (определены в строках 65, 73 и 81), а каждая функция обратного вызова имеет два возможных выбора. Всякий раз, когда сделан обратный вызов, нужно определить, была ли выбрана эта кнопка или выбор другой кнопки отменяет выбор этой. Когда кнопка выбрана, возвращаемое из gtk_toggle_button_get_active () значение, отличное от нуля, указывает, что она активна. Всякий раз, когда радиокнопка выбрана, доступны два обратных вызова. Вновь выбранная кнопка выдает один обратный вызов, а кнопка, которая ранее была выбрана (и становится отмененной), выдает другой обратный вызов. Если пользователь выбирает кнопку, которая уже является активной, имеется только один обратный вызов, и кнопка остается активной.
Переключатели в меню
Кнопка-переключатель меняет состояние всякий раз, когда для ее выбора используется мышь. Если переключатель включен, щелчок мыши выключает его; если он выключен, мышь включает его. Следующий пример демонстрирует, как вставить кнопки-переключатели в меню.
/** mtoggle.c **/
#include <gnome.h>-
3
static void dummyCallback(GtkObject *,gpointer);
static void toggleOne(GtkObject *,gpointer);
static void toggleTwo(GtkObject *,gpointer);
static void toggleThree(GtkObject *,gpointer);
8
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
‘
GnomeUIInfo toggleMenu[] = {
GNOMEUIINFO_MENU_NEW_GAME_ITEM(dummyCallback,NULL),
GNOMEUIINFOSEPARATOR,
GNOMEUIINFOJTOGGLEITEM("ToggleOne",
"The first toggle button",
toggleOne,NULL),'
GNOMEUIINFO TOGGLEITEM("ToggleTwo",
"The second toggle button",
toggleTwo,NULL),
GNOMEUIINFO_TOGGLEITEM("ToggleThree",
"The third toggle button",
toggleThrее,NULL),
GNOMEUIINFO_SEPARATOR,
GNOMEUIINFO_MENU_PAUSE_GAME_ITEM(dummyCallback,NULL),
GNOMEUIINFO_END
};
30
GnomeUIInfo mainMenu[] = {
GNOMEUIINFO_SUBTREE("Toggle Buttons",toggleMenu),
GNOMEUIINFO END
};
35
int main(int argc,char *argv[J)
{
GtkWidget *арр;
39
gnome_init("mtoggle","1.0",argc,argv);
арр = gnome_app_new("mtoggle","Menu Toggles");
gtk_window_set_default_size(GTK_WINDOW(app),200,100);
gtk_signal_connect(GTK_OBJECT(app),"delete_event",
GTK_SIGNAL_FUNC(eventDelete),NULL);
gtk_signal_connect(GTKOBJECT(app),"destroy",
GTK_SIGNAL_FUNC(eventDestroy),NULL);
47
gnome_app_create_menus(GNOME_APP(app),mainMenu);
49
gtk_widget_show_all(app);
gtk_main();
exit(0);
}
static void dummyCallback(GtkObject *object,gpointer data)
{
gnome_ok_dialog("The dummy callback executed.");
}
static void toggleOne(GtkObject *object,
gpointer data) {
if(GTK_CHECK_MENU_IТЕМ(object)->active)
gnomeokdialog("The toggle one button is on.");
else
gnomeokdialog("The toggle one button is off.");
}
static void toggleTwo(GtkObject ♦object,
gpointer data) {
if(GTK_CHECK_MENU_ITEM(object)->active)
gnome_ok_dialog("The toggle two button is on.");
else
gnome_ok_dialog("The toggle two button is off.");
}.
static void toggleThree(GtkObject *object,
gpointer data) {
if(GTKCHECKMENUIТЕМ(object)->active)
gnomeokdialog("The toggle three button is on.");
else
gnomeokdialog("The toggle three button is off.");
}
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data) {
return(FALSE);
}
gint eventDestroy(GtkWidget *widget,
GdkEvent ♦event,gpointer data) {
gtk_main_quit();
return(0);
}
Опускающаяся часть меню описана в виде массива в строках с 14 по 29. Каждый переключатель определен через макрос GNOMEUIINFO_TOGGLEITEM(). В этом примере переключатели сгруппированы вместе, но это вовсе не обязательно. Между ними отсутствует какое-либо взаимодействие, как в случае с радиокнопками.
Меню создано из набора массивов GnomeUIInfo путем обращения в строке 48 к gnome_app_create__menus (). Результирующее меню показано на рис. 8.27.
Toggle Buttons |yew game Ctl*Nr Toggle OneJ Toggle Two r Toggle Three ^ Pause gameРисунок 8.27.Переключатели в менюToggle Buttons |yew game Ctl*Nr Toggle OneJ Toggle Two r Toggle Three ^ Pause gameРисунок 8.27.Переключатели в менюНеважно, включается переключатель или выключается, при этом используется одна и та же функция обратного вызова. Например, функция обратного вызова для первого переключателя названа toggleOne() и определена в строке 58. Если кнопка включена, значение active, проверяемое в строке 60, отлично от нуля. Если кнопка выключена, значение active равно нулю.
Toggle Buttons |
yew game Ctl*N
r Toggle One
J Toggle Two r Toggle Three ^ Pause game
Рисунок 8.27.
Переключатели в меню
Toggle Buttons |
yew game Ctl*N
r Toggle One
J Toggle Two r Toggle Three ^ Pause game
Рисунок 8.27.
Переключатели в меню
Переключатели на панели инструментов
Кнопка-переключатель меняет свое состояние всякий раз, когда для ее выбора используется кнопка мыши. Если переключатель включен, щелчок мыши выключает его; если он выключен, мышь включает его. Следующий пример демонстрирует, как вы можете вставить переключатели на панель инструментов.
/♦* tbtoggle.c **/
tinclude <gnome.h>
3
Iinclude "tbxpm.h"
5
static void dummyCallback(GtkObject *,gpointer);
static void toggleOne(GtkObject ♦,gpointer);
static void toggleTwo(GtkObject *,gpointer);
static void toggleThree(GtkObject *,gpointer);
10
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
15
static GnomeUIInfo toggleToolbar[] = {
{ GNOME_APP_UI_ITEM,"New",
"Create a new file",dummyCallback,NULL,NULL,
GNOME_APP_PIXMAP_STOCK,GNOME_STOCK_PIXMAP_NEW,
0,0,NULL },
GNOMEUIINFOSEPARATOR,
GNOMEUIINFO_TOGGLEITEM("Toggle One",
"The first toggle button",
toggleOne,downXPM),
GNOMEUIINFO_TOGGLEITEM("ToggleTwo",
"The second toggle button",
7toggleTwo,attachXPM),
GNOMEUIINFO_TOGGLEITEM("ToggleThree",
"The third toggle button",
toggleThree,propertiesXPM),
GNOMEUIINFOSEPARATOR,
"32{ GNOME_APP_UI_IТЕМ,"Save as",
"Save to a new file",dummyCallback,NULL,NULL,
GNOME_APP_PIXMAP_STOCK,GNOMESTOCKPIXMAPSAVEAS,
0,0,NULL },
GNOMEUIINFOEND
};
38
int main(int argc,char *argv[])
{
GtkWidget *app;
42
gnome_init("tbtoggle","1.O",argc,argv);
арр = gnome_app_new("tbtoggle","Toolbar Toggles");
gtk_signal_connect(GTK_OBJECT(app),"deleteevent",
GTK_SIGNAL_FUNC(eventDelete),NULL);
gtk_signal_connect(GTK_OBJECT(app),"destroy",
GTK_SIGNAL_FUNC(eventDestroy),NULL);
49
gnome_app_create_toolbar (GNOME_APP (app), toggleToolbar);
gtk_widget_show_all(app);
52
gtk_main();
exit(O);
}
static void dummycallback(GtkObject *object,gpointer data)
{
gnome_ok_dialog("The dummy callback executed.");
}
static void toggleOne(GtkObject *object,
gpointer data) {
if(gtk_toggle_button_get_active(
GTK_TOGGLE_BUTTON(object)))
gnome_ok_dialog("The toggle one button is on.");
else
gnome_ok_dialog("The toggle one button is off.");
}
static void toggleTwo(Gtkdbject *object,
gpointer data) {
if(gtk_toggle_button_get_active(
GTK_TOGGLE_BUTTON(object)))
gnome_ok_dialog("The toggle two button is on.");
else
gnome_ok_dialog("The toggle two button is off.");
}
static void toggleThree(GtkObject *object,
gpointer data) {
if(gtk_toggle_button_get_active(
GTKTOGGLEBUTTON(object)))
gnomeokdialog("The toggle three button is on.");
else
gnome_ok_dialog("The toggle three button is off.");
}
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data) {
return(FALSE);
}
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data) {
gtk_main_quit();
return(O);
}
Панель инструментов описана в виде массива в строках с 16 по 37. Каждый переключатель описан с помощью макроса GNOMEUIINFO_TOGGLEITEM(), а каждому переключателю назначена графическая пиктограмма в виде данных в формате ХРМ, содержащихся в заголовочном файле tbxpm.h. Переключатели в этом примере сгруппированы вместе между парой разделителей, но в этом нет никакой необходимости, так как между ними отсутствует взаимодействие, как и между радиокнопками.
Панель инструментов создана из массива GnomeUIInfo с помощью обращения к gnome_app_create_toolbar() в строке 50. Результирующая панель инструментов показана на рис. 8.28.
Рисунок 8.28.Переключатели на панели инструментовРисунок 8.28.Переключатели на панели инструментов
Рисунок 8.28.
Переключатели на панели инструментов
Рисунок 8.28.
Переключатели на панели инструментов
Неважно, включается переключатель или выключается, используется та же самая функция обратного вызова. Например, функция обратного вызова для первого переключателя названа toggleOne () и описана в строке 60. Если переключатель включается, возвращаемое из gtk_toggle_button_get_active() значение отлично от нуля. Если кнопка выключается, возвращаемое значение равно нулю.
Выводы'
В интерфейсе GUI пользователь взаимодействует с приложениями, выбирая компоненты (пункты) с помощью мыши. Строка меню дает возможность пользователю находить и выбирать пункты по имени (с необязательной пиктограммой), а панель инструментов дает возможность пользователю находить элементы по пиктограммам (с необязательным текстом). В этой главе было показано, как создавать меню и панели инструментов:
■V- • Меню и панели инструментов определяются массивами структур. Члены массива определяют все, что необходимо, для меню или элемента панели инструментов, включая функции обратного вызова и графические изображения. Большинство членов этих структур может быть сгенерировано макросами, поставляемыми как часть GNOME.
GNOME включает набор предопределенных макросов и предлагаемых размещений меню, которые вы можете использовать для поддержки совместимых интерфейсов между приложениями GNOME.
Панель инструментов можно закреплять на любой из четырех сторон окна приложения. Меню можно закреплять сверху или у основания окна. И панель инструментов, и меню могут быть оторваны от окна приложения и помещены в любом месте экрана дисплея. Вы можете создать всплывающее меню, которое появляется всякий раз, когда окно приложения выбрано с помощью мыши.
Элементы меню и панелей инструментов могут быть разрешены и запрещены динамически.
О И в меню, и в панели инструментов могут быть вставлены переключатели и наборы радиокнопок.
Эта глава заканчивает первую часть книги, которая содержит все основные и конструктивные сведения, необходимые читателю для программирования законченного приложения. Вторая часть книги прежде всего предназначена для того, чтобы углубиться в подробности касательно различных аспектов программирования приложений, но в ней будут также представлены некоторые новые темы. Например, в следующей главе обсуждается GnomeCanvas — специальный вид виджета-контейнера, который может содержать некоторые типы отображаемых объектов. •
ЧАСТЬЧАСТЬШаг за шагомШаг за шагомГлава 9:Глава 10:Глава 11:Глава 12:Глава 13:Глава 14:Глава 15:Глава 16:Глава 17:Глава 18:Глава 19:Глава 9:Глава 10:Глава 11:Глава 12:Глава 13:Глава 14:Глава 15:Глава 16:Глава 17:Глава 18:Глава 19:-л ^* ^/ \^Л ^>„ <'- W-j^^<»^zxv«^ ^'<«^ V '^V^, ^^-^> Г^,, V^' < В этой части
ЧАСТЬ
ЧАСТЬ
Шаг за шагом
Шаг за шагом
Глава 9:
Глава 10:
Глава 11:
Глава 12:
Глава 13:
Глава 14:
Глава 15:
Глава 16:
Глава 17:
Глава 18:
Глава 19:
Глава 9:
Глава 10:
Глава 11:
Глава 12:
Глава 13:
Глава 14:
Глава 15:
Глава 16:
Глава 17:
Глава 18:
Глава 19:
Виджет GnomeCanvas
Область для рисования и графические примитивы
Цвет и графический контекст
Мышь и клавиатура
Шрифты
Приемы работы с виджетами
Апплеты
Перетащить, бросить, копировать, вырезать и вставить
Интерфейс для работы с несколькими документами (MKI)
Создание вашего собственного виджета
Конфигурация и интернационализация
ГЛАВА
а Виджет GnomeCanvas
В этой главе
Использование GnomeCanvas — виджета высокого уровня с низкоуровневыми ВОЗМОЖНОСТЯМИ'
Ч Сортировка получаемой от мыши информации для передачи ее соответствующему компоненту GnomeCanvas
Организация отображения компонентов различных типов и размеров
< Рисование полигонов и размещение их среди других компонентов GnomeCanvas сл Изменение формы изображаемых объектов с помощью аффинных преобразований
Виджет GnomeCanvas может быть использован для рисования фигур, отображения графики, размещения виджетов и т.д. Если вы хотите создать окно, меняющееся динамически, или получить полный контроль над положением и размерами виджетов в окне, то в этом вам может помочь GnomeCanvas.
GnomeCanvas — это окно с виджетом-контейнером, который называется группа (group). Задавая координаты и размер, можно добавлять в группу любое количество компонентов (items). Причем компонент может быть любым другим виджетом, например, кнопкой или даже другим контейнером, таким, как горизонтальный ящик, в котором в свою очередь содержатся виджеты. Группа может даже содержать другие группы. Кроме того, существует несколько компонентов, специально предназначенных для включения их в канву (canvas). В настоящей главе приведены примеры каждого из типов компонентов группы.
При работе с компонентами в канве изображения вам иногда потребуется иметь доступ к какому-либо полю внутри события GdkEvent, сгенерированного компонентом. События GdkEvent будут также встречаться и в последующих главах настоящей книги. В последней части этой главы приведен список всех типов событий GdkEvent, указаны их назначение и данные, включаемые в каждый тип.
Виджет GnomeCanvas
Виджет GnomeCanvas — это виджет высокого уровня, который может использоваться для отображения совокупности графических структур. В данном случае высокий уровень означает, что GnomeCanvas был разработан для использования его при создании интерактивных или динамических изображений. GnomeCanvas может отображать линии,
прямоугольники, окружности и текст.
Каждый графический компонент создается как независимый объект, который можно перемещать из одного места в другое, изменять размеры или независимо модифицировать его. Имеется набор функций аффинных преобразований, которые могут быть использованы для изменения формы, размеров и положения графических компонентов. Кроме того, можно сделать так, чтобы каждый компонент получал данные о событиях мыши и клавиатуры.
Компоненты виджета могут быть организованы в группы. При создании GnomeCanvas содержит только одну корневую группу, и все добавляемые в него компоненты будут добавляться в эту группу. Если ваше изображение становится сложным, а у вас уже есть из чего выбирать, будет удобнее организовать графические компоненты в виде отдельных групп. Все группы организуются в виде иерархического дерева. Члены группы — или отдельные компоненты, или другие группы — располагаются по принципу стека. То есть компонент, который находится в самом низу, рисуется первым, затем рисуется второй снизу компонент, и, наконец, самым последним рисуется самый верхний компонент. Таким образом, самый верхний компонент рисуется на вершине всех других компонентов изображения.
Приведенная ниже программа создает окно, содержащее GnomeCanvas, и использует его для рисования прямоугольника и двух отрезков линии. Окно, полученное при запуске программы, приведено на рис. 9.1.
/** canvas.с **/
Iinclude <gnome.h>
3
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data); •
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
8
Idefine WIDTH 400
«define HEIGHT 200
11
int main(int argc,char *argv[])
{
GtkWidget *app;
GtkWidget *canvas;
GnomeCanvasPoints *points;
GnomeCanvasGroup *rootGroup;
18
gnome_init("canvas","1.0",argc,argv);
app = gnome_app_new("canvas","Gnome Canvas");
gtk_signal_connect(GTK_OBJECT(app),"delete_event",
GTK^SIGNAL_FUNC(eventDelete),NULL);
gtk_signal_connect(GTKOBJECT(app),"destroy",
GTK_SIGNAL_FUNC(eventDestroy),NULL);
25
canvas = gnome_canvas_new();
gtk_widget_set_usize(canvas,WIDTH,HEIGHT);
gnome_canvas_set_scroll_region(GNOME_CANVAS(canvas),
0.0,0.0,WIDTH,HEIGHT);
rootGroup = gnome canvas root(GNOME_CANVAS(canvas));
gnomeappsetcontents(GNOME_APP(app),canvas);
32
33gnome_canvas_item_new(rootGroup,
34gnome_canvas_rect_get_type(),
35"xl",(double)10,
36"yl",(double)10,
37"х2",(double)(WIDTH - 10),
38"у2",(double)(HEIGHT - 10),
39"fill color","white",
40"outline_color","black",
41NULL);
42
43points = gnome_canvas_points_new(3);
44points->coords[0]=20;
45points->coords[1]=20;
46points->coords[2]=WIDTH -20;
47points->coords[3]=HEIGHT/2;
48points->coords[4]=20;
49points->coords[5]=HEIGHT-20;
50gnome_canvas_item_new(rootGroup,
51gnome_canvas_line_get_type(),
52"points",points,
53"fill_color","black",
54"width_pixels",2,
55NULL);
56gnomecanvaspointsfree(points);
57
58gtk_widget_show_all(app);
59gtk_main();
60exit(0);
61 }
62 gint eventDelete(GtkWidget *widget,
63GdkEvent *event,gpointer data) {
64return(FALSE);
65 }
66 gint eventDestroy(GtkWidget *widget,
67GdkEvent *event,gpointer data) {
68gtkmainquit();
69return(0);
70 }
Рисунок 9.1.
Использование GnomeCanvas для отображения форм и линий
При обращении к функции gnome_canvas_new( ) в строке 26 создается пустой неинициализированный объект GnomeCanvas. Вызовы функции gtk_widget__set_usize () в строке 27 задают высоту и ширину канвы (canvas) виджета. После определения полного размера необходимо задать прямоугольник внутри канвы, который и будет отображаемой областью. Размеры видимой области задаются с помощью вызова функции gnome_canvas_set_scroll__region() в строке 28. В простейших случаях, каким и является данный пример, размеры отображаемой области обычно устанавливаются на всю канву. Но в приложениях, в которых необходимо отображать
большие графические области, вы может использовать эту технологию позиционирования для задания как размеров, так и положения отображаемой области.
Начало системы координат находится в верхнем левом углу канвы, то есть координаты х и у верхнего левого угла равны нулю. Значение координаты у растет при перемещении вниз, а координаты х — при перемещении направо. Начало системы координат всегда рассчитывается на полную канву, а не на текущую прокручиваемую область. Например, если координата х верхнего левого угла просматриваемой области равна 10 и вы хотите отобразить компонент возле левого края отображаемой области, то необходимо указать координату х компонента равной 10, поскольку установка х в значение 0 отбросит вас за пределы отображаемой области. Однако, как будет показано далее в этой главе, можно преобразовать координаты каждого компонента в более удобный набор значений.
Обращение к функции gnome_canvas_root() в строке 30 возвращает корневой объект GnomeCanvasGroup. Объект GnomeCanvas предназначен для отображения графических компонентов, следовательно, он должен содержать координаты и всю другую информацию, необходимую для рисования компонентов в окне. С этой целью на канве в качестве контейнера этих компонентов применяется корневой объект GnomeCanvasGroup. Компоненты не добавляются непосредственно в канву, а включаются в корневую группу, содержащуюся в канве. Поскольку объект GnomeCanvasGroup может содержать другие объекты GnomeCanvasGroup, в иерархическом дереве можно создавать вложенные группы. Каждая группа может содержать множество графических компонентов таким образом, чтобы они прорисовывались в определенном порядке. Этот порядок определяет, какие компоненты рисуются позже и к тому же на вершине других, уже существующих. Таким образом, создавая подгруппы, можно манипулировать группой графических компонентов как единым объектом.
Вызов gnome_app_set_contents () в строке 31 добавляет канву, как если бы только виджет отображался в окне приложения. Если бы главное окно было бы окном GtkWindow, а не окном Gnome Арр, то, чтобы вставить канву, следовало бы обратиться к функции gtk_container_add().
Вызов функции gnome_canvas__item_new() в строке 33 используется для создания прямоугольника и включения его в корневую группу. Первый аргумент функции — группа, второй аргумент задает тип создаваемого объекта. Остальные аргументы используются для задания информации по конфигурации. Обратите внимание, что аргументы в строках с 35 по 40 парные. Первый элемент в паре — наименование параметра, а второй — значение, ассоциирующееся с наименованием. В нашем случае имена ”xl", ”у1”, "х2” и "у2” задают координаты четырех углов прямоугольника. Параметр ”f ill_color” указывает цвет для заполнения прямоугольника. Параметр ”outline_color” определяет цвет обрамления (рамки), окружающего прямоугольник. И, наконец, последний аргумент в строке 41 — это NULL, благодаря которому вызываемая функция определяет конец массива аргументов переменной длины.
Вызов функции gnome_canvas_item_new() в строке 50 создает и добавляет линию, состоящую из двух сегментов (отрезков). Первые два аргумента указывают группу и тип создаваемых объектов. Кроме того, имеются еще три аргумента. Параметр "width_pixels” имеет значение 2 в качестве аргумента, задающего толщину линии, "f ill_color" задает "black” (черный) как цвет линии. Параметр ’’points” передает адрес объекта GnomeCanvasPoints, содержащего массив координат х и у точек. Каждая точка массива определяет вершину сегмента линии.
Объект GnomeCanvasPoints создается в строке 43 при помощи обращения к функции gnome_canvas_points_new(). Общее количество точек (в нашем примере их 3) передается функции для создания массива указанного размера. Имеется только один массив, а каждая точка требует два значения, поэтому четные элементы массива coords содержат значения х, а нечетные — значения у. Если вам необходимо пройти цикл по всем точкам, можно сделать следующее:
points = gnome_canvas_points_new(19);
for(i=0; i<19; i++) {
/♦* calculate x and у **/
points->coords[i*2] = x;
points->coords[(i*2)+l] = y;
}
Так как список точек занимает память и после построения графического объекта больше не используется, память освобождается путем вызова gnome_canvas_points_fгее() в строке 56.
Мышь, событие и порядок в стеке
При добавлении каждого нового компонента в группу он добавляется вверху списка. Это означает, что при прорисовке группы в окне, последний добавленный компонент рисуется последним и отображается поверх всех других компонентов данной группы. Порядок в стеке можно изменить в любое время. Приведенная ниже программа отображает три перекрывающихся графических компонента, как показано на рис. 9.2, и присоединяет к ним функцию обратного вызова, которая при попадании указателя мыши во внутрь компонента перемещает этот компонент на вершину стека.
/*♦ canvasorder.с ♦♦/
Iinclude <gnome.h>
3
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,'
GdkEvent *event,gpointer data);
static gint itemEvent(GnomeCanvasItem *item,
GdkEvent *event,gpointer data);
10
Idefine HORIZ 100
Idefine VERT 60
Idefine WIDTH (HORIZ ♦ 6)
Idefine HEIGHT (VERT ♦ 6)
15
int main(int argc,char *argv[J)
{
GtkWidget *app;
GtkWidget ♦canvas;
GnomeCanvasGroup *rootGroup;
GnomeCanvasItem *item;
22
gnome_init("canvasorder","1.0",argc,argv);
app = gnome_app_new("canvasorder",
"Gnome Canvas Order");.
gtk_signal_connect(GTK OBJECT(app),"delete_event",
GTK_SIGNAL_FUNC(eventDelete),NULL )7
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
gtk_signal_connect(GTK_OBJECT(app),"destroy", GTK_SIGNAL_FUNC(eventDestroy),NULL);
canvas = gnome_canvas_new();
gtk_widget_set_usize(canvas,WIDTH,HEIGHT);
gnome_canvas_set_scroll_region(GNOME_CANVAS(canvas), 0.0,0.0,WIDTH,HEIGHT);
rootGroup = gnome_canvas__root(GNOME^CANVAS(canvas)); gnome_app_set_contents(GNOME_APP(app),canvas);
item = gnome_canvas_item_new(rootGroup, gnome_canvas_rect_get_type(), "xl",(double)(HORIZ * 1), "yl",(double)(VERT * 1), "x2",(double)(HORIZ * 3), "y2",(double)(VERT * 3), "fill_color","white", "outline color","black", NULL);
gtk_signal_connect(GTK_OBJECT(item),"event", (GtkSignalFunc)itemEvent,NULL);
item = gnome_canvas_item_new(rootGroup, gnome_canvas ellipse__get_type(), "xl",(double!(HORIZ * 2), "yl",(double)(VERT *2), "x2",(double)(HORIZ * 4), "y2",(double)(VERT * 4), "fill_color","blue", "outline_color","black", NULL);
gtk_signal_connect(GTK_OBJECT(item),"event", (GtkSignalFunc)itemEvent,NULL);
item = gnome_canvas_item_new(rootGroup, gnome_canvas_rect_get_type(), "xl",(double)(HORIZ * 3), "yl",(double)(VERT * 3), "x2",(double)(HORIZ * 5), "y2",(double)(VERT ♦ 5), "fill_color","black", "outlinecolor","white", NULL);
gtk_signal_connect(GTK_OBJECT(item),"event", (GtkSignalFunc)itemEvent,NULL);
gtk_widget_show_all(app); gtk_main();
exit(0);
}
static gint itemEvent(GnomeCanvasItem *item, GdkEvent *event,gpointer data) { if(event->type == GDK_ENTER_NOTIFY) gnome_canvas_item_raise_to_top(item); return(0);
838485838485}
83
84
85
83
84
85
gint eventDelete(GtkWidget *widget, GdkEvent *event,gpointer data) {
8б return(FALSE);
87 }
88 gint eventDestroy(GtkWidget *widget,
89GdkEvent *event,gpointer data) {
90gtkmainquit();
91return(O);
92 }
Рисунок 9.2.Три перекрывающихся на канве компонента показывают порядок их расположения в стекеРисунок 9.2.Три перекрывающихся на канве компонента показывают порядок их расположения в стеке
Рисунок 9.2.
Три перекрывающихся на канве компонента показывают порядок их расположения в стеке
Рисунок 9.2.
Три перекрывающихся на канве компонента показывают порядок их расположения в стеке
Константы, объявленные в строках с 11 по 14, используются для задания размещения компонентов канвы. Значения HORIZ и VERT определяют положение и размеры каждой фигуры, a WIDTH и HEIGHT — размеры канвы.
Канва создается и конфигурируется в строках с 31 по 34. В строке 35 путем вызова gnome_canvas_item_new( ) выбирается корневая группа. С помощью вызова gnome_app_set_contents () в строке 36 устанавливается канва как содержимое окна приложения GNOME.
Первая из трех фигур — прямоугольник, создаваемый обращением к функции gnome_canvas_item_new() в строках с 38 по 46. Первый аргумент этой функции задает группу, в которую будет включен компонент, а второй — определяет тип объекта. Следующие четыре аргумента задают координаты четырех вершин прямоугольника, а еще два — цвет окантовки и цвет заливки. Обращение к функции gtk_signal_connect() в строке 47 указывает, что функция обратного вызова itemEvent () должна вызываться для каждого события, связанного с данным компонентом.
Еще два компонента — эллипс и другой прямоугольник— создаются в строках с 50 по 72. Этим компонентам назначена та же функция обратного вызова, что и для первого компонента. Окно с компонентами показано на рис. 9.2.
Функция обратного вызова itemEvent () в строке 78 вызывается при возникновении любого события, регистрируемого для компонента. Как видно из списка параметров, первый параметр — компонент, вызвавший обратный вызов, второй — само событие. Как показано в табл. 9.2 далее в этой главе, в структуре GdkEvent могут содержаться несколько типов событий. Функция обратного вызова в строках 80 и 81 — ответ на событие GDK_ENTER_NOTIFY, возникающее, когда указатель мыши перемещается снаружи во внутрь компонента, передвигает компонент на вершину стека с помощью функции gnome_canvas_item__raise__to_top().
Существует семейство функций, с помощью которых можно размещать компоненты в стеке. Функция, которая выполняет действие, обратное действию функции, используемой в этом примере, перемещает компонент вниз стека:
gnome_canvas_item_lower_to_bottom(item);
Вы можете изменять взаимное положение компонентов в стеке, перемещая компонент выше или ниже на определенное количество позиций. Например, если компонент находится в стеке на позиции 7, а вы хотите переместить его на позицию 5, то это можно сделать следующим образом:
gnome_canvas_item_raise(item,2);
Компоненты могут быть перемещены и вниз стека. Например, следующая функция перемещает компонент с позиции 3 вниз на позицию 8:
gnome_canvas_item_lower(item,5);
События, передаваемые компонентам виджета Canvas
Виджет GnomeCanvas представляет собой окно, которое используется для отображения различных присоединенных к нему компонентов. При возникновении события мыши внутри границ какого-либо компонента событие тут же передается именно этому компоненту. Хотя передаются не все возникающие события, а только те, которые связаны с положением и перемещением мыши.
ПРИМЕЧАНИЕ
В конце этой главы приведено более подробное описание различных видов событий GdkEvent. Компоненты окна виджета GnomeCanvas получают только события мыши, все остальные события обрабатываются либо GnomeCanvas, либо его родительским окном.
Ниже приведена несколько измененная программа предыдущего примера, которая выводит информацию по событиям одного из отображаемых компонентов.
/** canvascall.с **/
linclude <gnome.h>
3
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint ^ventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
static gint itemEvent(GnomeCanvasItem *item,
GdkEvent *event,gpointer data);
static gint rectangleEvent(GnomeCanvasItem *item,
GdkEvent *event,gpointer data);
void describeEventButton(gchar *name,GdkEvent *event);
void describeEventMotion(gchar *name,GdkEvent *event);
void describeEventCrossing(gchar *name,GdkEvent *event);
.
Idefine HORIZ 100
Idefine VERT 60
Idefine WIDTH (HORIZ * 6)
Idefine HEIGHT (VERT * 6)
20
21 int main(int argc,char *argv[])
22 {
2324252627 282930 3132 3334353637383940414243444546474849505152535455 565758596061626364656667686970717273747576777879802324252627 282930 3132 3334353637383940414243444546474849505152535455 56575859606162636465666768697071727374757677787980
23
24
25
26
27 28
29
30 31
32 33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55 56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
23
24
25
26
27 28
29
30 31
32 33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55 56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
GtkWidget *арр;
GtkWidget *canvas;
GnomeCanvasGroup *rootGroup; GnomeCanvasItem *item;
gnome_init("canvascall","1.0",argc,argv); app = gnome_app_new("canvascall", "Gnome Canvas Order");
gtk_signal_connect(GTK_OBJECT(app),"delete_event", GTK_SIGNAL_FUNC(eventDelete),NULL);
gtk_signal_connect(GTK_OBJECT(app),"destroy", GTK_SIGNAL_FUNC(eventDestroy),NULL);
canvas = gnome_canvas_new();
gtk_widget_set_usize(canvas,WIDTH,HEIGHT);
gnome_canvas_set_scroll_region(GNOMECANVAS(canvas), 0.0,0.0,WIDTH,HEIGHT);
rootGroup = gnome_canvas_root(GNOME_CANVAS(canvas)); gnome_app_set_contents(GNOME_APP(app),canvas);
item = gnome_canvas_item_new(rootGroup, gnome_canvas_ellipse_get_type(), "xl",(double)(HORIZ * 1), "yl",(double)(VERT ♦ 1), "x2",(double)(HORIZ * 3), "y2",(double)(VERT * 3), "fill_color","white", "outline_color","black", NULL);
gtk_signal_connect(GTK_OBJECT(item),"event", (GtkSignalFunc)itemEvent,NULL);
item = gnome_canvas_item_new(rootGroup, gnome_canvas_rectget_type(), "xl",(double)(HORIZ ♦ 2), "yl",(double)(VERT * 2), "x2",(double)(HORIZ *4), "y2",(double)(VERT * 4), "fill_color","blue", "outline_color","black", NULL);
gtk_signal_connect(GTK_OBJECT(item),"event", (GtkSignalFunc)itemEvent,NULL);
gtksignalconnect(GTK_OBJECT(item),"event", (GtkSignalFunc)rectangleEvent,NULL);
item = gnomecanvas_item_new(rootGroup, gnome_canvas_ellipse_get_type(), "xl",(double)(HORIZ * 3), "yl",(double)(VERT * 3), "x2",(double)(HORIZ ♦ 5), "y2",(double)(VERT * 5), "fill_color","black", "outlinecolor","white", NULL);
gtk_signal_connect(GTK_OBJECT(item),"event", (GtkSignalFunc)itemEvent,NULL);
8182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713881828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
gtk_widget_show_all(app);
gtk_main();•
exit(0);
}
static gint itemEvent(GnomeCanvasItem *item, GdkEvent *event,gpointer data) {
if(event->type == GDK_BUTTON_PRESS) ’ gnome_canvas_item_raise_to_top(item);
return(O);
}
static gint rectangleEvent(GnomeCanvasItem *item, GdkEvent *event,gpointer data) {
switch(event->any.type) {
case GDK_ENTER_NOTIFY:
describeEventCrossing("GDK_ENTER_NOTIFYM,event); break;
case GDKJLEAVE_NOTIFY: describeEventCrossing("GDK_LEAVE_NOTIFY",event); break;
case GDK_MOTION_NOTIFY:
describeEventMotion("GDKMOTIONNOTIFY",event); break;
case GDK_BUTTON_PRESS:
describeEventButton("GDK_BUTTON_PRESS",event); break;
case GDK_2BUTTON_PRESS:
describeEventButton("GDK_2BUTTON_PRESS",event); break;
case GDK_3BUTTON_PRESS: describeEventButton("GDK_3BUTTON_PRESS",event); break;
case GDKBUTTONRELEASE:
describeEventButton("GDKBUTTONRELEASE",event); ■break;
default: g_print( "An unexpected event\n" ); break;
}
g_print("GdkEvent t %d",event->type);
if(event->any.send_event) g_print(" (from another client,");
else g_print(" (from server,");
if(event->any.window 1= NULL) { if(data == NULL) g_print(" with no data)\n"); else g_print(" with data %p)\n",data);
}
return(0);
}
void describeEventButton(gchar *name,GdkEvent *event)
g_print("%s — GdkEventButton\n",name); g_print(" x=%g y=%g xtilt=%g ytilt=%g" " pressure=%g button=%d\n", event->button.x,event->button.у, event->button.xtilt,event->button.ytilt,
139 140 141 142143144145 146 147 148149 150151 152153 154155 156157 158159160161 162163164 165166167168169170 171172173174 175176177 178179180181 182 183139 140 141 142143144145 146 147 148149 150151 152153 154155 156157 158159160161 162163164 165166167168169170 171172173174 175176177 178179180181 182 183event->button.pressure,event->button.button); g_print(M x_root=%g y_root=%g time=%u" " state=0x%08X\n", event->button.x_root,event->button.y_root, event->button.time,event->button.state);
139 140 141 142
143
144
145 146 147 148
149 150
151 152
153 154
155 156
157 158
159
160
161 162
163
164 165
166
167
168
169
170 171
172
173
174 175
176
177 178
179
180
181 182 183
139 140 141 142
143
144
145 146 147 148
149 150
151 152
153 154
155 156
157 158
159
160
161 162
163
164 165
166
167
168
169
170 171
172
173
174 175
176
177 178
179
180
181 182 183
}
void describeEventMotion(gchar *name,GdkEvent *event) {
g_print("%s — GdkEventMotionXn",name);
g_print(" x=%g y=%g xtilt=%g ytilt=%g" " pressure=%g is_hint=%s\n", event->motion.x,event->motion.у, event->motion.xtilt,event->motion.ytilt, event->motion.pressure, event->motion.is_hint ? "TRUE" : "FALSE");
g_print(" x_root=%g y_root=%g time=%u" " state=0x%08X\n", event->motion.x_root,event->motion.yroot, event->motion.time,event->motion.state);
}
void describeEventCrossing(gchar *name,GdkEvent *event)
gchar *mode = event->crossing.mode == GDK_CROSSING_NORMAL ? "Normal" : event->crossing.mode == GDK_CROSSING_GRAB ? "Grab" : "Ungrab";
g_print("%s — GdkEventCrossingXn",name);
g_print(" x=%g y=%g x_root=%g y_root=%g focus=%s\n", event~>crossing.x,event->crossing.у, event->crossing.xroot,event->crossing.yroot, event->crossing.focus ? "TRUE" : "FALSE");
g_print(" mode=%s time=%u detail=%d state=0x%08X\n", mode,event->crossing.time, event->crossing.detail,event->crossing.state);
}
gint eventDelete(GtkWidget *widget, GdkEvent *event,gpointer data) { return(FALSE);
}
gint eventDestroy(GtkWidget *widget, GdkEvent *event,gpointer data) { gtkmainquit();
return(0);
}
В строках с 36 по 41 создается и инициализируется GnomeCanvas, поступает адрес корневой группы, а к окну приложения присоединяется канва.
В строках с 43 по 79 создаются три компонента, которые добавляются в корневую группу. В строках 52, 64 и 78 всем трем компонентам назначается функция обратного вызова itemEvent(). Кроме того, с помощью вызова gtk_signal_connect () в строке 66 второй компонент — прямоугольник, показанный на рис. 9.3, также связывается с функцией обратного вызова rectangleEvent (). Компонент можно связать с любым количеством функций обратного вызова, которые будут вызываться при возникновении каждого события. В приведенной программе удобно использовать одну функцию обратного вызова, отвечающую на щелчки мыши, и перемещать выбранный компонент.
Функция обратного вызова itemEvent( ) из строки 85 вызывается при каждом щелчке мышью на любом из компонентов окна. Обращение к gnome_canvas__item_raise_to__top () в строке 88 перемещает указанный компонент на передний план перед всеми компонентами в канве окна.
Функция обратного вызова rectangleEvent () вызывается только при возникновении неких событий в прямоугольнике. Функция не производит никаких действий, связанных с отображением компонента. Вместо этого она выдает информацию, содержащуюся в событии. Существуют различные виды событий со своими специфическими данными, но все события поступают как GdkEvent (общий тип для всех событий). Первое поле в структуре данных для всех видов событий — поле типа, по которому можно определить действительный формат данных. В строке 104 начинается оператор switch/case, который определяет тип события и вызывает функцию, выводящую данные для этого типа. Существует гораздо больше типов событий, чем их форматов. Например, все щелчки кнопкой мыши независимо от того, одинарные, двойные или более, имеют один и тот же формат данных.
Существует функция обратного вызова, которая выводит данные, прилагаемые к каждому из семи типов событий мыши. Функция describeEventButton() в строке 132 вызывается со структурой GdkEvent But ton при каждом нажатии кнопки мыши. Функция describeEventMotion() в строке 145 вызывается со структурой GdkEventMotion при передвижении указателя мыши внутри компонента. Функция describeEventCrossing ( ) в строке 159 вызывается со структурой GdkEventCrossing при пересечении указателем мыши граничной кромки компонента.
Ниже приведен пример вывода программы, получаемого при вхождении указателя мыши в компонент, нажатии на первую кнопку мыши, перемещении мыши внутри компонента, освобождении кнопки и перемещении указателя мыши за пределы компонента. В выходном листинге программы будет присутствовать большое количество событий GdkEventMotion, поскольку каждое движение мыши генерирует такое событие, хотя в приведенном выводе удален ряд событий.
GDK_ENTER_NOTIFY -- GdkEventCrossing
х=345 у=120 x_root=445 y_root=248 focus=FALSE
mode=Normal time=4027445079 detail=0 state=0x00000000
GdkEvent 110 (from server, with no data)
GDKMOTIONNOTIFY — GdkEventMotion
х=345 у=120 xtilt=0 ytilt=0 pressure=0.5 is_hint=FALSE x_root=445 y_root=248 time=4027449171 state=0x00000000 GdkEvent #3 (from server, with no data)
GDK_MOTION_NOTIFY — GdkEventMotion
x=345 y=121 xtilt=0 ytilt=0 pressure=0.5 is_hint=FALSE x_root=445 y_root=249 time=4027449192 state=0x00000000 GdkEvent #3 (from server, with no data)
GDK_MOTION_NOTIFY — GdkEventMotion
x=345 y=135 xtilt=0 ytilt=0 pressure=0.5 is_hint=FALSE x_root=445 y_root=263 time=4027449457 state=0x00000000 GdkEvent 13 (from server, with no data)
GDKBUTTONPRESS —- GdkEventButton
x=345 y=135 xtilt=0 ytilt=0 pressure=0.5 button=l
x_root=445 y_root=263 time=4027449967 state=0x00000000
GdkEvent 14 (from server, with no data)
GDK_MOTION_NOTIFY — GdkEventMotion
x=346 y=135 xtilt=0 ytilt=0 pressure=0.5 is_hint=FALSE x_root=446 y_root=263 time=4027450007 state=0x00000100 GdkEvent 13 (from server, with no data)
GDK_MOTION_NOTIFY — GdkEventMotion
x=346 y=136 xtilt=0 ytilt=0 pressure=0.5 is_hint=FALSE x_root=446 y_root=264 time=4027450038 state=0x00000100 GdkEvent 13 (from server, with no data)
GDK_MOTION_NOTIFY — GdkEventMotion
x=363 y=149 xtilt=0 ytilt=0 pressure=0.5 is_hint=FALSE x_root=463 y_root=277 time=4027451089 state=0x00000100 GdkEvent #3 (from server, with no data)
GDK_MOTION_NOTIFY — GdkEventMotion
x=364 y=149 xtilt=0 ytilt=0 pressure=0.5 is__hint=FALSE x_root=464 y_root=277 time=4027451282 state=0x00000100 GdkEvent #3 (from server, with no data)
GDKBUTTONRELEASE — GdkEventButton
x=364 y=149 xtilt=0 ytilt=0 pressure=0.5 button=l x_root=464 y_root=277 time=4027451619 state=0x00000100 GdkEvent 17 (from server, with no data)
GDKMOTIONNOTIFY — GdkEventMotion
x=364 y=150 xtilt=0 ytilt=0 pressure-0•5 is_hint=FALSE x_root=464 y_root=278 time=4027451925 state=0x00000000 GdkEvent 13 (from server, with no data)
GDK_MOTION_NOTIFY — GdkEventMotion
x=365 y=150 xtilt=0 ytilt=0 pressure=0.5 is_hint=FALSE x_root=465 y_root=278 time=4027452159 state=0x00000000 GdkEvent 13 (from server, with no data)
GDK_MOTION_NOTIFY — GdkEventMotion
x=396 y=152 xtilt=0 ytilt=0 pressure=0.5 is_hint=FALSE x_root=496 y_root=280 time=4027452333 state=0x00000000 GdkEvent #3 (from server, with no data)
GDK_MOTION_NOTIFY — GdkEventMotion
x=398 y=151 xtilt=0 ytilt=0 pressure=0.5 is_hint=FALSE x_root=498 y_root=279 time=4027452343 state=0x00000000 GdkEvent 13 (from server, with no data)
GDK_LEAVE_NOTIFY — GdkEventCrossing
x=401 y=151 x_root=501 y_root=279 focus=FALSE mode-Normal time=0 detail=0 state=0x00000000
GdkEvent 111 (from server, with no data)
12345 б78910111213141516171819202122232425262728293031323334353637383940414243444546474812345 б789101112131415161718192021222324252627282930313233343536373839404142434445464748
1
2
3
4
5 б
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
1
2
3
4
5 б
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
Перемещение компонентов внутри виджета Canvas
Вы можете переместить компоненты в окне GnomeCanvas из одного положения в другое, задавая расстояние по осям х и у, на которое необходимо переместить компоненты. Приведенная ниже программа аналогична двум предыдущем за тем лишь исключением, что функция обратного вызова обнаруживает, остается ли нажатой кнопка при движении мыши, и, если да, то перемещает компонент на новое место.
/** canvasdrag.с **/ Iinclude <gnome.h>
gint eventDelete(GtkWidget *widget, GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget, GdkEvent *event,gpointer data);
static gint dragEvent(GnomeCanvasItem *item, GdkEvent *event,gpointer data);
Idefine HORIZ 100
♦define VERT 60
♦define WIDTH (HORIZ * 6)
♦define HEIGHT (VERT * 6)
int main(int argc,char *argv[]) <.
GtkWidget *app;
GtkWidget *canvas; GnomeCanvasGroup *rootGroup; GnomeCanvasItern *item;
gnome_init("canvasdrag","1.0",argc,argv); app = gnome_app__new( "canvasdrag", "Gnome Canvas Dragging");
gtksignalconnect(GTK_OBJECT(app),"deleteevent", GTKSIGNALFUNC(eventDelete),NULL);
gtk_signal_connect(GTK_OBJECT(app),"destroy", GTK_SIGNAL_FUNC(eventDestroy),NULL);
canvas = gnome_canvas__new(); gtk_widget_set_usize(canvas,WIDTH,HEIGHT); gnome_canvas_set_scroll_region(GNOME_CANVAS(canvas), 0.0,0.0,WIDTH,HEIGHT);
rootGroup = gnomecanvasroot(GNOMECANVAS(canvas)); gnome_app_set_contents(GNOME_APP(app),canvas);
item = gnome_canvas_item_new(rootGroup, . gnome_canvas_rect_get_type(), "xl",(double)(HORIZ * 1), "yl",(double)(VERT * 1), "x2",(double)(HORIZ * 3), "y2",(double)(VERT ♦ 3), "fill_color","white", "outline-Color","black", NULL);
gtksignalconnect(GTK_OBJECT(item),"event", (GtkSignalFunc)dragEvent,NULL);
495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106item = gnome_canvas_item_new(rootGroup, gnome_canvas_ellipse_get_type(), "xl",(double)(HORIZ * 2), - "yl",(double)(VERT * 2), "x2",(double)(HORIZ *4), "y2",(double)(VERT ♦ 4), "fill_color","blue", "outline_color","black", NULL);
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
gtk_signal_connect(GTK_OBJECT(item),"event", (GtkSignalFunc)dragEvent,NULL);
item = gnome_canvas_item_new(rootGroup, gnome canvas_rect_get_type(), "xl",7double)(HORIZ * 3), "yl",(double)(VERT * 3), "x2",(double)(HORIZ *5), "y2",(double)(VERT *5), "fill_color","black", "outline_color","white", NULL);
gtk_signal_connect(GTK_OBJECT(item),"event", (GtkSignalFunc)dragEvent,NULL);
gtk_widget_show_all(app);
gtk_main();
exit(0);
}
static gint dragEvent(GnomeCanvasItern *item, GdkEvent *event,gpointer data) { static gint x;
static gint y;s
gint newx;
gint new_y;
switch(event->type) { case GDK_MOTION_NOTIFY: if(event->button.state & 0x00000400) { newx = event->button.x; new_y = event->button.y; gnome_canvas_item_move(item, (double)(newx - x), (double)(newy - y));
x = newx; у = newy;
} break; case GDKBUTTONPRESS: if(event->button.button == 1) gnome_canvas_item_raise_to_top(item); x = event->button.x;
у = event->button.y; break; default:
break;
}
return(0);
107 }
108 gint eventDelete(GtkWidget *widget,
109GdkEvent *event,gpointer data) {
110 return(FALSE);
Hl }
112 gint eventDestroy(GtkWidget *widget,
113GdkEvent *event,gpointer data) {
114gtk_main_quit();
115return(O);
116 }
Как показано на рис. 9.4, на канве находятся три компонента. Каждый из них может быть легко перемещен из одного положения в другое, поскольку каждый из компонентов использует функцию обратного вызова dragEvent(), начинающуюся со строки 78.
Рисунок 9.4.Правая кнопка мыши перемещает эти компонентыРисунок 9.4.Правая кнопка мыши перемещает эти компоненты
Рисунок 9.4.
Правая кнопка мыши перемещает эти компоненты
Рисунок 9.4.
Правая кнопка мыши перемещает эти компоненты
Переменные х и у объявлены в строках 80 и 81 как static, то есть они сохраняют :вои значения от одного обратного вызова до другого. Эти переменные необходимы, по- жольку перемещение компонента производится по величине смещения, а не по абсолют- 1ым координатам положения компонента, и поэтому единственным способом определе- <ия расстояния является определение разности между координатами старого и нового по- южения компонента. Это очень удобно при использовании указателя мыши для переме- дения компонента, поскольку для вычисления расстояния требуется всего лишь отслеживать положение указателя мыши, а актуальное положение перемещаемого компонента не имеет никакого значения.
Оператор case в строке 86 выполняется при каждом перемещении указателя мыши, но никаких действий не производится, если только при его перемещении не нажата правая кнопка мыши. Далее в этой главе в табл. 9.2 вместе с описанием GdkEvent приведены биты, которые будут проверяться для каждой кнопки мыши. Само перемещение компонента производится путем вызова gnome_canvas_item_move () и задания разности между предшествующим и текущим положениями мыши. После перемещения ранее сохраненные значения х и у обновляются, отражая новое положение, так что можно будет вычислять расстояние для следующего перемещения.
Оператор case в строке 97 выполняется при каждом нажатии кнопки мыши. Если нажата левая кнопка (номер 1), то компонент перемещается к вершине стека. Кроме того, устанавливаются значения х и у на случай, если это начало операции перемещения.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484912345678910111213141516171819202122232425262728293031323334353637383940414243444546474849
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
Изображения на канве
Изображение может отображаться в GnomeCanvas путем преобразования его в Gdklmliblmage и добавления в канву в качестве компонента. В следующем примере используются изображения в формате ХРМ, которые были созданы с помощью методов, описанных в главе 7.
/** canvasimage.с ♦*/
Iinclude <gnome.h>
Iinclude "logo.xpm" Iinclude "foot.xpm"
gint eventDelete(GtkWidget *widget, GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget, GdkEvent *event,gpointer data);
static gint dragEvent(GnomeCanvasItem *item, GdkEvent *event,gpointer data);
int main(int argc,char *argv[])
GtkWidget *app;
GtkWidget *canvas;
GnomeCanvasGroup *rootGroup;
GnomeCanvasItem *item; Gdklmliblmage *image;
gnome__init("canvasimage","1.0",argc,argv); app = gnome_app_new("canvasimage", "Gnome Canvas Image");
gtksignalconnect(GTKOBJECT(app),"deleteevent", GTKSIGNALFUNC(eventDelete),NULL);
gtk_signal_connect(GTK_OBJECT(app),"destroy", GTK_SIGNAL_FUNC(eventDestroy),NULL);
canvas « gnome_canvas_new();
gtk_widget_set_usize(canvas,600,360);
gnome_canvas_set_scroll_region(GNOME_CANVAS(canvas), 0.0,0.0,600,360);
rootGroup = gnomecanvasroot(GNOME_CANVAS(canvas)); gnome_app_set_contents(GNOMEAPP(app),canvas);
image = gdk_imlib_create_image_from_xpm_data(logo); item = gnome_canvas_item_new(rootGroup, gnome_canvas_image_get_type(), "image",image, "x",(double)100, "y",(double)100, "width",(double)257, "height",(double)303, "anchor",GTK_ANCHOR_CENTER, NULL);
gtksignalconnect(GTK_OBJECT(item),"event", (GtkSignalFunc)dragEvent,NULL);
gdk_imlib_destroy_image(image);
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
image = gdk_imlib_create_image_from_xpm_data(foot); item = gnome_canvas_item_new(rootGroup, gnome_canvas_image_get_type(), "image",image, "x",(double)300, "y",(double)100, "width",(double)172, "height",(double)51, "anchor",GTK_ANCHOR_CENTER, NULL);
gtk_signal_connect(GTK_OBJECT(item),"event", (GtkSignalFunc)dragEvent,NULL);
item = gnome_canvas_item_new(rootGroup, gnome_canvas_image_get_type(), "image",image, "x",(double)200, "y",(double)150, "width",(double)200,1
"height",(double)2 0 0, "anchor",GTK_ANCHOR_CENTER, NULL);
gtk_signal_connect(GTK_OBJECT(item),"event", (GtkSignalFunc)dragEvent,NULL);
gdk_imlib_destroy_image(image);
gtk_widget_show_all(app);
gtk_main();
exit(0);
}
static gint dragEvent(GnomeCanvasItem *item, GdkEvent *event,gpointer data) {
static gint x;
static gint y; gint new_x; gint new_y;
switch(event->type) { case GDKJfpTIONNOTIFY: if(event->button.state & 0x00000100) { newx = event->button.x; newy = event->button.y; gnome_canvas_item_move(item, (double)(newx - x), (double)(newy - y));
x = newx; у * new_y;
} break; case GDKBUTTONPRESS: if(event->button.button == 1) gnome_canvas_item_raise_to_top(item); x = event->button.x; у = event->button.y; break;
default:
107107break
107
107
108}
109return(O);
110 }
111 gint eventDelete(GtkWidget *widget,
112GdkEvent *event,gpointer data) {
113return(FALSE);
114 }
115 gint eventDestroy(GtkWidget *widget,
116GdkEvent *event,gpointer data) {
117gtk_main_quit();
118return(O);
119 }
В строках 4 и 5 в программу включаются файлы, содержащие определения двух изображений. Как описано в главе 7, чтобы получить возможность вставлять рисунки непосредственно в программу, вам необходимо преобразовать их в формат ХРМ из другого формата.
При помощи обращения к функции gdk_imlib_create_image_f rom_xpm_data() в строке 37 создается Gdklmliblmage. Изображение добавляется в канву путем вызова gnome_canvas_item_new() в строке 38. Gdklmliblmage передается как аргумент "image". Значения х и у определяют точку привязки изображения в канве окна, а значение anchor задает, какая точка изображения располагается в точке привязки. В примере для размещения центра изображения в точке привязки используется GTK_ANCHOR_CENTER. Используя значения, приведенные в табл. 9.1, вы можете также привязать его в центре одной из сторон или в одном из углов. Существует более длинный вариант каждого имени, приведенного в таблице: например, имя GTK_ANCHOR_NORTH_EAST то же, что и GTK_ANCHOR_NE.
Хотя само изображение имеет встроенные размеры, все равно необходимо указывать высоту и ширину. Изображение масштабируется до указанных размеров. Если вы не хотите, чтобы рисунок масштабировался автоматически, нужно передать те же размеры, что определены в оригинальном изображении. Два из трех изображений в этом примере отображаются в их натуральную величину, а третье, размеры которого устанавливаются в строках 69 и 70, масштабируется в больший размер автоматически, как показано на рис. 9.5.
Таблица 9.1. Точки привязки, присоединяющие изображение к канве
Имя
Привязка изображения в...
GTK_ANCHkR_CENTER GTK_ANCHkR_E GTK_ANCHkR_N GTK_ANCHkR_NE GTK_ANCHkR_NW GTK_ANCHkR_S GTK_ANCHkR__.se GTK_ANCHkR_SW GTK_ANCHkR_W
его центре середине правого края середине верхнего края верхнем правом углу верхнем левом углу середине нижнего края нижнем правом углу нижнем левом углу середине левого края
Рисунок 9.5.Изображения можно установить так, чтобы они реагировали на события мышиРисунок 9.5.Изображения можно установить так, чтобы они реагировали на события мыши
Рисунок 9.5.
Изображения можно установить так, чтобы они реагировали на события мыши
Рисунок 9.5.
Изображения можно установить так, чтобы они реагировали на события мыши
После добавления изображения на канву, вы можете удалить его, если желаете, поскольку GnomeCanvasItem создает копию (возможно масштабированную). Изображение, созданное в строке 37, удаляется в строке 49. Другое изображение, созданное в строке 51, удаляется только после создания двух компонентов класса GnomeCanvasItem. Удаление выполняется вызовом функции gdk_imlib_destroy_image() в строке 75.
Функция обратного вызова dragEvent () практически та же, что и в предыдущем примере. В этой версии нажатие на левую кнопку приводит к перемещению компонента на вершину стека (проверка номера кнопки происходит в строке 101). Левая кнопка также выбрана для перемещения компонента по канве (в строке 90 проверяется бит state).
Текст на канве
Текст также может быть компонентом, отражаемым на канве. Он обладает практически всеми теми же свойствами, что и любой другой компонент. Приведенный ниже пример
создает три текстовых компонента и размещает их на канве.
/** canvastext.с **/
.2 linclude <gnome.h> 3
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
static gint dragEvent(GnomeCanvasItem *item,
GdkEvent *event,gpointer data);
•
Idefine WIDTH 600
Idefine HEIGHT 75
13
int main(int argc,char *argv[])
{
GtkWidget *app;
GtkWidget *canyas;
GnomeCanvasGroup *rootGroup;
GnomeCanvasItem *item;
20
21gnome_init("canvastext","1.0",argc,argv);
22арр = gnome_app_new("canvastext",
23"Gnome Canvas Text");
2 4gtk_signal_connect(GTK_OBJECT(app),"deleteevent",
2 5GTK_SIGNAL_FUNC(eventDelete),NULL);
26gtk_signal_connect(GTK_OBJECT(app),"destroy",
27GTK_SIGNAL_FUNC(eventDestroy),NULL);
28
293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879canvas = gnome_canvas_new();
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
gtk_widget_set_usize(canvas,WIDTH,HEIGHT); gnome_canvas_set_scroll_region(GNOMECANVAS(canvas), 0.0,0.0,WIDTH,HEIGHT);
rootGroup = gnome_canvas_root(GNOME_CANVAS(canvas)); gnome_app_set_contents(GNOME_APP(app),canvas);
item = gnome_canvas_item_new(rootGroup, gnome_canvas_text_get_type(), "text","This is on the left-", "x",(double)(WIDTH / 2), "y",(double)25,•
"anchor",GTK_ANCHOR_E, NULL);
gtk_signal_connect(GTK_OBJECT(item),"event", (GtkSignalFunc)dragEvent,NULL);
item = gnome_canvas_item_new(rootGroup, gnome_canvas_text_get_type(), "text","-and this is on the right.", "x",(double)(WIDTH / 2), "y",(double)25, "anchor",GTK_ANCHOR_W, NULL);
gtk_signal_connect(GTKOBJECT(item),"event", (GtkSignalFunc)dragEvent,NULL);
item * gnome_canvas_item_new(rootGroup, gnomecanvastextgettype(), "text","These larger red letters" " go all the way across.", "font","12x24", "x",(double)(WIDTH / 2), "y",(double)50, "fill_color","red", "anchor",GTKANCHORCENTER, NULL);
gtk_signal_connect(GTK_OBJECT(item),"event", (GtkSignalFunc)dragEvent,NULL);
gtk_widget_show_all(app);
gtk_main(); exit(0);
}
static gint dragEvent(GnomeCanvasItem *item, GdkEvent *event,gpointer data) { static gint x;
static gint y; gint new_x; gint newy;
8081828384858687888990919293949596979880818283848586878889909192939495969798switch(event->type) { case GDK_MOTION_NOTIFY:
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
if(event->button.state & 0x00000100) { new_x = event->button.x;
newy = event->button.y;
*gnome_canvas_item_move(item,
(double)(newx - x),
(double)(new_y - y));
x = newx;
у = new_y;
} break;
case GDK_BUTTON_PRESS:
if(event->button.button == 1) gnome_canvas_item_raise_to_top(item);
x = event->button.x;
у = event->button.y; break;
default:
99break;
100}
101return(O);
102 }
103 gint eventDelete(GtkWidget *widget,
104GdkEvent ♦event,gpointer data) {
105 return(FALSE);
106 }
107 gint eventDestroy(GtkWidget *widget,
108GdkEvent *event,gpointer data) {
109gtk_main_quit();
110return(0);
Hl }
Первый из трех компонентов создается с помощью функции gnome_canvas_item_new() в строке 36. Сам текст представляет собой строку символов. Необходимо задать координаты х и у и использовать точку привязки, чтобы указать, каким образом текст будет размещен относительно точки, применяемой для определения положения текстового компонента. Возможные положения точки привязки приведены в табл. 9.1 (в предыдущем разделе). Первый текстовый компонент подсоединяется к указанной точке своей правой стороной (восток).
Второй текстовый компонент, заданный в строке 46, использует ту же точку привязки, что и первый, но подсоединяется к заданной точке своей левой стороной (запад). Таким образом, эти две строки текста соединены вместе и выглядят как одна строка, что показано на рис. 9.6.
Рисунок 9.6.
. Thie i< on .the left—and this is on the right.These larger red letters go all the way across.. Thie i< on .the left—and this is on the right.These larger red letters go all the way across.Текст, возникающий как компонент канвы
. Thie i< on .the left—and this is on the right.
These larger red letters go all the way across.
. Thie i< on .the left—and this is on the right.
These larger red letters go all the way across.
Третий текстовый компонент определяется в строке 56. Текст присоединяется к точке, лежащей на 50 пикселов ниже вершины канвы, а по горизонтали — в центре окна. Таким образом текст центрируется. Кроме того, можно задать цвет текста и имя шрифта.
Текстовые компоненты похожи на любые другие компоненты канвы. Все три компонента подключаются к функции обратного вызова dragEvent() в строках 43, 53 и 66.
Эта функция позволяет вам с помощью нажатой левой кнопки мыши перемещать текст по канве. После перемещения текста окно будет выглядеть так, как показано на рис. 9.7.
This is on the left-These larger red letters-and this is on the right.This is on the left-These larger red letters-and this is on the right.Рисунок 9.7.Над текстом можно производить те же операции, что и над любым другим компонентомРисунок 9.7.Над текстом можно производить те же операции, что и над любым другим компонентом
This is on the left-
These larger red letters
-and this is on the right.
This is on the left-
These larger red letters
-and this is on the right.
Рисунок 9.7.
Над текстом можно производить те же операции, что и над любым другим компонентом
Рисунок 9.7.
Над текстом можно производить те же операции, что и над любым другим компонентом
Группирование компонентов на канве
При создании канвы создается и группа, которая взаимодействует с различными компонентами, расположенными на экране. Поскольку группа — тоже компонент, существует возможность включать одну группу канвы в другую. Это позволяет вам манипулировать целой труппой как одним компонентом. В приведенной ниже программе создается подгруппа, содержащая четыре эллипса.
/** grouping.с **/
#include <gnome.h>
gint eventDelete(GtkWidget «widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget «widget,
GdkEvent *event,gpointer data);
static gint dragEvent(GnomeCanvasItern «item,
GdkEvent *event,gpointer data);
10
Idefine HORIZ 50
Idefine VERT 50
Idefine WIDTH (HORIZ * 6)
Idefine HEIGHT (VERT * 6)
15
int main(int argc,char *argv[])
{
int i;
GtkWidget *app;"
GtkWidget «canvas;
GnomeCanvasGroup «rootGroup;
GnomeCanvasItern «item;
23GnomeCanvasItem «innerGroup;
24
25gnome_init("grouping", "1.0",argc,argv);
26app = gnome_app_new("grouping",
27"Canvas Grouping");
28 gtksignal connect(GTK_OBJECT(app),"delete_event",
29GTKSIGNALFUNC(eventDelete),NULL)7
30 gtk_signal_connect(GTKOBJECT(app),"destroy",
31GTKSIGNALFUNC(eventDestroy),NULL);
32
33canvas = gnome_canvas_new();
34gtk_widget_set_usize(canvas,WIDTH,HEIGHT);
35gnome_canvas_set_scroll_region(GNOMECANVAS(canvas),
360.0,0.0,WIDTH,HEIGHT);
37rootGroup = gnome_canvas_root(GNOME_CANVAS(canvas));
38gnome_app_set_contents(GNOME_APP(app),canvas);
39
40 4142 43444546474849505152 535455 56575859606162636465666768697071727374757677787980818283848586878889909192939495969740 4142 43444546474849505152 535455 565758596061626364656667686970717273747576777879808182838485868788899091929394959697innerGroup = gnome_canvas_item_new(rootGroup, gnome_canvas_group_get_type(), "x",(double)(HORIZ), "y",(double)(VERT), NULL);
40 41
42 43
44
45
46
47
48
49
50
51
52 53
54
55 56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
40 41
42 43
44
45
46
47
48
49
50
51
52 53
54
55 56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
gtksignalconnect(GTK_OBJECT(innerGroup),"event*, (GtkSignalFunc)dragEvent,NULL);
for(i=0; i<4; i++) { item = gnome_canvas_item_new( GNOME_CANVAS_GROUP(innerGroup), gnome_canvas_ellipse_get_type(), "xl",(double)(0), "yl",(double)(VERT ♦ i), "x2",(double)(HORIZ), "y2",(double)(VERT * (i+1)), "fill_color","white", "outline_color","black", NULL);
if(i == 2) gtk_signal_connect(GTK_OBJECT(item),"event", (GtkSignalFunc)dragEvent,NULL);
}
item = gnome_canvas_item_new(rootGroup, gnome_canvas_ellipse_get_type(), "xl",(double)(HORIZ * 3), "yl",(double)(VERT * 2), "x2",(double)(HORIZ *5), "y2",(double)(VERT * 4), "fill_color","green", "outlinecolor","white", NULL);
gtksignalconnect(GTK_OBJECT(item),"event", (GtkSignalFunc)dragEvent,NULL);
gtkwidgetshowall(app);
gtk_main();
exit(0);
} static gint dragEvent(GnomeCanvasItem *item, GdkEvent *event,gpointer data) { static gint x; static gint y; gint new_x; gint new_y;
switch(event->type) { case GDK_MOTION_NOTIFY: if(event->button.state & 0x00000100) { new_x = event->button.x; new_y = event->button.y; gnome_canvas_item_move(item, (double)(newx - x), (double)(new_y - y));
. x = new__x;у = new_y;
}
98break;
99 case GDK_BUTTON_PRESS:
100if(event->button.button== 1)
101gnome_canvas_item_raise_to_top(item);
102x = event->button.x;
103у = event->button.y;
104break;
105 defaults
106break;
107}
108return(O);
109 }
110 gint eventDelete(GtkWidget *widget,
111GdkEvent *event,gpointer data) {
112 return(FALSE);
113 }
114 gint eventDestroy(GtkWidget *widget,
115GdkEvent *event,gpointer data) {
116gtk_main_quit();
117return(O);
118 }
В строках с 33 по 38 создается канва и извлекается указатель на ее корневую группу.
Еще одна группа, которая будет добавлена в главную группу, создается в строке 40 путем вызова gnome_canvas__item_new(). Внутренняя группа просто накладывается на корневую группу, но это незаметно, поскольку обе группы абсолютно прозрачны как для отображения на экране, так и для мыши. Значения х и у, которые передаются функции — это координаты верхнего левого угла внутренней группы. Установка координат введена просто для удобства программирования, поскольку группа не имеет границ, а заданные значения только указывают начало отсчета, от которого будут измеряться расстояния. В нашем примере координаты (х и у) равны (50, 50), таким образом, присоединение какого-либо компонента к точке (0, 0) внутренней группы помещает его в точку (50, 50) корневой группы.
Рисунок 9.8. Несколько отдельных компонентов могут быть объединены в одну группуРисунок 9.8. Несколько отдельных компонентов могут быть объединены в одну группуЧетыре окружности, созданные из четырех эллипсов с равными высотой и шириной, добавляются во внутреннюю группу в цикле, который начинается со строки 48. Все четыре окружности одинаковы, но расположены во внутренней группе по-разному. Большая окружность справа в окне, определенная в строке 64, включается в корневую группу, что можно видеть на рис. 9.8.
Рисунок 9.8. Несколько отдельных компонентов могут быть объединены в одну группу
Рисунок 9.8. Несколько отдельных компонентов могут быть объединены в одну группу
Функция обратного вызова dragEvent (), начинающаяся в строке 80, позволяет при помощи мыши перетаскивать компоненты с одного места на другое. Функция обратного вызова связывается с внутренней группой в строке 45. В строках с 59 по 61 функция связывается с третьей окружностью внутренней группы. И в строке 73 функция обратного
вызова подключается к большей окружности.
Так же, как и в предыдущих примерах, вы можете перемещать в любое место большую окружность. Перемещая одну из малых окружностей (за исключением третьей), вы
Рисунок 9.9. Обратные вызовы могут быть определены как для отдельного компонента, так и для всей группыРисунок 9.9. Обратные вызовы могут быть определены как для отдельного компонента, так и для всей группы
Рисунок 9.9. Обратные вызовы могут быть определены как для отдельного компонента, так и для всей группы
Рисунок 9.9. Обратные вызовы могут быть определены как для отдельного компонента, так и для всей группы
перемещаете всю группу окружностей в новое положение. Третья окружность может перемещаться отдельно от группы, поскольку она имеет свою функцию обратного вызова. Внутренняя группа также имеет обратный вызов, но он прозрачен для мыши и поэтому выполняется только тогда, когда указатель находится внутри одного из объектов внутренней группы. При перемещении одной из окружностей (за исключением третьей) каждая окружность (включая третью) перемещается вместе с ней. После перемещения окно может выглядеть так, как показано на рис. 9.9.
Другими словами, если какой-либо компонент не имеет функции обратного вызова, то событие мыши передается группе, содержащей этот объект. При перемещении группы все компоненты этой группы перемещаются вместе с ней. Если же компонент имеет свою функцию обратного вызова, никакие события не передаются группе.
Добавление виджетов на канву
На канве может быть размещен любой виджет. Таким образом, если обычные контейнеры виджетов, описанные в главе 5, не дают необходимой вам гибкости, то для размещения виджетов в окне можно использовать канву. Преимущество канвы — возможность совместного использования графических объектов и виджетов. Существующий недостаток при использовании канвы в качестве контейнера — то, что ответственность за правильное размещение и размеры виджетов полностью возлагается на вашу программу.
В приведенной далее программе создаются три кнопки, и для их размещения в окне и задания размеров используется канва.
/♦♦ canvaswidget.с **/
Iinclude <gnome.h>
3
gint eventDelete(GtkWidget *widget,
GdkEvent *eventrgpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *eventrgpointer data);
8
Idefine HORIZ 50
Idefine VERT 30
Idefine WIDTH (HORIZ * 5)
Idefine HEIGHT (VERT * 5)
13
int main(int argc,char *argv[])
{
GtkWidget*app;
GtkWidget*canvas;
GtkWidget*button;
GnomeCanvasGroup *rootGroup;
GnomeCanvasItem *item;
gnome_init("canvaswidget","1.0",argc,argv); app = gnome_app_new("canvaswidget", "Gnome Canvas Widget");
gtk_signal_connect(GTK_OBJECT(app),"delete_event", GTK_SIGNAL_FUNC(eventDelete),NULL);
gtk_signal_connect(GTK_OBJECT(app),"destroy", GTK_SIGNAL_FUNC(eventDestroy),NULL);
canvas = gnome_canvas_new();
gtkwidgetsetusize(canvas,WIDTH,HEIGHT);
gnome_canvas_set_scroll_region(GNOMECANVAS (canvas)., 0.0,0.0,WIDTH,HEIGHT);
rootGroup = gnome_canvas_root(GNOME_CANVAS(canvas)); gnome_app_set_contents(GNOME_APP(app),canvas);
button = gtk_button_new_with_label("Button 1"); item = gnome_canvas_item_new(rootGroup, gnome_canvas_widget_get_type(), "widget",button, "x",(double)(HORIZ), "y",(double)(VERT), "width",(double)(HORIZ), "height",(double)(VERT), "anchor",GTK_ANCHOR_NW, NULL);
button = gtk_button_new_with_label("Button 2");
item = gnome_canvas_item_new(rootGroup, gnomecanvaswidgetgettype(), "widget",button, "x",(double)(HORIZ ♦ 3), "y",(double)(VERT), "width",(double)(HORIZ), "height",(double)(VERT), "anchor"rGTK_ANCHOR_NW, NULL);
button = gtk_button_new_with_label("Button Three"); item = gnome canvasitem new(rootGroup, gnome_canvas_widget_get_type(), "widget",button, "x",(double)(HORIZ), "y",(double)(VERT * 3), "width",(double)(HORIZ * 3), "height",(double)(VERT), "anchor",GTK_ANCHOR_NW, NULL);
gtk_widget_show_all(app);
gtk_main();
exit(0);
}
7576777875767778return(FALSE);return(FALSE);gint eventDelete(GtkWidget *widget, GdkEvent *event,gpointer data) {
75
76
77
78
75
76
77
78
return(FALSE);
return(FALSE);
}
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
gint eventDestroy(GtkWidget *widget, GdkEvent *event,gpointer data) {
79gtk_main_quit();
80return(O);
81 }
В строках с 30 по 35 создается и конфигурируется канва и вставляется в главное окно программы..
Обращение к gtk__button_new_wi th_label () в строке 37 создает кнопку с меткой ’’Button 1”. Эта кнопка конфигурируется как компонент канвы и с помощью функции gnome_canvas_item_new() помещается в корневую группу в строке 38. Виджет, заданный в строке 40, добавляется в канву при использовании точки привязки с координатами, указанными как х и у. Поскольку точка привязки задана как GTK_ANCHOR_NW, кнопка присоединяется к ней своим верхним левым углом. Полный список опций привязки можно найти ранее в этой главе в табл. 9.1. Высоту и ширину кнопки можно оставить принятыми по умолчанию, но в этом примере высота и ширина заданы явно.
Аналогичным образом кнопки ’’Button 2” и ’’Button Three” создаются и включаются в канву в строках с 48 по 67. На рис. 9.10 показан результат.
Размещение виджетов вРазмещение виджетов вокне с использованием канвыокне с использованием канвыПРИМЕЧАНИЕ .
Размещение виджетов в
Размещение виджетов в
окне с использованием канвы
окне с использованием канвы
В предыдущем примере никакие функции обратного вызова не назначены компонентам виджета канвы. Это вызвано тем, что виджет-кнопка имеет свой собственный набор функций обратного вызова и перехватывает несколько событий мыши, при этом некоторые события передаются через компонент, содержащий кнопку, а некоторые — не передаются. В любом случае вы можете определить для кнопки обычные функции обратного вызова и делать все, что пожелаете.
Рисование полигонов на канве
Полигон (polygon) — фигура произвольной формы с любым числом сторон также может быть включена в канву и отображаться как компонент. Приведенная ниже программа создает простую стрелку и отображает ее на канве.
/** canvaspolygon.с **/
#include <gnome.h> 3
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
GnomeCanvasPoints *makeArrow(gint h,gint v,
9
gint h_off,gint v_off);
10
11
12
13
♦define HORIZ 30
♦define VERT 30
♦define WIDTH (HORIZ * 6)
14
♦define HEIGHT (VERT * 6)
15
16
int main(int argc,char *argv[])
17
18
19
{
GtkWidget *app;
GtkWidget *canvas;
GnomeCanvasGroup *rootGroup;
GnomeCanvasItem *item;
22
3gnome_init("canvaspolygon","1.0",argc,argv);
app = gnome_app_new("canvaspolygon",
"Polygon Item");
gtk_signal_connect(GTK_OBJECT(app),"delete_event",
GTK_SIGNAL_FUNC(eventDelete),NULL);
gtk_signal_connect(GTKOBJECT(app),"destroy",
GTK_SIGNAL_FUNC(eventDestroy),NULL);
30
canvas = gnome_canvas_new();
gtk_widget_set_usize(canvas,WIDTH,HEIGHT);
gnome_canvas_set_scroll_region(GNOME CANVAS(canvas),
0.0,0•0,WIDTH,HEIGHT);
rootGroup = gnomecanvasroot(GNOMECANVAS(canvas));
gnome_app_set_contents(GNOME_APP(app),canvas);
37
item = gnome_canvas_item_new(rootGroup,
gnome canvas_polygonget_type(),
"points",make Arrow(HORIZ,VERT,HORIZ,VERT),
"fill_color","white",
"outline_color","black",
NULL);
44
gtk_widget_show_all(app);
gtk__main();
exit(0);
}
49
GnomeCanvasPoints *makeArrow(gint h,gint v,
gint h_off,gint voff) {
int i;
GnomeCanvasPoints*points;
static const gintxy[16] ={
552,0,0,2, 1,2, 1,4, 3,4,3,2,4,2, 2,0
};
57
points =gnome_canvas_points_new(8);
59for(i=0;i<16; i += 2) {
points->coords[i] = (xy[i] ♦ h) + hoff;
points->coords[i+l] = (xy[i+l] * v) + v_off;
}
return(points);
}
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data) {
return(FALSE);
}
69 gint eventDestroy(GtkWidget *widget,
. 70GdkEvent *event,gpointer data) {
gtkmainquit();
return(0);
}
Функция makeAr row (), начинающаяся co строки 50, создает объект GnomeCanvasPoints, который используется для создания компонента. Аргументы h и v определяют размеры стрелки в пикселах. Аргументы h_of f и v^of f складываются
с соответствующей координатой каждой точки и полученные результаты определяют положение стрелки на канве. Массив ху объявлен в строке 54, каждое его значение умножается на h и v для получения размеров сегментов, которые требуется нарисовать.
Всего стрелка имеет 8 точек, следовательно массив ху содержит 16 элементов. Элементы с четными номерами содержат координаты х, а с нечетными —у. Такая организа
Рисунок 9.11.Различные фигуры могут быть определены как набор точекРисунок 9.11.Различные фигуры могут быть определены как набор точекция координат точек совпадает с организацией в объекте GnomeCanvasPoints, поэтому один объект легко преобразовать в другой. Объект GnomeCanvasPoints создается в строке 58, а цикл, в котором вычисляются координаты стрелки, начинается в строке 59. В строках 60 и 61 путем умножения на h и v и добавления смещений вычисляются действительные координаты точек.
Рисунок 9.11.
Различные фигуры могут быть определены как набор точек
Рисунок 9.11.
Различные фигуры могут быть определены как набор точек
Полигон создается вызовом gnome_canvas_item_new() в строке 38. Для получения указателя на объект GnomeCanvasPoints вызывается функция makeArrow(). Все точки масштабируются и располагаются соответствующим образом, остается только закрасить сам полигон, что и выполняется в строках 41 и 42. Результат представлен на рис. 9.11. .
Аффинные преобразования на канве
Аффинные преобразования (affine transforms) могут использоваться для перемещения, масштабирования, вращения и других действий над отображаемыми компонентами. В приведенном ниже примере создаются три стрелки и к каждой из них применяются аффинные преобразования. Пример демонстрирует только основы использования аффинных преобразований над компонентами канвы.
ПРИМЕЧАНИЕ
Если вы не знакомы с аффинными преобразованиями, они могут показаться загадочными и даже волшебными. Аффинные преобразования используются для изменения размеров, зеркального отображения, вращения, инвертирования, растягивания, перекашивания и сжатия графических объектов. Имеется возможность объединить группу аффинных преобразований для выполнения серии манипуляций за один шаг.
/♦* canvasaffine.с **/
Iinclude <gnome.h>
3
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widgetr
GdkEvent *event,gpointer data);
GnomeCanvasPoints *makeOriginArrow(gint h,gint v); 9
Idefine HORIZ 30
Idefine VERT 30
Idefine WIDTH (HORIZ * 6)
Idefine HEIGHT (VERT ♦ 6)
14
int main(int argc,char *argv[])
{
GtkWidget *app;
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
' 65
66
67
68
69
70
71
72
73
74
75
GtkWidget *canvas;
GnomeCanvasGroup *rootGroup;
GnomeCanvasItem *item;
double affine[6];
gnomeinitf"canvasaffine","1.0",argc,argv);
app = gnome_app_new("canvasaffine", "Canvas Affine");
gtksignalconnect(GTKOBJECT(app),"deleteevent",
-GTKSIGNALFUNC(eventDelete),NULL);
gtksignalconnect(GTKOBJECT(app),"destroy", GTK_SIGNAL_FUNC(eventDestroy),NULL);
canvas * gnome_canvas_new();
gtkwidgetsetusize(canvas,WIDTH,HEIGHT);
gnome_canvas_set_scroll_region(GNOME_CANVAS(canvas),
-WIDTH/2,-HEIGHT/2,WIDTH/2,HEIGHT/2);
rootGroup = gnomecanvasroot(GNOMECANVAS(canvas)); gnomeappsetcontents(GNOMEAPP(app),canvas);
item = gnome_canvas_item_new(rootGroup,
gnome_canvas_polygon_get_type(), "points",makeOriginArrow(HORIZ,VERT) "fill-Color","white", "outlinecolor","black", NULL);
artaffine_scale(affine,1.3,1.3); gnome_canvas_item_affine_relative(item,affine);
item = gnome_canvas_item_new(rootGroup,
gnome_canvas_polygon_get_type(),
"points",makeOriginArrow(HORIZ/2,VERT/2), "fillcolor","black", "outline_color","white",
NULL);
artaffinerotate(affine,45.0);
gnome_canvas_item_affine_relative(item,affine);
item = gnome_canvasitem_new(rootGroup,
gnome_canvas_polygon_get_type(), "points",makeOriginArrow(HORIZ/2,VERT/2), "fill_color","green", "outlinecolor","black",
NULL);
art_affine_translate(affine,60,-50);
gnome_canvas_item_af f ine_relative (item, af f ine);
gtkwidgetshowall(app);
gtk_main();
exit(0);
GnomeCanvasPoints *makeOriginArrow(gint h,gint v) <
int i;
GnomeCanvasPoints *points;
76 static const gint xy[16] = {
770,-2, -2,0, -1,0, -1,2, 1,2, 1,0, 2,0, 0,-2
78};
79
80points =gnome_canvas_points_new(8);
81for(i=0;i<16; i += 2) {
82points->coords[i] = (xy[i] * h);
83points->coords[i+l] = (xy[i+l] * v);
84}
8 5return(points);
86 }
87 gint eventDelete(GtkWidget *widget,
88GdkEvent *event,gpointer data) {
89return(FALSE);
90 }
91 gint eventDestroy(GtkWidget *widget,
92GdkEvent *event,gpointer data) {
93gtkjmainquit();.
94 return(0);
95 }
Рисунок 9.12.К трем компонентам применены аффинные преобразованияРисунок 9.12.К трем компонентам применены аффинные преобразованияВ этом примере создаются три стрелки и к каждой из них применяются аффинные преобразования. Результат показан на рис. 9.12.
Рисунок 9.12.
К трем компонентам применены аффинные преобразования
Рисунок 9.12.
К трем компонентам применены аффинные преобразования
Как видно из строки 22, аффинные преобразования представляют собой массив из б чисел. При применении аффинных преобразований к графическому объекту этот массив чисел прикладывается к каждой точке объекта, перенося таким образом все точки этого объекта в другое положение. GNOME имеет несколько функций, которые могут быть использованы при инициализации массива для некоторых стандартных аффинных операций.
Стрелки создаются при обращении к функции makeOriginArrow() в строке 72. Эта стрелка несколько от-
личается от стрелки из предыдущего примера, поскольку в данном примере начало — точка с координатами (0,0) — размещается в центре стрелки. Чтобы стрелка появилась в центре окна, канва выставляется с началом координат в центре окна. Это производится с помощью функции gnome_canvas_set_scroll_region() в строке 34. Расположение начала координат в центре окна означает, что точка с координатами (0,0) расположена в центре экрана дисплея. Это очень удобно, поскольку некоторые аффинные преобразования (например, вращение) выполняются относительно начала координат. Существуют и другие пути достижения этого же размещения, но они требуют выполнения дополнительных аффинных преобразований.
Белая стрелка на заднем плане рис. 9.12 создается в строке 40 путем вызова gnome_canvas_item_new(). В строке 46 при обращении к art af f ine_scale() инициализируется аффинное преобразование, которое увеличивает стрелку в 1,3 раза вдоль обеих осей. А поскольку каждое число массива является сомножителем, значения большие, чем 1.0, увеличивают размеры, а меньшие, чем 1.0, — уменьшают. Расширение происходит относительно начала координат, которое в нашем случае располагается в центре стрелки, следовательно, стрелка равномерно расширяется во всех направлениях.
Черная стрелка, расположенная под углом в центре окна, создается в строке 49. Аффинное преобразование — поворот направо на 45° — инициализируется в строке 55 функцией art_af f ine_rotate(). Само вращение выполняется в строке 56.
Стрелка в верхнем правом углу окна, создаваемая в строке 58, создается в той же позиции, что и вращающаяся стрелка в центре. При обращении в строке 64 к функции art_af f ine_translate () инициализируется аффинное преобразование, которое перемещает стрелку вправо на 60 пикселов и вверх на 50 пикселов. Положительные значения перемещают компонент вниз и вправо, отрицательные — вверх и влево.
GdkEvent
На самом нижнем уровне мышь, клавиатура или что-нибудь еще создают событие Xevent, которое передается вашему приложению. Xevent содержит тег, идентифицирующий окно, для которого это событие предназначено. В табл. 9.2 перечислены типы событий и имена структур, которые используются для определения каждого из типов. После таблицы описано содержимое каждой из структур перечисленных событий.
Таблица 9.2. Имена, форматы и назначение приведенного класса событий GdkEvent
Имя события
Используемая структура
Описание
GKK_2BUTTkN_PRESS
GdkEventButton
Двойной щелчок любой кнопкой мыши.
GKK_3BUTTkN_PRESS
GdkEventButton
Тройной (или большей кратности) щелчок любой кнопкой мыши.
GKK_BUTTkN_PRESS
GdkEventButton
Нажата кнопка мыши.
GKK_BUTTkN_RELEASE
GdkEventButton
Отпущена кнопка мыши.
GKK_CLIENT_EVENT
GdkEventClient
Этот или другой процесс вызвал возникновение этого события.
GKK_CkNFIGURE
GdkEventConfigure
Изменение в конфигурации компонента.
GKK_KELETE
GdkEventAny
Был сделан запрос на удаление окна.
GKK_KESTRkY
GdkEventAny
Окно было разрушено.
GKK_KRAG_ENTER
GdkEventKNK
Указатель мыши при перетаскивании вошел в окно.
GKK_KRAG_LEAVE
GdkEventKNK
Указатель мыши при перетаскивании вышел из окна.
GKK_KRAG_MkTIkN
GdkEventKNK
Указатель мыши при перетаскивании
переместился внутри окна.
GKK_KRAG_STATUS
GdkEventKNK
Либо в источнике, либо в пункте назначения изменился статус перетаскивания.
GKK_KRkP_FINISHEK
GdkEventKNK
Операция переноса завершена.
GKK_KRkP_START
GdkEventKNK
Начинается операция переноса.
GKKJENTER_NkTIFY
GdkEventCrossing
Указатель мыши вошел в окно.
GKK_EXPkSE
GdkEventExpose
Все окно или его часть вышли на передний
план.
Таблица 9.2. (продолжение)
Имя события
Используемая структура
Описание
GKK_FkCUS_CHANGE
GdkEventFocus
Фокус переместился или в окно, или из
окна.
GKK_KEY_PRESS
GdkEventKey
Нажата клавиша на клавиатуре.
GKK_KEY_RELEASE
GdkEventKey
Отпущена клавиша на клавиатуре.
GKK_LEAVE_NkTIFY
GdkEventCrossing
Указатель мыши вышел из окна.
GKK_MAP
GdkEventAny
Окно было сделано видимым.
GKK_MkTIkN_NkTIFY
GdkEventMotion
Переместился указатель мыши.
GKK_NkTHING
GdkEventAny
Отсутствие событий.
GKK_Nk_EXPkSE
GdkEventNoExpose
При операции копирования изображения исходное окно было доступно, поэтому оно не требует перемещения на передний план.
GKK_PRkPERTY_NkTIFY
GdkEventProperty
Свойство окна было изменено или удалено.
GKK_PRkXIMITYJN
GdkEventProximity
Игольчатая мышь вошла в контакт с графическим планшетом.
GKK_PRkXIMITY_kUT
GdkEventProximity
Игольчатая мышь потеряла контакт с графическим планшетом.
GKK_SELECTIkN_CLEAR
GdkEventSelection
Во время операции cut-and-paste выбранный объект больше не принадлежит получателю этого события.
GKK_SELECTIkN_NkTIFY
GdkEventSelection
Во время операции cut-and-paste новый владелец выбранного объекта генерирует это событие для индикации успешной или аварийной передачи права собственности над этим объектом.
GKK_SELECTIkN_REQUEST
GdkEventSelection
Во время операции cut-and-paste другой клиент потребовал получения права собственности над выбранным объек
том.
gkkjjnmap
GdkEventAny
Окно больше не отображается.
GKK_VISIBILITY_NkTIFY
GdkEventVisibility
Произошло изменение в видимости окна.
Большинство виджетов в качестве объекта для всех событий используют полное окно, но GnomeCanvas на шаг опережает все остальные виджеты. Если событие привязано к определенному месту через координаты хиу некоторой точки в окне, то это событие передается для обработки компоненту, который находится по этим координатам. Вышесказанное позволяет использовать функции обратного вызова для отдельных объектов, отображаемых в виджете GnomeCanvas.
В заголовочных файлах каждая структура определена в виде двух частей. Первая — это собственно сама структура, а вторая — оператор typedef (определения типа) для этой структуры. Имена различаются только первым символом: имя структуры начинает-
ся с символа подчеркивания, a typedef — нет. Например, typedef для GdkEvent Any определен следующим образом:
typedef struct __GdkEventAny GdkEventAny;
Тогда структура определяется следующим образом:
struct GdkEventAny {
};
В результате при объявлении события применяется тот же синтаксис, что для любого базового типа:
GdkEventAny any;
Некоторые общие поля
Некоторые форматы событий имеют несколько одинаковых полей. Например, оба события — нажатие на кнопку мыши и освобождение кнопки — содержат координаты указателя мыши во время их возникновения.
X и у
В событиях, которые передают данные о положении, присутствуют два набора координат. Значения х и у — это координаты указателя мыши относительно верхнего левого угла текущего окна. Второй набор координат — x_root и y_root — координаты той же точки, но относительно верхнего левого угла корневого окна.
ПРИМЕЧАНИЕ
В окне GtkCanvas координаты берутся не относительно угла компонента внутри канвы, а относительно всего окна канвы.
time
Во многих структурах событий GdkEvent присутствуют поля time. Значение таких полей — это временная метка, по которой вы можете установить последовательность возникновения событий (при работе в сети порядок событий может быть нарушен) и, что еще более важно, определить, как объединить два происшедших события. В программном обеспечении GDK используются временные метки, чтобы определить, когда двойной щелчок кнопкой мыши рассматривается как событие двойного щелчка.
state
Некоторые из структур событий GdkEvent (в частности те, которые связаны с событиями мыши) содержат поле state (состояние), которое указывает, какая кнопка нажимается. Поскольку одновременно может быть нажато несколько кнопок, то каждой из них присвоен один бит. В табл. 9.3 перечислены кнопки и соответствующие им биты. Пока кнопка удерживается в нажатом состоянии, соответствующий ей бит state равен 1, если ни одна из кнопок не нажата, значение state состоит из одних нулей.
Таблица 9.3. Биты состояния, указывающие нажатые кнопки
СостояниеНазначенный бит
На клавиатуре нажата клавиша Shift.0x00000001
На клавиатуре включена клавиша Caps Lock. 0x00000002
Таблица 9.3. (продолжение)
Состояние
Назначенный бит
На клавиатуре нажата клавиша Ctrl.
На клавиатуре нажата клавиша Alt или Meta.
Нажата первая (левая) кнопка мыши.
Нажата вторая (средняя) кнопка мыши.
Нажата третья (правая) кнопка мыши.
0x00000004
0x00000008
0x00000100
0x00000200
0x00000400
source
Когда возникает событие, связанное с каком-либо аппаратным устройством, то для идентификации типа устройства используется поле source (источник), имеющее тип GdklnputSource. Это поле принадлежит к типу enum (энумератор) и может принимать одно из следующих значений:
GDK_SOURCE_MOUSE
GDK_SOURCE_PEN
GDK_SOURCE_ERASER
GDK_SOURCE__CURSOR
GdkEvent
GdkEvent — это объединение нескольких структур событий. Каждая из этих структур содержит поля данных, необходимые для одного или нескольких событий. Это позволяет системе передавать различные события, как если бы они были одного типа, но это также означает, что ваша программа должна определить действительный тип события. Чтобы облегчить задачу определения типа события и структуры, которая содержит данные о событии, первым полем во всех структурах является поле type.
type;any;expose;no_expose; visibility; motion;button; key;crossing; focus_change; configure;property; selection; proximity; client;dnd;type;any;expose;no_expose; visibility; motion;button; key;crossing; focus_change; configure;property; selection; proximity; client;dnd;union _GdkEvent { GdkEventType GdkEventAny GdkEventExpose GdkEventNoExpose GdkEventVisibility GdkEventMotion GdkEventButton GdkEventKey GdkEventCrossing GdkEventFocu s GdkEventConfigure GdkEventProperty GdkEventSelection GdkEventProximity GdkEventClient GdkEventDND
type;
any;
expose;
no_expose; visibility; motion;
button; key;
crossing; focus_change; configure;
property; selection; proximity; client;
dnd;
type;
any;
expose;
no_expose; visibility; motion;
button; key;
crossing; focus_change; configure;
property; selection; proximity; client;
dnd;
Для получения доступа к полю данных одного из событий вы можете привести это поле к его действительному типу или использовать имя, входящее в объединение. Например, если необходимо скопировать значение поля х из события типа GdkEventMotion, сделайте следующее:
GkdEvent *event;
if (even t-> type == GDK—MOTION—NOTIFY) { xlocation = event~>motion.x;
Можно также выполнить приведение типа объединения к типу структуры и получить доступ к полям данных напрямую:
GdkEvent *event;
GdkEventMotion *motion;
if(event->type == GDK_MOTION_NOTIFY) { motion = (GdkEventMotion *)event; xlocation = motion~>x;
GdkEventAny
Любое событие, которое не требует дополнительных данных, может быть передано как событие any ("любое”), поскольку данные о нем содержат только основные поля, которые появляются во всех событиях. Пример события такого типа — GDK_DESTROY, которое сообщает о том, что окно разрушено.
struct _GdkEventAny {
GdkEventType type;
GdkWindow *window;
gint8 send_event;
}?
GdkEventButton
Значение поля button — это число, указывающее, какая кнопка была использована. Причем левой кнопке соответствует 1, средней — 2 и правой — 3.
Значение поля pressure всегда равно 0.5. Значения полей xtilt и ytilt всегда равны 0.0. Возможные значения поля state приведены в табл. 9.3 (в разделе state ранее в этой главе).
source — это идентификатор устройства ввода. Обычно это GDK_CORE_POINTER, что соответствует константе OxFEDC.
struct _GdkEventButton {
GdkEventType type;
GdkWindow *window;
gint8 send-event;
guint32 time;
gdouble x;
gdouble y;.
'gdouble pressure;
gdouble xtilt;
gdouble ytilt;
guint state;
guint button;
GdklnputSource source;
guint32 deviceid;
gdouble X-root, У-root;
};
GdkEventClient
Это событие может быть использовано для взаимодействия между процессами (или между окнами). Для этого события значение send_event будет всегда равно TRUE, поскольку события такого типа всегда порождается в процессе. Для передачи данных в структуру события включается блок размером до 20 байт.
Поле message_type используется для передачи действительного типа события. Это строка символов, которая передается в формате GdkAtom.
Значение поля data_f ormat — это количество бит в каждом элементе массива данных. Если это значение равно 8, то массив Ь содержит 20 байт данных, если — 16, то массив s содержит десять 16-битных двоичных значений, если — 32, то массив 1 содержит пять 32-битных значений.
struct _GdkEventClient {
GdkEventType type;
GdkWindow *window;
gint8 sendevent;
GdkAtom messagetype;
gushort data_format;
union {
char b[20];
short s[10);
long 1(5);
} data;
};
GdkEventConfigure
Это событие возникает, когда изменяются размеры и/или положение окна. Значения х и у указывают положение, а значение width и height — размеры.
struct ^GdkEventConfigure {
GdkEventType type;
GdkWindow *window;
gint8 send-event;
gintl6 x, y;
gintie width;
gintie height;
};
GdkEventCrossing
Это событие возникает всегда, когда указатель мыши пересекает границу окна.
struct —GdkEventCrossing {
GdkEventType type;
GdkWindow *window;
gint8 send-event;
GdkWindow *subwindow;
guint32 time;
gdouble x;
gdouble y;
gdouble X-root;
gdouble y_root;
GdkCrossingMode mode;
GdkNotifyType detail;
gboolean focus;
guint state;
};
Поле mode, как правило, принимает значение GDK_CROSSING_NORMAL. Однако, если пересечение границы происходит в начале операции перетаскивания объекта, mode содержит значение GDK_CROSSING_GRAB, а если пересечение границы происходит в конце операции перетаскивания — GDK_CROSSING_UNGRAB.
Если окно-приемник, в которое перемещается указатель мыши, или одно из его родительских окон попало в фокус (еще говорят сфокусировано), то поле focus содержит значение TRUE.
Поле window — указатель на окно-приемник, a subwindow — указатель на окно, из которого или в которое переходит указатель мыши. Поле detail содержит одно из значений, приведенных в табл. 9.4, которое дает дополнительные данные о subwindow.
Таблица 9.4. Возможные значения поля detail, сообщающие дополнительные данные о другом окне, участвующем в перетаскивании объекта
Имя
Описание
GKK_
_NkTIFY_
_ANCESTkR
Другое окно является родительским окном или каким- либо предком данного окна.
GKK_
_NkTIFY.
JNFERIkR
Другое окно является дочерним окном или каким- нибудь потомком данного окна.
GKK_
_NkTIFY_
_NkNLINEAR
Другое окно не является ни дочерним, ни родительским окном данного окна — они просто в разных иерархиях.
GKK,
_NkTIFY_
VIRTUAL
Указатель передается между двумя окнами в том же иерархическом дереве, что и данное окно; одно из окон является дочерним окном данного окна, а другое — родительским.
GKK_NkTIFY_NkNLINEAR_VIRTUAL Указатель перемещается между дочерним окном данного окна и окном, принадлежащим другому иерархическому дереву.
GdkEventDND
Все операции drag-and-drop используют этот тип события для обмена данными о статусе операции. Поле context содержит информацию по операции drag-and-drop. Примеры использования этого события приведены в главе 16.
struct _GdkEventDND {
GdkEventType type;
GdkWindow *window;
gint8 send_event;
GdkDragContext *context;
guint32 time;
gshort x_root, y_root; '
GdkEventExpose
Внутренние утилиты, которые копируют прямоугольную область пикселов из одного места в другое место этого же или другого окна, генерируют это событие, если источник недоступен, потому что невидим. Он может быть закрыт другим окном или просто частично или полностью находиться вне просматриваемой области окна. Если источник копирования доступен, генерируется событие GdkEventNoExpose.
Поле area указывает, какая часть окна невидима. Бывают случаи, когда в качестве источника используется не одна прямоугольная область, следовательно, может генерироваться целая серия таких событий, которые можно объединить, чтобы описать полную область. Если за данным событием GdkEventExpose должны последовать другие такие же, то значение поля count указывает их количество.
struct _GdkEventExpose { GdkEventType type; GdkWindow *window; gint8 send_event; GdkRectangle area; gint count;
};
GdkEventFocus
Это событие сигнализирует об изменениях фокуса для данного окна. Если значение поля in не равно нулю, то окно попадает в фокус. Если значение поля in равно нулю, то окно, имеющее фокус, утрачивает его.
struct _GdkEventFocus { GdkEventType type; GdkWindow *window; gint8 send_event; gint!6 in;
};
GdkEventKey
Это событие сигнализирует о том, что клавиша на клавиатуре была либо нажата, либо отпущена. Значение поля keyval идентифицирует клавишу. По значению поля state можно определить, нажаты ли клавиши Ctrl, Shift, Alt или Meta._
Поле string содержит описание клавиши в формате ASCII. Значение поля length — это количество символов в поле string.
struct _GdkEventKey { GdkEventType type; GdkWindow *window; gint8 send-event; guint32 time; guint state; guint keyval; gint length;
gchar *string;
I:
GdkEventMotion
Событие этого типа возникает при перемещении указателя мыши в пределах окна.
Поля х, у, x_root и y_root отражают новое расположение.
struct __GdkEventMotion {
GdkEventType type;
GdkWindow *window;
gint8 send-event;
guint32 time;
gdouble x;'
gdouble y;
gdouble pressure;
gdouble xtilt;
gdouble ytilt;
guint state;
gintl6 iS—hint;
GdklnputSource source;
guint32 deviceid;
gdouble x_root, yroot;
};
Поле is_hint используется для передачи предупреждения о том, что хотя данное событие и дает правильную информацию о перемещении указателя для данной временной метки, но после него следуют другие события, которые могут изменить эти данные. Вышесказанное дает возможность приложению (для достижения большей эффективности) не обрабатывать текущие данные о положении указателя, а подождать до возникновения следующего события. В обычных условиях это ничего не дает, но в достаточно медленной сети события могут накапливаться на сервере.
GdkEventNoExpose
Внутренние утилиты, копирующие прямоугольную область пикселов из одного места в другое место этого же или другого окна, генерируют это событие, если источник отображаем и доступен для копирования. Если источник закрыт другими окнами, частично или полностью находится вне просматриваемой области окна, то возникает событие GdkEventExpose.
struct _GdkEventNoExpose {
GdkEventType type;
GdkWindow ♦window;
gint8 send_event;
};
GdkEventProperty
Это событие сигнализирует о том, что свойство окна было изменено.
atom — ключевое значение, используемое для установки значения свойства. Значение поля state равно 0, если произошло изменение свойства, и 1, если свойство удаляется.
struct -GdkEventProperty {
GdkEventType type;
GdkWindow *window;
gint8 send-event;
GdkAtom atom;
guint32 time;
quint state;
GdkEventProximity
Событие сигнализирует программе о том, что указатель мыши находится внутри или вне области, в которой окно приложения должно рисовать свой собственный курсор. Это событие практически никогда не используется в приложениях, поскольку GNOME обеспечивает гораздо более простые пути обработки изменений вида курсора.
struct _GdkEventProximity {
GdkEventType type;
GdkWindow *window;
gintS send_event;
guint32 time;
GdklnputSource source;
guint32 deviceid;
};
GdkEventSelection
События такого типа передаются из одного приложения другому для уведомления об изменении права собственности над объектом в результате операций drag-and-drop или cut-and-paste.
struct _GdkEventSelection {
GdkEventType type;
GdkWindow *window;
gintB sendevent;
GdkAtom selection;
GdkAtom target;
GdkAtom property;
guint32 requestor;
guint32 time;
}?
Поле selection идентифицирует компонент, который передается из одного приложения в другое.'
" target — это формат, в который необходимо преобразовать данные для выполнения передачи объекта. Если значение target равно нулю, информация не может быть конвертирована.
Поле requestor содержит идентификатор окна, которое потребовало передачи права собственности.
GdkEvenWisibility
Событие этого типа возникает каждый раз при изменении состояния видимости окна. Состояние видимости изменяется, когда все или часть окна закрывается или открывается при сворачивании, разворачивании или изменении порядка окон в стеке.
struct _GdkEventVisibility {
GdkEventType type;
GdkWindow *window;
gint8 send_event;
GdkVisibilityState state;
Поле state отражает текущее состояние видимости окна. Оно может принимать одно из следующих значений:
GDKVISIBILITYUNOBSCURED
GDKVISIBILITYPARTIAL
GDKVISIBILITYFULLYOBSCURED
Выводы
Если возможности контейнеров, которые были описаны в главах 4 и 5, вас не устраивают, виджет GnomeCanvas может оказаться наилучшим решением. С помощью этого виджета вы не только получите полный контроль над размерами и положением всех компонентов, но и сможете использовать аффинные преобразования для изменения их вида. Описание GnomeCanvas в этой главе включает следующее:
® Виджет GnomeCanvas поддерживает порядок в своем внутреннем стеке и передает события мыши тому компоненту, внутри которого в данный момент находится указатель мыши.,
# Компонент канвы (canvas) можно перемещать из одного положения в другое. В действительности канва не имеет ограничений ни по ширине, ни по высоте, поэтому вы можете перемещать компонент куда угодно.
<1 Компоненты виджета объединяются в группы, и сама группа также является компонентом. Это означает, что любая группа может содержать любое количество подгрупп.
О Имеются специальные графические примитивы, которые могут быть использованы для создания рисунков. Вы можете их изменять с помощью аффинных преобразований.
^ События мыши, клавиатуры и другие события могут быть переданы отдельным компонентам виджета GnomeCanvas .
В то время как виджет GnomeCanvas предоставляет вам широкие возможности для размещения компонентов, виджет GtkKra wing Area, описанный в следующей главе, позволяет рисовать пикселы прямо в окне. Помимо возможности рисования отдельных пикселов этот виджет имеет целый ряд функций, которые позволяют рисовать и/или заливать прямоугольники, полигоны, окружности, эллипсы, дуги, текст и цветные растровые изображения.
™ область для рисования и 1 0 графические примитивы
# Рисование отдельных пикселов
• Рисование квадратов, прямоугольников и полигонов
^ Рисование кривых, окружностей, эллипсов и дуг
® Совместное использование текста и других компонентов в одном окне
• Рисование цветных растровых изображений на поверхности окна
# Создание анимации путем рисования многочисленных кадров
Существует виджет GtkKrawing Area, отображающий пустое окно, которое может быть использовано для рисования графических объектов. Вы можете рисовать их по пикселу, по одной линии, или можете рисовать простые геометрические фигуры, полигоны, цветные растровые изображения и любые их комбинации.
В этой главе приведены примеры рисования графических объектов в области для рисования. Поскольку за рисование графических объектов и их размещение в окне отвечает прикладная программа, она должна также отвечать за восстановление (перерисовку) окна всякий раз, когда окно выходит на передний план. В некоторых случаях для введения необходимых изменений в рисунок приложение должно также отслеживать размеры и форму окна.
Таким образом, каждый отображаемый виджет содержит область для рисования (drawing area), потому что она является всего лишь окном. Для этой цели наиболее подходит виджет GtkKra wing Area, поскольку сам он ничего не рисует. Вы можете проделать те же операции, скажем, над виджетом-кнопкой, но вам придется бороться с естественными встроенными действиями кнопки по обновлению цвета и выводу текста — и результат может быть непредсказуемым. При использовании области для рисования вы получаете полноту управления.
Основы рисования
GtkDrawingArea — это всего лишь виджет в виде окна, не многим больше базового окна X. Существует набор функций, с помощью которых можно выполнять рисование. Но сам процесс рисования немного отличается от процесса рисования в других виджетах. Ваша программа должна нести ответственность за детали, поскольку все делается на более низком уровне, чем в GTK+ (да и в целом в GNOME).
Большинство виджетов GNOME и GTK+ сами обновляют свое изображение. Но GtkDrawingArea этого не делает. Вы сами должны создать функцию обратного вызова, которая будет рисовать окно, как только оно становится видимым. Кроме того, поскольку вы имеете доступ к пикселам рисунка, следует использовать для рисования объект GdkGC (графический контекст). Существует ряд объектов GdkGC, применяемых как часть виджета в GTK+, но, тем не менее, в некоторых случаях вам придется создавать свои собственные объекты.
Приведенный пример демонстрирует, как установить область для рисования. Эта программа вместе с GtkDrawingArea заполняет окно приложения и рисует в нем две линии.
/** simpleline.с **/
Iinclude <gnome.h>
3
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
gboolean eventDraw(GtkWidget ♦widget,
GdkEvent *event,gpointer data);
10
Idefine WIDTH 200
Idefine HEIGHT 100
13
int main(int argc,char *argv[])
{
GtkWidget *app;
17GtkWidget *area;
18•
19gnome_init("simpleline","1.0",argc,argv);
20app = gnome_app_new("simpleline","Drawing Area");
21gtksignalconnect(GTK_OBJECT(app),"delete_event",
GTK_SIGNAL_FUNC(eventDelete),NULL);
gtk_signal_connect(GTK_OBJECT(app),"destroy",
GTK_SIGNAL_FUNC(eventDestroy),NULL);
25
area = gtk_drawing_area_new();
gtk_widget_set_usize(area,WIDTH,HEIGHT);
gnome_app_set_contents(GNOME_APP(app),area);
29
gtk_signal_connect(GTK_OBJECT(area),"event",
GTKSIGNALFUNC(eventDraw),NULL);
32
gtk_widget_show_all(app);
gtk_main();
exit(0);
I
gboolean eventDraw(GtkWidget *widget,
38GdkEvent *event,gpointer data) {
39gdk_draw_line(widget->window,
40widget->style->black_gc,
4110,
4210,
43WIDTH - 10,
44HEIGHT - 10);
45gdk_draw_line(widget->window,
46widget->style->white_gc,
47
io.
48
HEIGHT - 10,
49
WIDTH - 10,
50
10);
51
return(TRUE);
52 }
53 gint eventDelete(GtkWidget *widget, 54GdkEvent ♦event,gpointer data) {
55return(FALSE);
56 }
57 gint eventDestroy(GtkWidget *widget,
58GdkEvent ♦event,gpointer data) {
59gtk_main_quit();
60return(O);
61 }
Область для рисования создается в строке 26 при помощи обращения к функции gtk_drawing_area_new(), а ее размер устанавливается в строке 27. При обращении к gnome_app_set_contents () присоединяется область рисования как единственное пока отображаемое содержимое окна приложения. Окно подстраивает свои размеры под область для рисования.
Обращение к функции gtk_signal_connect() в строке 30 назначает функцию обратного вызова сигналу event. Этот сигнал (доступный для всех виджетов) наилучшим образом подходит области для рисования, поскольку он не только сигнализирует об изменениях конфигурации и отображения окна, но и о необходимости прорисовки содержимого при выходе окна на передний план. Выход всего окна или его части на передний план (экспозиция) может произойти при разворачивании окна из пиктограммы, при перемещении другого окна, которое закрывало данное, или просто при закрытии подсказки,
которая частично закрывала окно.
Рисунок 10.1.Две линии, нарисованные в области для рисованияРисунок 10.1.Две линии, нарисованные в области для рисованияФункция обратного вызова eventDraw() начинается в строке 37. Это простая функция, которая игнорирует тип события и рисует все окно, когда бы ни возникло событие. Функция gtk_draw_line() используется с двумя разными графическими контекстами для рисования линий двух различных цветов. Графический контекст — объект GdkGC — определяет цвет каждой линии. Как видно из строк 40 и 46, несколько стандартных графических контекстов включается как часть виджета. Результат приведен на рис. 10.1.
Рисунок 10.1.
Две линии, нарисованные в области для рисования
Рисунок 10.1.
Две линии, нарисованные в области для рисования
Рисование по отдельным пикселам
Если вам необходимо получить полноту управления вашими изображениями, можно рисовать окно по пикселу. Существует два основных способа выполнить это: одноточечная функция, рисующая только один пиксел, и многоточечная функция, позволяющая вам сохранять координаты пикселов в массиве. Приведенный ниже пример демонстрирует оба этих метода.
/♦♦ pixels.с ♦♦/
#include <gnome.h>
3
gint eventDelete(GtkWidget *widget,
GdkEvent ♦event,gpointer data);
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
gint eventDestroy(GtkWidget *widget, GdkEvent *event,gpointer data); gboolean eventDraw(GtkWidget *widget, GdkEvent *event,gpointer data);
Idefine WIDTH 400
Idefine HEIGHT 200
int main(int argc,char *argv[]) {
GtkWidget *app;
GtkWidget *area;
gnome_init("pixels","1.0",argc,argv);
app = gnome_app_new("pixels","Drawing Pixels");
gtk_signal_connect(GTK_OBJECT(app),"deleteevent", GTK_SIGNAL_FUNC(eventDelete),NULL);
gtk_signal_connect(GTK_OBJECT(app),"destroy", GTKSIGNALFUNC(eventDestroy),NULL);
area = gtk_drawing_area_new();
gtk_widget_set_usize(area,WIDTH,HEIGHT); gnomeappsetcontents(GNOME_APP(app),area);
gtk_signal_connect(GTKOBJECT(area),"event", GTKSIGNALFUNC(eventDraw),NULL);
gtk_widget_show_all(app);
gtk_main();
exit(0);
}
gboolean eventDraw(GtkWidget *widget, GdkEvent ♦event,gpointer data) {
static GdkPoint points[] =
{
{ 50,100 }, { 51,100 },
{ 50,101 }, { 51,101 },
{ 60,100 }, { 61,100 },
{ 60,101 y, { 61,101 },
{ 55,105 }, { 56,105 y,
{ 55,106 y, { 56,106 },
{ 50,110 }, { 51,111 },
{ 52,112 y, { 53,112 },
{ 54,113 }, { 55,113 },
{ 56,113 У, { 57,113 },
{ 58,112 }, { 59,112 y,
{ 60,111 }, { 61,110 },
};
gint x = WIDTH/4;
gint у = 0;
gint i;
while(у < HEIGHT) {
for(i=0; i<10; i++) { gdk_draw_point(widget->window, widget->style->blackgc, x++, y);
}
for(i=0; i<10; i++) {
gdkdrawpoint(widget~>window, widget->style->white_gc, x,
62636263>>у++);у++);
62
63
62
63
>
>
у++);
у++);
64}
65
66srand(l);
67for(i=0; i<2000; i++) {
68x = (int)(((double)rand()*WIDTH)/RAND MAX);
69у= (int)(((double)rand()*HEIGHT)/RANDMAX);
70gdk_draw_point(widget->window,
71widget->style->white_gc,
72x,
73y);
74}
75
76gdkdrawpoints(widget->window,
77widget->style->black_gc,
78points,
79sizeof(points)/sizeof(GdkPoint));
80.
81return(TRUE);
82 }
83 gint eventDelete(GtkWidget *widget,
84GdkEvent *event,gpointer data) {
85return(FALSE);
86 }'
87 gint eventDestroy(GtkWidget *widget,
88GdkEvent ♦event,gpointer data) {
89gtkmainquit();
90return(O);
91 }
В строках с 26 по 31 создается область для рисования и включается в окно приложения, ей назначается функция обратного вызова е vent Dr aw (). Рисование пикселов производится именно в этой функции.
В окне рисуются отдельные пикселыВ окне рисуются отдельные пикселыЦикл, который начинается со строки 51, рисует зигзагообразную ломаную линию, которая проходит через все окно, как показано на рис. 10.2. Обращение к функции gdk_draw_point () в строке 53 выполняет рисование черного пиксела. Поскольку эта функция находится в цикле, который начинается в строке 52, при рисовании каждого последующего пиксела координата х увеличивается, возникает горизонтальная часть зигзага. Второй цикл, который начинается в строке 58, для рисования белого пиксела вызывает функцию gdk_draw__point () и перед рисованием каждого последующего пиксела увеличивает координату у. При этом рисуется вертикальная часть зигзага.
В окне рисуются отдельные пикселы
В окне рисуются отдельные пикселы
В строках с 66 по 73 белые пикселы случайным образом разбрасываются по окну. Задание одного и того же значения для генерации случайных чисел, которое производится с помощью функции grand() в строке 66, создает одну и ту же последовательность псевдослучайных чисел. В нашем случае возможность воспроизведения одной и той же последовательности является существенным преимуществом, поскольку окно при попадании на передний план может быть каждый раз перерисовано в одном и том же виде. В строках 68 и 69 путем вызова функции rand() генерируются новые значения для х и у.
Увеличенное изображение рисунка: рисование за один разУвеличенное изображение рисунка: рисование за один раз
Увеличенное изображение рисунка: рисование за один раз
Увеличенное изображение рисунка: рисование за один раз
Функция rand () возвращает число в диапазоне от 0 до RAND_MAX, так как необходимо масштабировать число в диапазоне возможных значений пиксела. Вызов gdk_draw_point() рисует пиксел, используя белый объект GdkGC. На рис. 10.2 видны разбросанные по окну белые точки.
В строках с 76 по 79 используется другой метод рисования пикселов. Вместо вычисления координат каждого пиксела и организации цикла для рисования, координаты пикселов хранятся в массиве структур GdkPoint, который объявлен в строке 39. Рисунок выполнен черными пикселами в левой части окна, что изображено на рис. 10.2, и имеет вид улыбающегося лица. Структура GdkPoint содержит только значения х и у:
struct _GdkPoint {
gintl6 х;
gintl6 у;
};
Вызов функции gdk_draw_points() в строке 76 требует адрес массива точек и количество элементов в массиве. В строке 79 определяется количество элементов в массиве путем деления размера массива на размер одного его элемента.
В X имеется стандартная утилита, облегчающая просмотр пикселов. Для ее запуска наберите в командной строке xmag, а затем выберите верхний левый угол области на экране. Область не обязательно должна ограничиваться одним окном. На рис. 10.3 изображен детальный рисунок рассмотренного примера.
Рисование и заливка прямоугольников
Рисование прямоугольников выполняется либо в виде цветных блоков, либо путем обводки контура. Можно также использовать совместно эти два способа и получить обведенный прямоугольник, залитый цветом.
/*♦ rectangles.с **/
♦include <gnome.h> 3
gint eventDelete(GtkWidget *widget, 5GdkEvent *event,gpointer data);
6*gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
gboolean eventDraw(GtkWidget *widget,
GdkEvent *event,gpointer data);
10
Idefine HORIZ 50
Idefine VERT 60
tdefine WIDTH (HORIZ ♦ 10)
tdefine HEIGHT (VERT * 3)
15
int main(int argc,char *argv[])
{
GtkWidget *app;
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
GtkWidget *area;
gnome_init("rectangles","1.0",argc,argv);
app = gnome_app_new("rectangles","Drawing Rectangles"); gtk_signal_connect(GTK_OBJECT(app),"deleteevent", GTK_SIGNAL_FUNC(eventDelete),NULL);
gtk_signal_connect(GTK__OBJECT(app),"destroy", GTK_SIGNAL_FUNC(eventDestroy),NULL);
area = gtk_drawing_area_new();
gtk_widget_set_usize(area,WIDTH,HEIGHT); gnome_app_set_contents (GNOME__APP (app), area);
gtk_signal_connect(GTK_OBJECT(area),"event", GTK_SIGNAL_FUNC(eventDraw),NULL);
gtk_widget_show_all(app);
gtk_main();
exit(0);
}
gboolean eventDraw(GtkWidget ♦widget, GdkEvent *event,gpointer data) {
gint x;
gint y;
gint width = HORIZ ♦ 2;
gint height = VERT;
x = HORIZ;
у = VERT;
gdk_draw_rectangle(widget->window, widget->style->black_gc, FALSE, x,y, width,height);
x = HORIZ ♦ 4;
gdkdrawrectangle(widget->window, widget->style->white_gc, TRUE, x,y, width,height);
x = HORIZ * 7;
gdk_draw_rectangle(widget->window, widget->style->white_gc, TRUE, x,y, width,height);
7374757673747576return(TRUE)return(TRUE)gdkdrawrectangle(widget->window, widget->style->black_gc, FALSE, x,y, width,height);
73
74
75
76
73
74
75
76
return(TRUE)
return(TRUE)
} gint eventDelete(GtkWidget *widget, GdkEvent *event,gpointer data) {
77гeturn(FALSE);
78 }
79 gint eventDestroy(GtkWidget *widget,
80GdkEvent *event,gpointer data) {
81gtk_main_quit();
82return(O);
83 }
На рис. 10.4 представлены прямоугольники, нарисованные в результате выполнения приведенной программы. Все они рисуются с помощью функции gdk_draw_rectangle{), параметрами которой являются координаты х и у верхнего левого угла и высота и ширина прямоугольника.
Рисунок 10.4.
Прямоугольники могут быть заполнены или обведены
Прямоугольник слева рисуется с помощью обращения к функции gdk__draw_rectangle () в строке 48. Используется встроенный черный объект GdkGC, и третий параметр установлен равным FALSE, а это означает, что прямоугольник не залит, лишь обведен его контур. Прямоугольник в центре окна рисуется таким же образом, как и левый, за исключением того, что используется встроенный белый объект GdkGC и опция заливки (заполнения) установлена равной TRUE.
Третий прямоугольник в окне в действительности рисуется дважды. Путем обращения к gdk_dr aw__rec tangle () в строке 62 выполняется заливка прямоугольника белым цветом, а вызов функции в строке 67 рисует вокруг него черный контур.
Рисование прямоугольников в X несколько непривычно. Контуры прямоугольников на один пиксел шире и выше, чем залитые прямоугольники. Их верхние и левые стороны находятся в одном и том же месте, а нижние и правые стороны выступают на один пиксел. Если требуется обвести залитый прямоугольник, то вы должны рисовать контур в последнюю очередь. В противном случае заливка закрывает верхнюю и левую стороны контура, а нижняя и правая сторона остаются видимыми.
ПРИМЕЧАНИЕ
Одна из особенностей, которая с самого начала была встроена в X, заключается в том, что обведенные прямоугольники больше залитых. Используется следующая концепция рисования: координаты задают точку между пикселами, и весь процесс рисования в этой точке происходит на пиксел ниже и правее заданных координат. В большинстве случаев это работает, как и ожидалось, но разница в размерах в один пиксел позволяет определить граничные по координатам пикселы заливки и пикселы, нарисованные при обводке.
Рисование и заливка полигонов
Полигон может быть нарисован по набору точек. Эти точки хранятся в массиве структур GdkPoint — таком же, как и при рисовании по отдельным пикселам, которое было описано ранее в данной главе. Функция gdk_draw_polygon () рисует отрезок прямой
от первой точки до второй, затем до третьей и так далее до последней точки. Затем, чтобы замкнуть полигон, рисуется отрезок от последней точки к первой. В приведенном ниже примере, чтобы продемонстрировать результаты заливки и обводки контура, один и тот же полигон рисуется различными способами.
/*♦ polygons.с ♦♦/
linclude <gnome.h>
3
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
gboolean eventDraw(GtkWidget *widget,
GdkEvent *event,gpointer data);
10
Idefine HORIZ 20
Idefine VERT 20
Idefine WIDTH (HORIZ ♦ 29)
Idefine HEIGHT (VERT ♦ 9)
15
16 static GdkPoint points[] = {
17
{ 80, 20 },
18
{ 20, 80 },
19
{ 40, 80 },
20
{ 60, 120 },
21
{ 20, 160 },
22
{ 80, 140 },
23
{ 140, 160 },
24
{ 100, 120 },
25
{ 120, 80 },
26
{ 140, 80 },
27
};
28
29
int main(int argc,char *argv[])
30 {
GtkWidget *app;
GtkWidget *area;
33
34gnome_init("polygons","1.0",argc,argv);
35app = gnome_app_new("polygons","Drawing Polygons");
gtk_signal_connect(GTK_OBJECT(app),"delete_event",
GTK_SIGNAL_FUNC(eventDelete),NULL);
gtk_signal_connect(GTK_OBJECT(app),"destroy",
GTK_SIGNAL_FUNC(eventDestroy),NULL);
40
area = gtk_drawing_area_new();
gtk_widget_set_usize(area,WIDTH,HEIGHT);
gnome_app_set_contents(GNOME_APP(app),area);
44
gtk_signal_connect(GTK_OBJECT(area),"event",
6GTK_SIGNAL_FUNC(eventDraw),NULL);
47
gtk_widget_show_all(app);
gtk_main();
50exit(0);
51 }
52 gboolean eventDraw(GtkWidget *widget,
53545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001015354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101GdkEvent ♦event,gpointer data) { gint i;
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
GdkPoint *p = malloc(sizeof(points));
gint pointcount = sizeof(points)/sizeof(GdkPoint);
for(i=0; i<pointCount; i++) { p[i].x = points[i].x; P[i]-Y = points[i].у;
gdk_draw_polygon(widget->window, widget->style->black_gc, FALSE,
P, pointcount);
for(i=0; i<pointCount; i++) p[i].x += 140;
gdk_draw_polygon(widget->window, widget->style->white_gc, TRUE,
Pr pointcount);
for(i=0; i<pointCount; i++) p[i].x += 140;
gdk_draw_polygon(widget->window, widget->style->black_gc, FALSE,
Pr pointcount);
gdk_draw_polygon(widget->window, widget->style->whitegc, TRUE,
Pr pointcount);
for(i=0; i<pointCount; i++) p[i].x += 140;
gdkdrawpolygon(widget->window, widget->style->white_gc, TRUE,
Pr pointcount); gdk_draw_polygon(widget->window, widget->style->black_gc, FALSE,
Pr pointcount);
102free(p);
103return(TRUE);
104 }
105 gint eventDelete(GtkWidget *widget,
106GdkEvent *event,gpointer data) {
107 return(FALSE);
108 }
109 gint eventDestroy(GtkWidget *widget,
110GdkEvent *event,gpointer data) {
111 gtk_main_quit();
112 return(O);
113 }
Сам полигон задается массивом points в строке 16. Эта форма используется для рисования всех полигонов, поэтому функция, которая выполняет само рисование — eventDraw() из строки 52 — должна скопировать массив точек и пересчитать координаты для перемещения полигона из одного положения в другое. Рабочая копия массива создается в строке 55, а общее количество точек в массиве вычисляется в строке 56. Исходный массив копируется в цикле, который начинается со строки 58. Функция eventDraw() может вызываться любое количество раз, поэтому важно освобождать и возвращать обратно системе выделяемую память, что и делается в строке 102 при обращении к функции free ().
Полигон слева на рис. 10.5 рисуется вызовом gdk_draw_polygon() в строке 62. Используется встроенный черный объект GdkGC. Параметр заливки установлен в значение FALSE, то есть выполняется только обводка контура.
Цикл, начинающийся в строке 68, перемещает рабочий полигон влево на 140 пикселов, просто добавляя 140 ко всем значениям х в массиве. Путем вызова gdk_draw_polygon () в строке 70 рисуется заполненный полигон, и при этом используется встроенный белый объект GdkGC.
Рисунок 10.5.Залитые и обведенные полигоныРисунок 10.5.Залитые и обведенные полигоны
Рисунок 10.5.
Залитые и обведенные полигоны
Рисунок 10.5.
Залитые и обведенные полигоны
В строках с 76 по 87 координаты массива перемещаются вправо и рисуются два полигона. Первый из них обводится черной линией, а второй — заполняется белой заливкой. Для полигонов справедливо то же, что и для прямоугольников: контур слегка превышает залитую форму. Как и в случае с прямоугольниками, вертикальные правые и горизонтальные нижние стороны контура выступают на один пиксел соответственно правее и ниже, чем у заливки. Как видно по третьему полигону на рисунке, в некоторых местах заливка закрывает контур, а в других — нет.
В правом полигоне, нарисованном в строках с 89 по 100, сначала выполняется заливка, а потом обводка контура. В этом случае контур полигона виден полностью.
Рисование окружностей, эллипсов и дуг
Приведенная ниже программа демонстрирует рисование и заполнение криволинейных фигур. Для рисования окружностей и эллипсов используется одна и та же функция, ведь окружность — это просто эллипс с равными высотой и шириной. Эта функция также позволяет ограничиться рисованием только части окружности или эллипса. Кроме того, можно рисовать только контур фигуры или заполнить при рисовании область фигуры, или залить ее.
/♦* arcs.с **/
Iinclude <gnome.h>
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
gboolean eventDraw(GtkWidget *widget,
GdkEvent *event,gpointer data);
static void drawArcs(GtkWidget *widget,gint у,gint fill);
11
Idefine WIDTH 455
fdefine HEIGHT 140
14
int main(int argc,char *argv[])
{
GtkWidget *app;
GtkWidget *area;
19
gnome_init("arcs", "1.0",argc,argv);
app = gnome_app_new("arcs",
"Drawing Circles and Ellipses");
23gtk_container_set_border_width(GTK_CONTAINER(app), 20);
gtk_signal_connect(GTK_OBJECT(app),"delete_event*,
GTKSIGNALFUNC(eventDelete),NULL);
gtk_signal_connect(GTK_OBJECT(app),"destroy",
GTK_SIGNAL_FUNC(eventDestroy),NULL);
28
area = gtk_drawing_area_new();
gtk_widget_set_usize(area,WIDTH,HEIGHT);
gnome_app_set_contents(GNOME_APP(app),area);
32
gtk_signal__connect(GTK_OBJECT(area),"event",
GTKSIGNALFUNC(eventDraw),NULL);
35
gtk_widget_show_all(app);
gtk_main();
exit(0);
}
gboolean eventDraw(GtkWidget *widget,
GdkEvent *event,gpointer data) {
42
drawArcs(widget,0,FALSE);
drawArcs(widget,80,TRUE);
return(TRUE);'
}
static void drawArcs(GtkWidget *widget,gint y,gint fill)
{
49gdk_draw_arc(widget->window,
50widget->style->black_gc,
51fill,
520,y,
5360,60,
540,360 ♦ 64);
55gdk_draw_arc(widget->window,
56widget->style->black_gc,
57fill,
5880,y,
5960,60,
60135 ♦ 64,90 * 64);
61gdk_draw_arc(widget->window,
62widget->style->black_gc,
63fill,
64НО,у,
6560,60,
66135 ♦ 64,-270 ♦ 64);
67
68gdk__draw__arc(widget->window,
69widget->style->black_gc,
70fill,
71190,у,
72100,60,
730,360 ♦ 64);
74gdk_draw_arc(widget->window,
75widget->style->black_gc,
76fill,
77310,y,
78100,60,
79135 ♦ 64,90 ♦ 64);
80gdk_draw_arc(widget->window,
81widget->style->black_gc,
82fill,
83350,y,
84100,60,
85135 ♦ 64,-270 ♦ 64);
86 }
87 gint eventDelete(GtkWidget *widget,
88GdkEvent *event,gpointer data) {
89return(FALSE);
90 }
91 gint eventDestroy(GtkWidget *widget,
92GdkEvent *event,gpointer data) {
93gtk_main_quit();
94return(O);
95 }
Функция eventDraw() в строке 40 вызывается всякий раз, когда область для рисования выходит на передний план. Само рисование выполняется при обращении к drawArcs (). Верхний ряд на рис. 10.6 выполняется путем вызова функции drawArcs () в строке 43, а второй ряд — функции drawArcs () в строке 44. Первый аргумент функции — виджет области для рисования. Второй аргумент — смещение по оси у. Третий аргумент указывает, нужна ли заливка.
Рисунок 10.6.
Залитые и обведенные, полные и неполные дуги
При обращении к gdk_draw_arc () в строке 49 рисуется полная окружность в верхнем левом углу области для рисования. Первый и второй аргументы — это окно и графический контекст. Следующий аргумент равен TRUE, если фигура заливается, и FALSE — в противном случае. Два следующих аргумента — координаты хиу окружности. Эти коор-
динаты задают положение верхнего левого угла прямоугольника, ограничивающего окружность или эллипс. Два следующих аргумента—ширина и высота этого прямоугольника.
Предпоследний аргумент функции gdk_draw_arc () — это угол, с которого начинается рисование дуги. Последний аргумент указывает длину дуги. Углы измеряются целыми значениями, единица измерения равна 1/64 градуса. Углы отсчитываются в декартовой системе координат с началом отсчета, лежащим справа, положительное направление отсчета — против хода часовой стрелки.
Принципы рисования дуг представлены на рис. 10.7. Здесь рисование дуги начинается с 45° и происходит против часовой стрелки на 270°, то есть окончание дуги находится в точке, отстоящей от начала на 315°. Можно задавать и отрицательные значения для одного или обоих углов. Отрицательное значение начальной точки отсчитывается слева и движение происходит по ходу часовой стрелки. Например, приведенную на рис. 10.7 дугу можно нарисовать другим способом, используя в качестве начального угла -(45*64), и отмерять количество нарисованных градусов значением -(270*64). Полученная дуга аналогична показанной на рисунке, но рисовалась в противоположном направлении.
Рисунок 10.7.Дуга задается двумя угламиРисунок 10.7.Дуга задается двумя углами
Рисунок 10.7.
Дуга задается двумя углами
Рисунок 10.7.
Дуга задается двумя углами
В нижнем ряду на рис. 10.6 показан тот же набор фигур, что и в верхнем ряду, но выполненных заливкой. Для замкнутой окружности или эллипса контур описывает ту же фигуру, что и заливка. Если окружность или эллипс не замкнуты, часть контура просто не прорисовывается в то время, как заливка производится в области, ограниченной дугой и прямыми, соединяющими конечные точки дуги с ее центром.
Рисование текста
Существуют две функции, предназначенные для рисования строк символов в области для рисования. Обе на входе требуют массив символов, но одна из функций рисует полную строку, а вторая — только выбранную часть строки.
/** text.с ♦*/
linclude <gnome.h>
3
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
gboolean eventDraw(GtkWidget *widget,
GdkEvent *event,gpointer data);
static void mark(GtkWidget *widget,gint x,gint y);
11
Idefine WIDTH 420
Idefine HEIGHT 140
14
int main(int argc,char *argv[])
{
GtkWidget *app;
GtkWidget *area;
19
gnome_init("text","1.0",argc,argv);
app * gnome_app_new("text","Drawing Text");
gtk_signal_connect(GTK_OBJECT(app),"deleteevent",
GTK_SIGNAL_FUNC(eventDelete),NULL);
gtk_signal_connect(GTK_OBJECT(app),"destroy",
GTK_SIGNAL_FUNC(eventDestroy),NULL);
26
area = gtk_drawing_area_new();
gtk_widget_set_usize(area,WIDTH,HEIGHT);
gnome_app_set_contents(GNOME_APP(app),area);
30
gtk_signal_connect(GTK_OBJECT(area),"event",
GTK_SIGNAL_FUNC(eventDraw),NULL);
33
gtk_widget_show_all(app);
gtk_main();
exit(0);
}
gboolean eventDraw(GtkWidget *widget,
GdkEvent *event,gpointer data) {
static gchar outString[] =
"every character in the string is displayed";
GdkFont *font;
43
font = gdk_font_load("vga");
gdk_draw_string(widget->window,
font,
widget->style->black_gc,
4850,50,
outString);
gdk_font_unref(font);
mark(widget,50,50);
52
53font ^ gdk_font_load("10x20");
5 4gdkdrawtext(widget->window,
55font,
56widget->style->black_gc,
5750,80,
58&outString[19],
5923);
60gdkfontunref(font);
61mark(widget,50,80);
62
63font = gdk_font__load( "12x24" );
64gdkdrawtext(widget->window,
65font,
66widget->style->black_gc,
6750,110,
686outString[6],
699);
70gdkfontunref(font);
71mark(widget,50,110);
72
73return(TRUE);
74 }
75 static void marк(GtkWidget *widget,gint x,gint y)
76 {
77gdkdrawline(widget->window,
78widget->style->white_gc,
79x - 5,y,
80x + 5,y);
81gdk_draw_line(widget->window,
82widget->style->white_gc,
83x,y-5,
84x,y+5);
85 }
86 gint eventDelete(GtkWidget *widget,
87GdkEvent ♦event,gpointer data) {
88return(FALSE);
89 }
90 gint eventDestroy(GtkWidget *widget,
91GdkEvent *event,gpointer data) {
92gtkmainquit();
93return(0);
94 }
В строках с 27 по 32 создается окно области для рисования, к которому подключается функция обратного вызова. Отображение текста выполняется функцией обратного вызова eventDraw(), которая начинается со строки 38. Строка символов out String объявлена в строке 40 как массив ASCII-символов, заканчивающийся нулем. Как показано на рис Л 0.8, строка и ее части отображаются с использованием трех различных шрифтов.
■ every character in the string is displayed . the string is displayedcharacter .■ every character in the string is displayed . the string is displayedcharacter .Рисунок 10.8.Строки и части строк, отображаемые в области для рисованияРисунок 10.8.Строки и части строк, отображаемые в области для рисования
■ every character in the string is displayed . the string is displayed
character .
■ every character in the string is displayed . the string is displayed
character .
Рисунок 10.8.
Строки и части строк, отображаемые в области для рисования
Рисунок 10.8.
Строки и части строк, отображаемые в области для рисования
В строках с 44 по 50 рисуется верхняя строка. Шрифт под названием vga выбирается в строке 44. Существуют сотни доступных шрифтов, с размером, цветом и стилем которых можно производить различные изменения. Описание шрифтов приведено в главе 13.
После использования объектов шрифтов ссылки на шрифты удаляются, чтобы освободить занимаемую память. Первый объект GdkFont создается при обращении к функции gdk_font_load() в строке 44. Как и всем новым объектам, ему назначается внутренний счетчик, установленный в значение 1. Затем в строке 45 шрифт передается функции gdk_draw_string(). Приложению ничего не известно о процессах, происходящих со шрифтом внутри функции рисования. Она может создавать новый объект, являющийся копией имеющегося (клонирование), может хранить указатель на передаваемый вами объект или может выполнять рисование без каких-либо ссылок на объект. Но благодаря внутреннему счетчику не имеет никакого значения, что именно делает функция рисования. Вызов функции gdk_f ont_unref () в строке 50 уменьшает внутренний счетчик на единицу, и объект шрифта удаляется, только если счетчик становится равным нулю. Объект шрифта остается только в случае, если функция рисования добавляет свою собственную ссылку на внутренний счетчик.
Функция gdk_draw_string () использует шрифт для рисования каждого символа строки, пока не встретит конец строки. Положение строки задается координатами х и у в строке 48.
Вовсе не обязательно, чтобы функция gdk_draw_text () из строки 54 начинала обработку с начала массива и использовала нулевой символ как признак конца строки. Аргументы в строках 58 и 59 указывают, что отображение должно начаться с 19-го символа массива и охватить максимум 23 символа. Функция gdk_draw_text() из строки 64 рисует подстроку, начиная с середины массива символов. В строках 68 и 69 устанавливается стартовое начало с шестого символа, а общее количество отображаемых символов равно девяти. •
После рисования каждой строки текста из строки 75 вызывается функция mark(), используемая для маркировки точки с координатами х и у, которая применяется при рисовании текста (маленькие белые крестики отмечают начало каждой строки текста). Таким образом, вы можете видеть, как расположена точка по отношению к рисуемому тексту. Понятие начала для текста отличается от этого же понятия для уже рассмотренных геометрических фигур: обычно начало фигуры располагается в верхнем левом углу. Для текста точка начала расположена в нижнем левом углу текста. Многие символы выравниваются снизу по горизонтальной линии, проходящей через начало текста, но у некоторых символов имеются подстрочные части (как, например, у или g), которые располагаются ниже этой линии. Кроме того, в некоторых специальных шрифтах начало первого символа может находиться левее точки начала, то есть точка начала будет находиться внутри символа, а не левее его. Все вышесказанное, а также вариации размеров пункта и отношений высоты и ширины могут вызвать сложности при размещении текста в окне. В главе 13 описаны методы, используемые для вычисления размеров и координат размещения и позволяющие вам правильно расположить текст.
Рисование цветных растровых изображений
Как говорилось в предыдущих главах, нарисовать растровый рисунок можно и без применения области для рисования, но с ней легче совместно использовать цветные растровые изображения и другие типы графики. В приведенном ниже примере рисуется цвет-
1 2
3 4
5 6
7
8
9
10 11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52 53
54
ное растровое изображение, а затем для создания аннотаций к нему используются другие типы области для рисования.
/** pixmap.с *♦/
♦include <gnome.h>
♦include "logo.xpm"
gint eventDelete(GtkWidget *widget, GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget, GdkEvent ♦event,gpointer data);
gboolean eventDraw(GtkWidget *widget, GdkEvent *event,gpointer data);
♦define WIDTH 500
♦define HEIGHT 300
int main(int argc,char *argv[]) {
GtkWidget *app;•
GtkWidget *area;
gnome^init("pixmap","1.0",argc,argv);
app = gnome_app_new("pixmap","Pixmaps Etcetera"); gtksignalconnect(GTKOBJECT(app),"deleteevent",
GTK_SIGNAL_FUNC(eventDelete),NULL);
gtk_signal_connect(GTKOBJECT(app),"destroy", GTK_SIGNAL_FUNC(eventDestroy),NULL);
area = gtk_drawing_area_new(); gtk_widget_set_usize(area,WIDTH,HEIGHT); gnome_app_set_contents(GNOME_APP(app),area);
gtk_signal_connect(GTK_OBJECT(area),"event", GTK_SIGNAL_FUNC(eventDraw),NULL);
gtk_widget_show_all(app);
gtk_main();
exit(0);
}
gboolean eventDraw(GtkWidget *widget,
GdkEvent *event,gpointer data) { GdkBitmap *mask;
GdkPixmap *pixmap;
GtkStyle *style;
GdkFont *font = gdk__font_load( "10x20");
static GdkPoint points[] = {
{ 210, 253 },
{ 220, 245 },
{ 220, 252 },
{ 295, 252 },
{ 295, 254 },
{ 220, 254 },
{ 220, 260 }, };
5555stylestyle= gtkwidgetgetstyle(widget);= gtkwidgetgetstyle(widget);
55
55
style
style
= gtkwidgetgetstyle(widget);
= gtkwidgetgetstyle(widget);
56575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131145657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114pixmap = gdk_pixmap_create_fгom_xpm_d(widget->window, &mask,&style->bg[GTK_STATE_NORMAL], (gchar **)logo);
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
gdk_draw_pixmap(widget->window, widget->style->black_gc, pixmap, 0,0, 0,0, 257,303);
gdk_draw_pixmap(widget->window, widget->style->black_gc, pixmap, 70,60, 210,50, 90,50);
gdk_draw_string(widget->window, font, widget->style->white_gc, 240,75, "Beak");
gdk_draw_pixmap(widget->window, widget->style->black_gc, pixmap, 0,200, 350,105, 100,100);
gdk_draw_string(widget->window, font, widget->style->black_gc, 350,210, "Right");
gdk_draw_string(widget->window, font, widget->style->black_gc, 300,260, "Left");
gdk_draw_polygon(widget->window,"
widget->style->black_gc, TRUE, points, sizeof(points) / sizeof(GdkPoint));
gdkpixmapunref(pixmap); gdk_font_unref(font);
return(TRUE);
}
gint eventDelete(GtkWidget *widget, GdkEvent *event,gpointer data) {
return(FALSE);
}
gint eventDestroy(GtkWidget *widget, ' GdkEvent *event,gpointer data) { gtk_main_quit();
return(0);
В строках с 28 по 33 создается окно области для рисования и присоединяется функция обратного вызова eventDraw(). Все рисование производится функцией обратного вызова, поэтому при выходе на передний план окно корректно перерисовывается. Картинка, изображающая пингвина (рис. 10.9), получена путем рисования трех областей цветного растрового изображения, трех текстовых строк и одного заполненного (залитого) полигона.
Рисунок 10.9.
Подогнанные растровые рисунки с текстом и полигон
Данные в формате ХРМ для цветного растрового рисунка берутся из файла logo.xpm, который включается в программу в строке 4. В строке 56 вызов функции gdk_pixmap_create_f rom_xpm_d() преобразовывает данные в формате ХРМ в объект GdkPixmap.
Вызов gdk_draw_pixmap() в строке 60 рисует полной цветное растровое изображение в области для рисования. Первые три аргумента определяют окно области для рисования, и, чтобы нарисовать GdkPixmap, используется GdkGC. Внутри функции само рисование производится путем копирования прямоугольника пикселов из цветного растрового изображения в окно, поэтому последние шесть аргументов соответственно являются координатами х и у источника, координатами х и у приемника, высотой и шириной копируемого прямоугольника. В строке 60 рисуется полное цветное растровое изображение и заданы координаты источника (0, 0). Чтобы поместить рисунок в верхний левый угол области для рисования, координаты приемника также установлены в значение (0, 0). Высота и ширина такие же, как определены в данных формата ХРМ.
ПРИМЕЧАНИЕ
Вам может показаться странным, что при обращении к функции gdk_draw_pixmap() в качестве аргумента требуется графический контекст, поскольку все размеры и цвета определяются растровым рисунком и другими аргументами. Оказывается, что в GdkGC имеются некоторые скрытые данные, необходимые низкоуровневой функции ХСоруАгеа(), которая копирует пикселы из одного места в другое.
Функция gdk_draw_pixmap() в строке 67 на входе использует тот же цветной растровый рисунок, но копирует только его небольшую часть. В строке 70 координаты верхнего левого угла копируемого прямоугольника устанавливаются в значение (70,60). Координаты верхнего левого угла приемника задаются в строке 71 равными (210,50). В строке 72 ширина прямоугольника устанавливается в значение 90 пикселов, и высота — 50 пикселов. В результате в окно копируется только небольшая область, окружающая клюв пинг
вина.
В области для рисования вы можете рисовать новые объекты поверх уже имеющихся. Вызов функции gdk_draw_string() в строке 73 размещает текст ’’Beak” поверх цветного растрового изображения, которое мы поместили туда ранее.
В строках с 79 по 89 в область для рисования копируется секция исходного черно-белого растрового изображения с правой лапкой, а затем с помощью еще одной строки текста добавляется тег, указывающий, что на рисунке изображена правая лапка. К левой лапке надпись добавляется в строках с 91 по 100. При помощи обращения к функции gdk_draw_string () рисуется текст. Функция gdk_draw_polygon () использует набор точек, заданный в строке 45, для рисования залитой стрелки, которая направлена от текста к лапке.
В строках 102 и 103 удаляются ссылки на растровое изображение и шрифт. Функция обратного вызова заново перестраивает цветное растровое изображение и шрифт при каждом своем вызове, поэтому нет особой необходимости хранить их постоянно, и, кроме того, без удаления можно вызвать дефицит памяти. В реальных приложениях имеет смысл хранить их в статических переменных, что позволяет использовать растровый рисунок и шрифт без полной перестройки.
ПРИМЕЧАНИЕ НАУЧНОГО РЕДАКТОРА
Хотя обычно термин bitmap подразумевает черно-белое растровое изображение, а pixmap — цветное растровое изображение, работе с цветом посвящена следующая глава, а в этой главе по сути демонстрируется работа с черно-белыми изображениями.
Изменение размеров области для рисования
Размеры области для рисования можно изменить в зависимости от того, что необходимо содержащимся в ней виджетам. Если вы игнорируете изменения размеров, ваш рисунок может содержать незаполненные области или оказаться обрезанным справа и снизу. Однако можно сделать так, чтобы ваш рисунок изменял свои размеры в соответствии с новой конфигурацией окна.
ПРИМЕЧАНИЕ
Написание кода, который бы изменял размеры рисунка, может оказаться слишком сложным. Чтобы размеры рисунка менялись, вам необходимо пересчитать все координаты в зависимости от отношения ширины окна к его высоте. Некоторые объекты, например, изображения в формате ХРМ и текстовые шрифты, не так легко изменить. И, кроме того, изменение отношения ширины к высоте превращает окружности в эллипсы, а квадраты в прямоугольники.
В приведенном ниже примере рисуются прямоугольники, размеры которых основываются на высоте и ширине окна и могут быть изменены.
/** configure.с **/
linclude <gnome.h>
3
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
gboolean eventDraw(GtkWidget *widget,
GdkEvent *event,gpointer data);
gboolean eventConfigure(GtkWidget *widget.
GdkEventConfigure *event,gpointer data);
12
static int width = 20;
static int height = 20;
15
int main(int argc,char *argv[])
{
GtkWidget *app;
GtkWidget *area;
20
gnome_init("configure",”1.0”,argc,argv);
app = gnome_app_new("configure","Resizing Rectangles");
gtk_signal_connect(GTK_OBJECT(app),"delete_event",
GTK_SIGNAL_FUNC(eventDelete),NULL);
gtk_signal_connect(GTKOBJECT(app),"destroy",
GTK_SIGNAL_FUNC(eventDestroy),NULL);
27
area = gtk_drawing_area_new();
gtk_widget_set_usize(area,width,height);
gnome_app_set_contents(GNOME_APP(app),area);
31
gtk_signal_connect(GTK_OBJECT(area),"expose-event",
GTK_SIGNAL_FUNC(eventDraw),NULL);
gtk_signal_connect(GTK_OBJECT(area),"configure-event",
GTK_SIGNAL_FUNC(eventConfigure),NULL);
36
gtk_widget_show_all(app);
gtk_main();
exit(0);
}
gboolean eventDraw(GtkWidget *widget,
GdkEvent *event,gpointer data) {
gint xDelta = width / 5;
gint yDelta = height / 5;
45
46gdk_draw_rectangle(widget->window,
47widget->style->white gc,
48TRUE,
490,0,
50width,height);
51
52 gdk_draw_rectangle(widget->window,
53widget->style->black_gc,
54TRUE,
55xDelta,yDelta,
56width - (2 ♦ xDelta),height - (2 * yDelta));
57
58xDelta *= 2;
59yDelta *= 2;
60gdkdrawrectangle(widget->window,
61widget->style->white_gc,
62TRUE,
63xDelta,yDelta,
64width - (2 * xDelta),height - (2 * yDelta));
65
66return(TRUE);
67 }
68 gboolean eventConfigure(GtkWidget *widget,
69GdkEventConfigure *event,gpointer data) {
70
71width = event~>width;
72height = event->height;
73
74return(TRUE);
75 }
76 gint eventDelete(GtkWidget *widget,
77GdkEvent *event,gpointer data) {
78return(FALSE);
79 }
80 gint eventDestroy(GtkWidget *widget,
81GdkEvent *event,gpointer data) {
82gtk_main_quit();
83return(O);
84 }
В строках с 28 по 30 создается область для рисования и включается в главное окно
приложения. При изменении главного окна изменяются и размеры области для рисования, к которой подключается функция обратного вызова в строках с 32 по 35. В случа
ях, когда рисунок нуждается в перерисовке своего содержимого, событие "exposе-
event" (можно "expose^event", попадание в экспозицию, или выход на передний план) вызывает функцию eventDraw(). В случаях, когда область для рисования изменяет свои размеры, событие "conf igure-event" (можно "conf igure-event", изменение конфигурации) вызывает функцию eventConfigure().
Рисунок 10.10. Прямоугольники меняют форму, подстраиваясь к размерам окнаРисунок 10.10. Прямоугольники меняют форму, подстраиваясь к размерам окнаРисование прямоугольников выполняется функцией обратного вызова eventDraw(), которая начинается в строке 41. Значения xDelta и yDelta, которые используются для вычисления размеров и положения прямоугольников, определяются в долях высоты и ширины. Вызов функции gdk_draw_rectangle () в строке 46 использует высоту и ширину для очистки всей области для рисования и создания белого фона. На основе значений xDelta и yDelta в строке 52 рисуется черный прямоугольник, а в строке 60 — белый. Поскольку все размеры вычисляются на основе размеров окна, то размеры всех прямоугольников пропорциональны размерам окна. На рис. 10.10 показано окно в четы-
Рисунок 10.10. Прямоугольники меняют форму, подстраиваясь к размерам окна
Рисунок 10.10. Прямоугольники меняют форму, подстраиваясь к размерам окна
рех видах: разные размеры и формы.
В строке 68 функция обратного вызова eventConf igure () вызывается при изменении конфигурации окна. В строках 71 и 73 определяются новые высота и ширина окна, которые хранятся до следующей перерисовки окна. Нет необходимости делать еще что- то, поскольку за событием "conf igure-event" всегда следует событие "expose
event" и вызывается функция eventDraw(), создающая на экране требуемую фигуру.
Занесение изображения в память и анимация
Иногда бывает удобно записывать графику в память, а не прямо рисовать в окне. Один из примеров такой ситуации — анимация, поскольку первый шаг при создании нового кадра — это очистка старого кадра. Если производить очистку прямо в окне, то изображе-
ние мигает на каждом кадре. К счастью, существует возможность нарисовать растровое изображение в памяти, а затем использовать для обновления всего окна за один раз.
Приведенная ниже программа демонстрирует простую анимацию: шарики падают сверху и отскакивают от низа окна, опускаясь все ниже и ниже, пока они не исчезают за левой или правой стороной окна.
/** animation.с **/
Iinclude <gnome.h>
Iinclude <math.h>
4
static struct ballStruct {
• 6doublex;
doubley;
doublexVelocity;
doubleyVelocity;
} ball[5);
11
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint nextFrame(gpointer data);
void newBall(struct ballStruct *b);
void nextBall(struct ballStruct *b);
19 gint nextFrame(gpointer data);
20
21 Idefine WIDTH 400
22 Idefine HEIGHT 300
23 Idefine GRAVITY 0.8
24 Idefine RADIUS 5
25 Idefine DIAMETER (RADIUS * 2)
26 Idefine INTERVAL 30
27
int main(int argc,char *argv[])
{
int i;
GtkWidget*app;
GtkWidget*area;
33
gnome_init("animation","1.0",argc,argv);
app = gnome_app_new("animation",
"Drawing Area Animation");
gtk_container_set_border_width(GTK_CONTAINER(app),20);
gtk_signal_connect(GTK_OBJECT(app),"delete_event",
GTK_SIGNAL_FUNC(eventDelete),NULL);
gtk_signal_connect(GTKOBJECT(app),"destroy",
GTK_SIGNAL_FUNC(eventDestroy),NULL);
42
area = gtk_drawing_area_new();
gtk_widget_set_usize(area,WIDTH,HEIGHT);
gnome_app_set_contents(GNOME_APP(app),area);
46
gtk_timeout_add(INTERVAL,nextFrame,area);
for(i=0; i<5; i++)
newBall(&ball[i]);
50
gtk_widget_show_all(app);
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
gtk_main(); exit(0);
}
gint nextFrame(gpointer data) {
int i;
static GdkPixmap *pixmap = NULL;
GtkWidget *widget = (GtkWidget *)data;
if(pixmap == NULL) { pixmap = gdk_pixmap_new(widget->window, WIDTH,HEIGHT,-1);
}
gdk_draw_rectangle(pixmap, widget->style->white_gc, TRUE, 0,0, WIDTH,HEIGHT);
for(i=0; i<5; i++) { nextBall(&ball[i]); gdk_draw_arc(pixmap, widget->style->black_gc, TRUE, (int)ball[i].x,(int)ball[i].y, DIAMETER,DIAMETER, 0,360*64);
}
gdk_draw_pixmap(widget->window, widget->style->black gc, pixmap, 0,0, 0,0, WIDTH,HEIGHT);
return(TRUE);
}
void newBall(struct ballStruct *b) { b->x = (((double)rand()*WIDTH)/RANDMAX); b->y = (((double)rand()*HEIGHT)/RAND_MAX) - HEIGHT; do {
b->xVelocity = (((double)rand()*10)/RANDMAX) - 5; b->yVelocity = (((double)rand()*10)/RAND MAX) - 5;
} while(fabs(b->xVelocity) < 0.5);
}
void nextBall(struct ballStruct *b) { if((b->x < -DIAMETER) || (b->X > WIDTH)) { newBall(b);
return;
}
if((b->y + DIAMETER) >= HEIGHT) { if(b->yVelocity > 0)
b->yVelocity = -b->yVelocity;
109
b->yVelocity *= 0.9;
110} else {
111b~>yVelocity += GRAVITY;
112}
113b->x+=b->xVelocity;
114b->y+=b->yVelocity;
115 }
116 gint eventDelete(GtkWidget *widget,•
117GdkEvent *event,gpointer data) {
118return(FALSE);
119 }
120 gint eventDestroy(GtkWidget *widget,
121GdkEvent *event,gpointer data) {
122gtk_main_quit();
123return(O);
124 }
В строках с 43 по 45 создается область для рисования и присоединяется к главному окну приложения. Поскольку отсутствуют события, которые нужно обрабатывать, то окно не связано ни с одной функцией обратного вызова. Вместо этого обращение к функции gtk_timeout_add() в строке 47 устанавливает интервальный таймер, который каждые 30 миллисекунд вызывает функцию nextFrame (). Функции nextFrame () передается указатель на виджет области для рисования. Цикл, начинающийся в строке 48, устанавливает начальные значения положения и скорости для каждого из пяти шариков.
Функция nextFrame (), которая начинается со строки 55, обновляет изображение для следующего кадра анимационной последовательности. Для этого ей нужно место, где она сможет выполнить создание нового кадра. В результате в строке 61 создается растровое изображение. Само изображение в строке 58 объявлено статическим, то есть его необходимо создать только первый раз до выхода из функции, а затем для рисования каждого кадра повторно использовать одно и то же изображение. Перед началом рисования кадра необходимо очистить изображение предыдущего кадра. Обращение к функции gdk_draw_rectangle() в строке 66, использующее белый графический контекст и полные ширину и высоту, заполняет весь рисунок белым цветом.
Цикл, который начинается со строки 72, выполняется по одному разу для каждого из пяти шариков. Для вычисления нового положения каждого шарика вызывается функция nextBall(), а с помощью функции gdk_draw_arc() в изображении рисуется залитая окружность. Каждый шарик перемещается и рисуется отдельно, пока растровое изображение держит кадр, содержащий все шарики в их позициях в отображаемом окне на один шаг вперед. Обращение к функции gdk_draw_pixmap() в строке 82 переносит весь растровый рисунок в окно, которое благодаря одинаковым размерам всех кадров, полностью перерисовывается за один раз. Для следующего экрана полный кадр обновляется за один раз, а не по частям, как это происходит в памяти.
# Функция newBall(), начинающаяся со строки 91, сохраняет набор случайных значений для задания начального положения и скорости шариков. Генератор случайных чисел используется для расположения шариков между левой и правой сторонами окна и несколько выше верхней границы окна. Рисовать можно и за границами окна или растрового рисунка, просто в таком случае рисунок не виден, но таким способом удобнее рисовать объекты, которые видны не полностью, чем вычислять, какая часть объекта не видна. Каждый шарик, как определено в структуре в строке 5, имеет четыре установки. Причем х и у — это координаты его расположения в окне, с точкой отсчета в верхнем левом углу. Значения xVelocity и yVelocity задают скорость движения шарика. Для вы-
числения нового положения шарика эти параметры добавляются к текущим значениям х и у. Падающий шарик имеет положительную скорость yVelocity, а поднимающийся — отрицательную yVelocity. Шарик, движущийся слева направо, имеет положительную скорость xVelocity, движущийся справа налево — отрицательную xVelocity.
Функция nextBall() в строке 100 перемещает шарик из одного положения в другое. Вспомните, что координаты х и у отсчитываются от верхнего левого угла рисуемых фигур, следовательно, для вычисления координат правой и нижней сторон шарика необходимо к ним добавить значение DIAMETER. Если проверка в строке 102 показывает, что шарик полностью вышел за левую или правую границу окна, то функция newBall () создает вместо него новый шарик. В строке 106 определяется, достиг ли шарик нижней границы окна, и если это условие выполняется, то в строке 108 меняется знак скорости. При отскоке шарик теряет энергию, поэтому его скорость уменьшается на 10%. Если шарик находится не на нижней стороне окна, то к его скорости в строке 111 добавляется GRAVITY. Это замедляет отскакивающий шарик и ускоряет падающий. И, наконец, в строках 113 и 114 для вычисления новых координат х и у используются текущие значения скорости.
Выводы
Существует довольно большое количество базовых операций, которые дают вашему приложению низкоуровневый доступ к пикселам, составляющим окно. Некоторые из этих операций настолько низкого уровня, что они просто предназначаются для функции от Xlib. Другие операции, как, например, функций GTK+, описанных в настоящей главе, действуют как высокоуровневые и позволяют:
В Вашей программе рисовать в окне по одному пикселу за раз. Каждый пиксел имеет свое положение и цвет.
й Рисовать отдельную линию или серию соединенных линий, рисуя их по отрезкам.
6 С помощью набора специальных функций создавать прямоугольники, квадраты, окружности, эллипсы и дуги. Имеется также общая функция для рисования полигона, с помощью которой можно рисовать любые другие фигуры. Все фигуры могут быть либо обведенные, либо залитые.
^ Использовать тот же набор примитивов для рисования растрового изображения в памяти, а не на экране дисплея. Растровое изображение в памяти может использоваться для создания рисунков на всем окне или на его части. Оно особенно полезно при создании анимации, поскольку рисование деталей происходит в фоновом режиме и полное окно на экране обновляется за один раз.
ф Программно изменять размеры рисунка в окне при изменении вами размеров области для рисования.
И все-таки в этой главе вся графика по сути отображалась как черно-белая. В следующей главе описано применение цвета в различных ситуациях, начиная от заливки полигонов и заканчивая рисованием текста. Ваша программа может выбрать и загрузить точный цвет или выбрать из уже загруженных цветов ближайший к тому, который вы хотите.
ГЛАВА11 dot ii rnoftii iiioryi 111
■Цое? I U I potJJUMcXIMLlU
4 4 контекст
В этой главе
' Инкапсулированный цвет и другая информация в составе графического контекста
Использование графического контекста при определении шаблонов для рисования и цветов
Манипулирование содержимым и конфигурационными установками графического контекста
Размещение цвета для использования вашей программой
: Выбор уже размещенного цвета
Эта глава посвящена описанию цвета и других конфигурационных установок для рисования. Цвета хранятся в графическом контексте, который используется для прорисовки пикселов в окне виджета. Кроме того, в графическом контексте содержатся установки, которые управляют видом и формой рисуемых линий. Можно заполнить область в окне сплошным цветом, прозрачным рифленым цветом или даже полноцветным растровым изображением (pixmap).
Закрашивать виджеты очень просто, но надо понимать модель цвета и принципы управления. Вот собственно о чем эта глава. Существует широкий диапазон цветовых возможностей с различными доступными опциями "железа”, но модель цвета в системе X позволяет легко разобраться во всем этом. При работе с цветом именно вы решаете, какой цвет хотите, и передаете его в вашу систему, а вот система или использует выбранный вами цвет, или выбирает другой, наиболее подходящий.
Архитектура цвета
X Window использует цветовую систему с каждым из трех основных цветов, представленных двоичным значением. Интенсивность каждого цвета — это отношение значения цвета к максимально возможному значению. Например, чтобы получить пятидесятипроцентный красный цвет в системе, где выделяется 8 бит на цвет, значение цвета должно равняться 127. А в системе, где на цвет выделено 16 бит, это же значение должно равняться 32767. Цвета также могут определяться значениями с плавающей запятой (или точкой, как принято говорить на западе) обычно в диапазоне от 0.0 до 1.0, поэтому уровень пятидесятипроцентного цвета должен равняться 0.5.
Существует несколько различных видов архитектур отображения. Система X Window использует стандартный метод взаимодействия с ними. Программное обеспечение GNOME/GTK+ выстроено на вершине этой обобщенной системы, так что вам наверняка никогда не потребуется знать все низкоуровневые детали (разве только тогда, когда потребуется делать что-то очень специальное). Однако ряд операций в вашей программе обретут больший смысл, если вы будете иметь представление о том, что происходит в основе этой обобщенной системы.
Для каждого пиксела, отображаемого на экране дисплея, существует область сохранения его местоположения. Содержание компонентов области сохранения определяют цвет и яркость связанных с ними пикселов: изменение пикселов вызывает изменение содержимого в этой области. Оборудование использует различные методы конвертирования сохраняемых значений в цвет: в то время как одни его виды используют числовые значения и напрямую конвертируют их в цвет, другие используют хранимые значения как индекс в таблице цветов. Эта таблица цветов известна как карта цветности (color тар). Различное оборудование требует различные виды карт. В табл. 11.1 описаны различные типы дисплеев.
Таблица 11.1. Классы дисплеев
Наименование
Описание
Pseudo Color
Значение пиксела индексирует карту цветности, содержащую RGB- значения. Карта цветности может быть динамически модифицирована.
Kirect Color
Значение пиксела разделяется на три составляющих и используется для индексации трех различных карт цветности: по одной для компонентов красного (Red), зеленого (Green) и синего (Blue) цветов. Карты цветности могут быть динамически модифицированы.
Gray Scale
Значение пиксела индексирует карту цветности, содержащую отображаемые значения в градациях серого. Карта цветности может быть динамически модифицирована.
Static Color
Значение пиксела индексирует карту цветности, содержащую RGB- значения. Карта цветности оборудования статична и не может быть
изменена.
True Color
Значение пиксела разделяется на три составляющих и используется для индексации трех различных карт цветности: по одной для компонентов красного, зеленого и синего цветов. Каждая из карт цветности — это равномерный (или почти равномерный) переход от отсутствия цвета к полной насыщенности; карты цветности не могут быть переделаны.
Static Gray
Значение пиксела индексирует карту цветности, содержащую отображаемые значения в градациях серого. Карта цветности статична и не может быть изменена.
Карта цветности используется оборудованием дисплея для раскрашивания всех пикселов во всех окнах, поэтому изменение карты цветности приводит к изменениям отображения всех деталей. Некоторые карты цветности позволяют производить такие изменения, а другие — нет. Иногда, хотя и редко, необходимо произвести изменение карты цветности, но если ваше приложение меняет карту цветности, то будет правильным вернуть назад значения оригинальной карты, когда вы утратили фокус при переходе к другому приложению.
Следующая программа расскажет о типе вашего дисплея, количестве бит на пиксел, размере карты цветности и некоторых других компонентах, имеющих отношение к этой теме.
/** visual.с **/
Iinclude <gnome.h>
3
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
8
int main(int argc,char *argv[])
{
GtkWidget *app;
GtkWidget *label;
GdkVisual *visual;
gchar work[80];
gchar text[4096];
16
17gnome_init("visual","1.0",argc,argv);
app = gnome_app_new("visual","GdkVisual");
gtk_container_set_border_width(GTKCONTAINER(app),30);
gtk_signal_connect(GTKOBJECT(app),"delete_event",
GTK_SIGNAL_FUNC(eventDelete),NULL);
gtk_signal_connect(GTK_OBJECT(app),"destroy",
GTK_SIGNAL_FUNC(eventDestroy),NULL);
24
visual = gdk_visual_get_system();
26
sprintf(text,"Type: ");
switch(visual->type) {
case GDKVISUALSTATICGRAY:
strcat(text,"Static GrayXn");
break;
caseGDK_VISUAL_GRAYSCALE:
strcat(text,"GrayscaleXn");
break;
caseGDK_VISUAL_STATIC_COLOR:
strcat(text,"Static Color\n");
break;
caseGDK_VISUAL_PSEUDO_COLOR:
strcat(text,"Pseudo Color\n");
break;
caseGDK_VISUAL_TRUE_COLOR:
strcat(text,"True ColorXn");
break;
case GDKVISUALDIRECTCOLOR:
strcat(text,"DirectColorXn");
break;
}
sprintf(work,"Depth (number ofbits per pixel): %d\n",
visual->depth);
streat(text,work);
streat(text,"Byte order;");
switch(visual->byte_order){
case GDK_LSB_FIRST:
strcat(text,"LSB firstXn");
break;
56575859606162636465666768697071727374757677787980815657585960616263646566676869707172737475767778798081Type: True ColorDepth (number of bits per pixel) 15Byte order: LSB firstType: True ColorDepth (number of bits per pixel) 15Byte order: LSB firstSize of colormap array: 32Colormap bits per RGB: 5Color Mask Shift Bitsred0x00007C00105greenОхОООООЗЕО55blue0x0000001 F05Size of colormap array: 32Colormap bits per RGB: 5Color Mask Shift Bitsred0x00007C00105greenОхОООООЗЕО55blue0x0000001 F05Рисунок 11.1.Характеристики и возможности дисплеяРисунок 11.1.Характеристики и возможности дисплея
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
Type: True Color
Depth (number of bits per pixel) 15
Byte order: LSB first
Type: True Color
Depth (number of bits per pixel) 15
Byte order: LSB first
Size of colormap array: 32
Colormap bits per RGB: 5
Color Mask Shift Bits
red0x00007C00105
greenОхОООООЗЕО55
blue0x0000001 F05
Size of colormap array: 32
Colormap bits per RGB: 5
Color Mask Shift Bits
red0x00007C00105
greenОхОООООЗЕО55
blue0x0000001 F05
Рисунок 11.1.
Характеристики и возможности дисплея
Рисунок 11.1.
Характеристики и возможности дисплея
case GDK_MSB_FIRST: strcat(text,"MSB firstXn"); break;
}
sprintf(work,"\nSize of colormap array: %d\n", visual->colormap_size);
strcat(text,work);
sprintf(work,"Colormap bits per RGB: %d\n", visual->bits_per_rgb);
strcat(text,work);
strcat(text, "XnColorMaskShift BitsXn");
sprintf(work," red 0x%08X%2d%2d\n",
visual->red__mask, visual->red_shif t, visual->red_prec);
strcat(text,work);
sprintf(work,"green 0x%08X%2d%2d\n",
visual->green_mask,visual->green_shift, visual->green_prec);
strcat(text,work);
sprintf(work," blue 0x%08X%2d%2d\n",
visual->blue_mask,visual->blue_shiftr visual->blue_prec);
strcat(text,work);
82label = gtk_label_new(text);
83gtk_label_set_justify(GTK_LABEL(label),
84GTK_JUSTIFY_LEFT);
85gtk_misc_set_padding(GTK_MISC(label),GNOME_PAD,0);
86
87 gnomeappset contents(GNOMEAPP(app),label);
88
89 gtk_widget_show_all(app);
90gtk_main();
91exit(0);
92 }
93 gint eventDelete(GtkWidget *widget,
94GdkEvent *event,gpointer data) {
95 return(FALSE);
96 }
97 gint eventDestroy(GtkWidget *widget,
98GdkEvent *event,gpointer data) {
99gtk_mainquit();
100return(0);
101 }
Обращение к gdk_visual_get_system() в строке 25 возвращает структуру GdkVisual, содержащую информацию о системном дисплее. Данные от дисплея форматируются как текстовые в строках с 27 по 80. В строках с 82 по 87 текст включается в метку, а метка (надпись) включается в окно приложения.
Результирующий дисплей одной из систем показан на рис. 11.1. Эта система имеет дисплей True Color, в котором предусмотрено для отображения цветности 15 бит
на пиксел. Имеется 32 значения красного цвета, 32 значения синего и 32 зеленого в трех массивах карт цветности. Это означает, что всего доступно 32768 цветов. Для определения, например, красного компонента цвета проводится сложение бит красной маски и бит значения пиксела, а результат сдвигается на 10 бит вправо. Результирующее 5-ти битное число:— это индекс внутри красной карты цветности.
Графический контекст
Весь процесс рисования проходит в соответствии с хранимыми значениями в объекте GdkGC — графическом контексте. В графическом контексте имеется два цвета: один для раскрашивания переднего плана и один для фона (совместно с несколькими другими компонентами). Имеются также установки, определяющие толщину рисуемых линий, их стиль, типы углов, полученных при объединении отрезков линий, область усечения, маски покрытия и гравировки пунктиром, правила заливки и т.д.
Конечно, имеются специальные исключения (цвета переднего плана и фона), но, в основном, содержимое графического контекста не может быть адресовано напрямую. Однако его можно копировать в двух направлениях с использованием структуры GdkGCValues:
struct _GdkGCValues {
GdkColor foreground;
GdkColor background;
GdkFont *font;
GdkFunction function;
GdkFill fill;
GdkPixmap *tile;
GdkPixmap *stipple;
GdkPixmap *clip_mask;
GdkSubwindowMode subwindowmode;
gint ts_x_origin;
gint ts_y_origin;
gint clip_x_origin;
gint clip_y_origin;
gint graphics_exposures;
gint line_width;
GdkLineStyle line_style;
GdkCapStyle cap_style;
GdkJoinStyle join_style;
};
В следующем примере из окна выбирается графический контекст и отображается информация о его содержимом. Здесь не только выводятся значения, хранящиеся в GdkGC, но и демонстрируются значения, доступные для каждого поля.
/** showgc.c **/
Iinclude <gnome.h>
3
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint listvalues(gpointer data);
static char *functionString(GdkFunction function);
static char *fillString(GdkFill fill);
static char *subwindowString(GdkSubwindowMode mode);
static char *lineStyleString(gint style);
static char *capStyleString(gint style);
14 static char *joinStyleString(gint style);
15
16 fdefine WIDTH 40
17 fdefine HEIGHT 30
18
int main(int argc,char *argv[])
{
GtkWidget *app;
GtkWidget *area;
23
gnome_init("showgc","1.0",argc,argv);
app = gnome_app_new("flasher","Listing GC");
gtk_signal_connect(GTK_OBJECT(app),"delete_event",
GTK_SIGNAL_FUNC(eventDelete),NULL);
gtk_signal_connect(GTK_OBJECT(app),"destroy",
GTK_SIGNAL_FUNC(eventDeStroy),NULL);
30
area = gtk_drawing_area_new();
gtk_widget_set_usize(area,WIDTH,HEIGHT);
gnome_app_set_contents(GNOME_APP(app),area);
gtk_signal_connect(GTK_OBJECT(app),"realize" ,
GTK_SIGNAL_FUNC(listvalues),area);
36
gtk_widget_show_all(app);
gtk_main();
exit(0);
}
gint listvalues(gpointer data)
{
GtkWidget *widget= GTK_WIDGET(data);
GdkGC *gc;
GdkGCValues gcv;
46
gc = widget->style->white_gc;
gdk_gc_get_values(gc,6gcv);
49
50printf("foreground RGB: %u %u%u (0x%08X)\n",
gcv.foreground.red,gcv.foreground.green,
gcv.foreground.blue,(guint)gcv.foreground.pixel);
printf("background RGB; %u %u %u (0x%08X)\n",
gcv.background.red,gcv.background.green,
gcv.background.blue,(guint)gcv.background.pixel);
printf("font id: %d ascent: %d descent: %d\n",
gdkfontid(gcv.font),
gcv.font->ascent,gcv.font->descent);
printf("pixel drawing function: %s\n",
functionstring(gcv.function));
printf("fill method: %s\n",fillString(gcv.fill));
printf("subwindow mode: %s\n",
subwindowString(gcv.subwindow_mode));
printf("tiling/stippling origin; (%d,%d)\n",
gcv.ts_x_origin,gcv.ts_y_origin);
printf("clipping origin; (%d,%d)\n",
gcv.clip_x_origin,gcv.clip_y_origin);
printf("graphic exposures; %d\n",
gcv.graphics_exposures);
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
’ 118
119
120
121
122
123
124 125^
126
printf("line width: %d\n",gcv.line_width); printf("line style; %s\n", lineStyleString(gcv.line_style));
printf("cap style: %s\n",
capStyleString(gcv.line_style)); printf("join style: %s\n", joinStyleString(gcv.line_style));
return(TRUE);
}
static char *functionString(GdkFunction function) {
switch(function) {
case GDK_COPY: return("copy");
case GDK_INVERT: return("invert");
case GDK_XOR: return("xor");
case GDK_CLEAR: return("clear");
case GDK_AND: return("and");
case GDK_AND_REVERSE: return("and reverse");
case GDK_AND_INVERT: return("and invert");
case GDK_NOOP; return("noop");
case GDK_OR: return("or");
case GDK_EQUIV: return("equiv");
case GDK_OR_REVERSE: return("or reverse");
case GDK_COPY_INVERT: return("copy invert");
case GDK_OR_INVERT: return("or invert");
case GDK_NAND: return("nand");
case GDK_SET: return("set");
default: return("");
}
}
static char *fillString(GdkFill fill) {
switch(fill) {
case GDK_SOLID: return("solid");
case GDK__TILED: return( "tiled" );
case GDK_STIPPLED: return("stippled");
case GDK_OPAQUE_STIPPLED: return("opaque stippled"); default: return("");
} } static char *subwindowString(GdkSubwindowMode mode)
if(mode == GDK_CLIP_BY_CHILDREN) return("clip by children");
else if(mode == GDK_INCLUDE_INFERIORS) return("include inferiors");
return("");
}
static char *lineStyleString(gint style) {
switch(style) {
case GDK_LINE_SOLID: return("solid");
case GDK_LINE_ON_OFF_DASH: return("on off dash");
case GDK_LINE__DOUBLE_DASH: return("double dash"); default: return("");
}
127 }
128 static char *capStyleString(gint style)
129 {
130switch(style) {
131case GDK_CAP_NOT_LAST: return("not last");
132case GDK_CAP_BUTT: return("butt");
133case GDK_CAP_ROUND: return("round");
134case GDK_CAP_PROJECTING: return("projecting");
135default: return("");
136}
137 }
138 static char *joinStyleString(gint style)
139 {
140switch(style) {
141case GDK_JOIN_MITER:return("miter");
142case GDK_JOIN_ROUND:return("round");
143case GDK_JOIN_BEVEL:return("bevel");
144default: return("");
145}
146 }
147
148 gint eventDelete(GtkWidget *widget,
149GdkEvent ♦event,gpointer data) {
150 return(FALSE);
151 }
152 gint eventDestroy(GtkWidget *widget,
153GdkEvent ♦event,gpointer data) {
154gtk_main_quit();
155return(O);
156 }
В строках с 31 no 35 создается область для рисования, вставляется в главное окно и к ней присоединяется функция обратного вызова listvalues (). Обратный вызов включается сигналом "realize". Это означает, что обращение к функции обратного вызова происходит только один раз, когда окно полностью построено и может быть показано. Надо подождать, пока это произойдет, ибо только после этого станут доступны значения GdkGC.
Функция обратного вызова listValues(), начинающаяся со строки 41, выводит на экран каждое значение из графического контекста, найденного в виджете. В этом виджете несколько графических контекстов, которые будут описаны позже в рассматриваемой главе, но один из них — white_gc — описывается в этой программе в строке 47. К значениям в объекте GdkGC нет прямого доступа, поэтому в строке 48 вызов функции gdk_gc_get_values () наполняет структуру GdkGCValues информацией из GdkGC. Остальные строки этой функции предназначены для вывода значений.
В строках с 50 по 55 отображается информация о цветах. В графическом контексте хранятся два цвета: один для переднего плана, другой для фона. Все раскрашивание и рисование производится с использованием цвета переднего плана, в то время как очистка и удаление — с использованием фонового цвета.
Строка 56 знакомит со всей известной информацией о шрифте: внутренний числовой Ю (идентификатор), максимальное количество пикселов символа, размещаемое над и под базовой линией. Сложение последних двух значений дает высоту самого высокого символа. Имеется также другая доступная информация, но только эта, прикладываемая к указанной строке, имеет значение, как и описано в главе 13.
В строке 59 вызывается функция functionstring (), определенная в строке 80, для показа метода (функции), который будет использоваться для рисования пиксела. Как видно из табл. 11.2, существует несколько доступных функций. По умолчанию наиболее общая из них — GDK_COPY — переписывает старые значения пикселов на новые. Функции осуществляют поразрядные операции, поэтому они работают абсолютно одинаково для любого количества бит на пиксел.
Таблица 11.2. Функции, используемые для записи пикселов
Функция
Описание побитовой операции
GKK_ANK
Каждый результирующий бит является результатом логической операции ANK (сложения) над соответствующими исходными и выходными битами.
GKK_ANKJNVERT
Биты источника инвертируются. Затем каждый результирующий бит является результатом логической операции ANK над соответствующими исходными и выходными битами.
GKK_ANK_REVERSE
Биты по месту назначения инвертируются. Затем каждый результирующий бит является результатом логической операции ANK над соответствующими исходными битами и битами по месту назначения.
GKK_CLEAR
Все биты пиксела в месте назначения устанавливаются равными 0.
GKK_CkPY
GKK__CkPYJNVERT
Исходные пикселы игнорируются.
Выходной пиксел копируется с исходного пиксела.
Исходный пиксел копируется в место назначения, а затем там инвертируется.
GKK_EQUIV
Исходные биты инвертируются. Затем каждый результирующий бит является результатом логической операции EXCLUSIVE к R (исключающее ИЛИ) над соответствующими исходными и выходными битами.
GKKJNVERT
Биты по месту назначения инвертируются (нули становятся единицами,
GKKjslANK
а единицы — нулями). Исходные пикселы игнорируются.
Инвертируются и исходные, и выходные пикселы. Затем каждый результирующий бит становится результатом логической операции ANK над соответствующими исходными и выходными битами.
GKK_NkkP
GKK_kR
Выходной пиксел остается неизменным.
Каждый результирующий бит является результатом логической операции к R над соответствующими исходными и выходными битами. ‘
GKK_kR_REVERSE
Биты в месте назначения инвертируются. Затем каждый результирующий бит является результатом логической операции к R (ИЛИ) над соответствующими исходными и выходными битами.
GKK_SET
GKK_XkR
Все выходные пикселы устанавливаются равными 1.
Каждый результирующий бит является результатом логической операции EXCLUSIVE к R (исключающее ИЛИ) над соответствующими исходными и выходными битами.
В строке 61 вызывается функция fillstring (), определенная в строке 101, для отображения метода, используемого для заливки (заполнения) областей в окне. В табл. 11.3
перечислены функции заливки в терминах полей структуры GdkGCValues, а также описано, как каждая из них использует цветные растровые изображения. По умолчанию GDK_SOLID выполняет заливку области сплошным цветом.
Таблица 11.3. Функции, используемые для заливки областей
Функция
Описание
GKK_SkLIK
Каждый пиксел области закрашивается цветом foreground (основным). Растровые изображения не работают.
GKKJTILEK
Цветное растровое изображение tile (покрытие) копируется в место назначения таким образом, что заполняет полностью всю область. Верхний левый угол цветного растра tile размещается в верхнем левом углу заполняемой области. Если растровое изображение слишком мало, то оно повторяется и вертикально, и горизонтально, пока не заполнится вся область.
GKK_STIPPLEK
Цветное растровое изображение stipple (пунктир) используется как маска для закрашивания области. Цветной растр stipple должен иметь глубину, равную 1, то есть один бит на пиксел. Цвет foreground наносится там, где бит гравировки пунктиром приравнивается к 1. Пиксел остается неизменным, когда бит гравировки пунктиром приравнивается к 0.
GKK_kPAQUE_STIPPLEK Цветное растровое изображение stipple (пунктир) используется
как маска для закрашивания области. Цветной растр stipple должен иметь глубину, равную 1, то есть один бит на пиксел. Цвет foreground наносится там, где бит гравировки пунктиром приравнивается к 1. Цвет background (фоновый) наносится там, где бит гравировки пунктиром приравнивается к 0.
Оператор из строки 62 выполняет вывод в режиме подокна, вызвав функцию subwindowString( ), объявленную в строке 111. Если установка — это опция GDK_CLIP_BY_CHILDREN, то в области, закрытой любыми дочерними окнами, никакого рисования не происходит. Другими словами, это окно не может перекрывать дочернее окно. Другая опция — это GDK_INCLUDE_INFERIORS, которая заставляет игнорировать любые дочерние окна и просто рисовать поверх них. Другими словами, это окно перекрывает его дочерние окна.
В строках с 64 по 67 осуществляется вывод координат х и у начальных точек для покрытия, гравировки пунктиром и для усечения. По умолчанию все эти значения устанавливаются в 0. По умолчанию покрытие (tiling) начинается с размещения элемента изображения в верхнем левом углу окна — в точке с координатами (0,0) области рисования, но не фигуры, которая рисуется на ней. Установки могут использоваться, чтобы поместить первый элемент покрытия для подгонки к рисуемой фигуре, как будет описано в примерах далее в этой главе. Симметрия — еще одна причина, по которой это надо сделать. Например, если имеется окно шириной 200 пикселов и используется элемент покрытия шириной 75 пикселов, то можно установить координату начала покрытия по горизонтали в значение -25, чтобы одинаково подогнать покрытие с обеих сторон окна. Начало координат маски усечения может быть переустановлено таким же образом.
В строке 68 показывается, должен ли сбой при копировании пикселов (происходит потемнение окна) вызвать прерывание. При копировании пикселов из окна на экране про-
цесс может завершиться аварийно частично или полностью, если оригинальное окно частично или полностью затемнено. Это результат действий приложения, отвечающего за обновление окна, ибо сервер не требует поддерживать копию затемненных пикселов. Когда копирование завершается аварийно, возникает событие GdkEventExpose, а когда копирование завершается успешно — GdkEventNoExpose.
Операторы в строках с 70 по 76 отображают установки управления рисуемыми линиями. Толщина линии измеряется в пикселах; нулевое значение (по умолчанию) определено для линии толщиной в один пиксел. В то время как линии с толщиной 0 или 1 отображаются на экране одинаково, линия с заданной толщиной 0 выводится только как непрерывная. Линия с ненулевой толщиной рисуется как непрерывная или может иметь одну из нескольких штрих-пунктирных форм, как указано функцией lineStyleString() в строке 119. Конец линии с толщиной более одного пиксела может относиться к одному из четырех стилей, и также один из трех различных стилей определяет тип соединения линий под углом. Примеры этих стилей будут приведены позже в этой главе.
Вывод этой программы изменяется от одной системы к другой из-за различия в графических возможностях. Также могут отличаться взятые по умолчанию черный и белый цвета, размеры шрифтов и стили линий. Ниже приведен типичный вывод программы:
foreground RGB: 62900 49151 35864 (0x00007FFF) background RGB: 24744 2055 0 (0x00000001) font id: 33554437 ascent: 11 descent; 3 pixel drawing function: copy fill method: solid subwindow mode: clip by children tiling/stippling origin: (0,0) clipping origin: (0,0) graphics exposures: False line width: 0 line style: solid cap style: not last join style: miter
Установка цвета виджета
Следующая программа использует числовые значения красного, синего и зеленого цветов для создания цвета в форме объекта GdkColor. Затем цвет вставляется как цвет переднего плана в (основной цвет) графический контекст (объект GdkGC). Графический контекст используется для заливки прямоугольнЬй области. Таймер вызывает постоянное окрашивание разноцветных прямоугольников в окне. Заметьте, что цвет, размер и расположение каждого прямоугольника случайны.
/♦* flasher.с ъ**/
#include <gnome.h>
3
gint eventDelete(GtkWidget *widget,
GdkEvent ♦event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint drawRandomRectangle(gpointer data); 9
Idefine WIDTH 400
Idefine HEIGHT 300
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
♦define INTERVAL 30
int main(int argc,char *argv[]) {
GtkWidget *app;
GtkWidget *area;
gnome_init("flasher","1.0",argc,argv);
app = gnome_app_new("flasher","Creating Colors"); gtk_signal_connect(GTK_OBJECT(app),"delete_event", GTK_SIGNAL_FUNC(eventDelete),NULL);
gtk_signal_connect(GTK_OBJECT(app),"destroy", GTK_SIGNAL_FUNC(eventDestroy),NULL);
area = gtk_drawing_area_new();
gtk_widget_set_usize(area,WIDTH,HEIGHT); gnome_app_set_contents(GNOMEAPP(app),area);
gtk_timeout_add (INTERVAL,drawRandomRectangle, area);
gtk_widget_show_all(app);
gtk_main();
exit(0);
}
gint drawRandomRectangle(gpointer data) {
static GdkColormap *colormap = NULL;
static GdkGC *gc = NULL;
GdkColor color;
GtkWidget *widget = GTK_WIDGET(data);
gint x = 20;
gint у = 20;
gint width = 40;
gint height = 40;
if(colormap == NULL) { colormap = gdk_colormap_get_system(); gc = gdk_gc_new(widget->window);
}
color.red += (((double)rand()*0xFFFF)/RAND MAX);
color.green += (((double)rand()*0xFFFF)/RANDMAX); color.blue += (((double)rand()*0xFFFF)/RANDMAX); gdkcoloralloc(colormap,&color);
gdk_gc_set_foreground(gc,&color);
x = (((double)rand()*WIDTH)/RANDMAX) - (WIDTH/4);
у = (((double)rand()*HEIGHT)/RAND_MAX) - (HEIGHT/4); width = (((double)rand()*(WIDTH/2))/RAND_MAX);
height = (((double)rand()♦(HEIGHT/2))/RAND_MAX);
gdkdrawrectangle(widget->window, gc, TRUE,.
6667686966676869}}х,у, width,height);
66
67
68
69
66
67
68
69
}
}
return(TRUE);
70
71 gint eventDelete(GtkWidget *widget,
72GdkEvent *event,gpointer data) {
73 return(FALSE);
74 }
75 gint eventDestroy(GtkWidget *widget,
76GdkEvent *event,gpointer data) {
77gtk_main_quit();
78return(O);
79 }
В строках с 26 по 29 создается область для рисования, используемая для отображения прямоугольников, и функция drawRandomRectangle() присоединяется к таймеру. Значение интервала, заданное в строке 12, устанавливается равным 30 миллисекундам. Виджет area переходит к функции обратного вызова в виде данных. Функция drawRandomRectangle(), начинающаяся со строки 35, использует при создании цвета генератор случайных чисел и рисует один прямоугольник.
Системная карта цветности выбирается в строке 47 с помощью функции gdk__colormap__get_systeni(). Локальная переменная карты цветности объявлена как статическая, поэтому карта цветности выбирается только первый раз, когда вызывается функция. Обращение к gdk_gc_new() в строке 48 создает новый графический контекст, удобный для рисования специфического окна.
ПРИМЕЧАНИЕ_
Именно это является причиной использования специфического окна при вызове функции gdk_gc_new(), создающей новый графический контекст. Существуют ограничения размеров, глубины пиксела и т.п., которые могут меняться от одного окна к другому. В X это происходит довольно часто, так как любая программа может иметь окна, одновременно открытые на двух или более рабочих станциях.
Программа создает цветной объект и размещает его в графическом контексте, а затем использует графический контекст для рисования прямоугольников. Цвет задается в следующей структуре:
struct _GdkColor {
gulong pixel;
gushort red;
gushort green;
gushort blue;
};
В строках с 51 по 54 создается новый цвет. Объект GdkColor назначает случайные числа от 0 до 65535 в каждое из его полей red, green и blue. Вызов функции gdk_color_alloc() делает все необходимое, чтобы сделать цвет доступным для использования, хотя конкретные действия зависят от системы. Если есть свободное место в перезаписываемой карте цветности, то эта функция добавляет цвет. Если карта цветности не перезаписываемая или уже заполнена, то она просматривает карту цветности и находит цвет, ближайший к требуемому. Если точное совпадение цвета не найдено, то функция подстраивает значения red, green и blue из объекта GdkColor к ближайшим значениям карты цветности. Какой бы метод ни использовался для расположения цвета, поле pixel объекта GdkColor обновляется на актуальное значение пиксела. Теперь цвет готов к использованию.
В строке 56 вызывается функция gdk_gc_set_foreground(), чтобы вставить объект GdkColor в объект GdkGC как основной цвет.
В строках с 58 по 61 задаются размер и расположение треугольника. Диапазон значений масштабируется в соответствии с размерами окна для того, чтобы получить в окне
максимальное количество рисунков и достаточно маленькие прямоугольники для одновременного вывода сразу нескольких из них. В строке 63 в окне рисуется прямоугольник путем обращения к gdk_draw_rectangle () и использования графического контекста, что поддерживает недавно созданный цвет.
Стили линий в графическом контексте
Для управления стилем создаваемых линией необходимо манипулировать значениями в самом графическом контексте. Так как каждая операция прорисовки требует собственный объект GdkGC, довольно просто создать одну из них и управлять ею, чтобы работать так, как вам захочется. В следующем примере создается графический контекст и используется для прорисовки линий различными стилями.
/** linestyle.с **/
linclude <gnome.h>
3
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
gboolean eventDraw(GtkWidget *widget,
GdkEvent *event,gpointer data);
10
Idefine WIDTH 300
Idefine HEIGHT 350
13
int main(int argc,char *argv[])
{
GtkWidget *app;
GtkWidget *area;
18
gnomeinit("linestyle","1.0",argc,argv);
app = gnome_app_new("linestyle","Line Styles");
gtk_signal_connect(GTK_OBJECT(app),"delete_event",
GTK_SIGNAL_FUNC(eventDelete),NULL);
gtk_signal_connect(GTK_OBJECT(app),"destroy",
GTK_SIGNAL_FUNC(eventDestroy),NULL);
25
area = gtk_drawing_area_new();
gtk_widget_set_usize(area,WIDTH,HEIGHT);
gnome_app_set_contents(GNOME_APP(app),area);
29
0gtk_signal_connect(GTK_OBJECT(area),"event",
GTK_SIGNAL_FUNC(eventDraw),NULL);
32
gtk_widget_show_all(app);
gtk_main();
exit(0);
}
gboolean eventDraw(GtkWidget *widget,
GdkEvent *event,gpointer data) {
3940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959639404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596int i;
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
int x = 40;
int у = 180;
char dashList[4) = { 5, 15, 20, 30 };
GdkGC *gc;
GdkColormap *colormap;
GdkColor foreground;
GdkColor background;
GdkFont *font;
GdkPoint points[3] = {
{ 80, 40 },
{ 40, 120 }, { 80, 120 }
font = gdk_font_load("vga");
gc = gdk_gc_new(widget->window);
colormap = gdk_colormap_get_system();
if(gdk_color_parse("blue",«foreground)) { gdk_color_alloc(colormap,«foreground); gdk_gc_set_foreground(gc,«foreground);
}
if(gdk_color_parse("yellow",&background)) { gdk_color_alloc(colormap,«background); gdk_gc_set_background(gc,«background);
}
/*- The MITER join -*/ gdk_gc_set_line_attributes(gc, 10, GDK_LINE_SOLID, GDK_CAP_BUTT, GDKJOINMITER);
gdk_draw_polygon(widget~>window,,
gc, FALSE, points, (int)(sizeof(points)/sizeof(GdkPoint)));
gdk_draw_string(widget->window, font,
gc, points[1].x,points[1].y + 20, "Miter");
/*- The ROUND join -*/ for(i=0; i<3; i++) points[ij.x += 80; gdk_gc_set_line_attributes(gc, 10, GDK_LINE_SOLID, GDKCAPBUTT, GDKJOINROUND);
gdk_draw_polygon(widget->window, gc, FALSE, points, (int)(sizeof(points)/sizeof(GdkPoint))); gdk_draw_string(widget->window,
97
font.
98
gc,
99
points[1].х,points[1].у + 20,
100
"Round");
101
102
/♦- The BEVEL join -*/
103
for(i=0; i<3; i++)
104
points[i].x += 80;
105
gdk_gc_set_line_attributes(gc,
106
10,
107
GDK_LINE_SOLID,
108
GDKCAPBUTT,
109
GDK_JOIN_BEVEL);
110
gdk_draw_polygon(widget->window,
111
gc,
112
FALSE,
113
points,
114
(int)(sizeof(points)/sizeof(GdkPoint)
115
gdk_draw_string(widget->window.
116
font,
117
gc,
118
points!1].x,points[1].y + 20,
119
"Bevel");
120
121
/♦- Cap BUTT -♦/
122
gdk gc set_line attributes(gc,
123
10,
124
GDK_LINE_SOLID,
125
GDK_CAP_BUTT,
126
GDK_JOIN_MITER);
127
gdk_draw_line(widget->window,
128
gc,
129
x,y,
130
x + 120,y);
131
gdk_draw_string(widget->window,
132
font,
133
gc,
134
x + 130,у + 5,
135
"Butt");
136
137
/*- Cap NOT LAST -♦/
138
у += 20;
139
gdk_gc_set_line_attributes(gc,
140
10,
141
GDK_LINE_SOLID,
142
GDK_CAP_NOT_LAST,
143
GDKJOINMITER);
144
gdk_draw_line(widget->window,
145
gc,
146
x,y,
147
x + 120,y);
148
gdkdrawstring(widget->window,
149
font,
150
gc,
151
x + 130,у + 5,
152
"Not last");
153
154
/♦- Cap ROUND -*/
155
у += 20;
156
gdk_gc_set_line_attributes(gc,
157
ю.
158
GDK_LINE_SOLID,
159
GDKCAPROUND,
160
GDK_JOIN_MITER);
161
gdk_draw_line(widget->window,
162
gc,
163
x,y,
164
x + 120,y);
165
gdk_draw_string(widget->window
166
font,
167
gc,
168
x + 130,у + 5,
169
"Round");
170
171
/*- Cap PROJECTING -*/
172
у += 20;
173
gdk_gc_set_line_attributes(gc,
174
10,
175
GDK_LINE_SOLID,
176
GDK_CAP_PROJECTING,
177
GDK_JOIN MITER);
178
gdk_draw_line(widget->window,
179
gc,
180
x,y,
181
x + 120,y);
182
gdk_draw_string(widget->window,
183
font,
184
gc,
185
x + 130,у + 5,
186
"Projecting");
187
188
/*- Style SOLID -♦/
189
у += 40;
190
gdk_gc_set_line_attributes(gc,
191
10,
192
GDK_LINE_SOLID,
193
GDK_CAP_BUTT,
194
GDK_JOIN_MITER);
195
gdkdrawline(widget->window,
196
gc,
197
x,y,
198
x + 120,y);
199
gdk_draw_string(widget->window,
200
font,
201
gc,
202
x + 130,у + 5,
203
"Solid");
204
205
/*- Style ONOFFDASH -*/
206
у += 20;
207
gdk_gc_set_dashes(gc,
208
0,
209
dashList,
210
4);
211
gdk_gc_set_line_attributes(gc,
212
10,
213GDK_LINE_ON_OFF_DASH,
214GDK_CAPJBUTT,
215GDK_JOIN_MITER);
216gdk_draw_line(widget->window,
217gc,
218x,y,
219x + 120,y);
220gdkdraw_string(widget->window,
221font,
222gc,
223x + 130,у + 5,
224"On off dash");
225 226/*- Style DOUBLE DASH -*/
227у += 20;
228gdk_gc_set_line_attributes(gc,
22910,
230GDK_LINE_DOUBLE_DASH,
231GDK_CAP_BUTT,
232GDK_JOIN_MITER);
233gdk_draw_line(widget->window,
234gc,
235x,y,
236x + 120,y);
237gdk_draw_string(widget->window,
238font,
239gc,
240x + 130,у +5,
241"Double dash");
242
243gdk_font_unref(font);
244gdkgcunref(gc);
245return(TRUE);
246 }
247 gint eventDelete(GtkWidget *widget,
248GdkEvent *event,gpointer data) {
249return(FALSE);
250 }
251 gint eventDestroy(GtkWidget *widget,
Miter Bound BevelMiter Bound BevelММММММЯ Butt - MMMMMMM Hot last;'MMMMMMM Bound MMMMMMMM ProjectingММММММЯ Butt - MMMMMMM Hot last;'MMMMMMM Bound MMMMMMMM Projecting■MMMMMM Solid . IMI Ml On off dashI MI M Double dash■MMMMMM Solid . IMI Ml On off dashI MI M Double dashРисунок 11.2.Толстые линии, демонстрирующие принятые стилиРисунок 11.2.Толстые линии, демонстрирующие принятые стили252GdkEvent *event,gpointer data) {
Miter Bound Bevel
Miter Bound Bevel
ММММММЯ Butt - MMMMMMM Hot last;'
MMMMMMM Bound MMMMMMMM Projecting
ММММММЯ Butt - MMMMMMM Hot last;'
MMMMMMM Bound MMMMMMMM Projecting
■MMMMMM Solid . IMI Ml On off dash
I MI M Double dash
■MMMMMM Solid . IMI Ml On off dash
I MI M Double dash
Рисунок 11.2.
Толстые линии, демонстрирующие принятые стили
Рисунок 11.2.
Толстые линии, демонстрирующие принятые стили
253gtk_main_quit();
254return(0);
255 }
В строках с 26 по 31 происходит создание виджета GtkDrawingArea и присоединение его к главному окну. Функция обратного вызова eventDraw() присоединяется к области для рисования. Весь объем рисования, выполняемый в функции обратного вызова eventDraw(), задан в строке 37. Окно, произведенное этой программой, изображено на рис. 11.2.
В строке 54 вызывается gdk_f ont_load() для загрузки шрифта, который будет использоваться потом для прорисовки текста в окне. Это понадобится позже, так как для рисования строк прямо в области для рисования требуется спецификация шрифта.
Новый графический контекст строится в строке 55 путем вызова gdk_gc_new() с окном в виде области для рисования. В новом графическом контексте устанавливаются значения по умолчанию для цвета, линий и т.п. и еще корректные внутренние значения для прорисовки окна, которое используется в качестве аргумента.
Основной и фоновый цвета устанавливаются в строках с 55 по 64. Цвета построены и назначены в соответствии с картой цветности, поэтому с помощью вызова gdk_colormap_get_system() в строке 56 выбирается системная карта цветности. В строке 57 при обращении к функции gdk_color_parse() задается название цвета и возвращается TRUE, если оно опознано и значения цвета получены.
При обращении к функции gdk_color_parse() существует два способа назначения наименований цветов. Можно указать название цвета, как в этом примере, если оно присутствует в файле /usr/lib/Xll/rgb.txt. Это текстовый файл, который используется для преобразования каждого названия цвета в его набор из трех RGB-чисел. Если вы добавляете в этот файл наименование цвета, то ваша программа сама найдет его и будет использовать. Но в то же время в вашей программе необходимо предусмотреть некоторые альтернативные действия, так как название цвета может отсутствовать в иной системе или исчезнуть в процессе ее обновления. Если хотите создать собственный цвет, то лучше указать RGB-значения. Можно применять метод, описанный ранее в этой главе, или использовать RGB-значения для названия цвета. Работает любой из нижеследующих форматов:
"IRGB"
"IRRGGBB"
"IRRRGGGBBB"
"IRRRRGGGGBBBB"
Каждая буква — это шестнадцатеричная цифра одного из трех основных цветов. Функция gdk_color_parse() разбирается с этими форматами путем подсчета общего количества символов в строке, а оно должно быть кратно трем. Например, при использования двух цифр на цвет, если планируется отказ от красного, максимум зеленого и немного синего цветов, строка, задающая формат, будет выглядеть следующим образом:
"I00FF3C"
В строке 57 функция gdk_color_parse() возвращает TRUE, если название цвета правильное. Функция gdk_color_alloc() вызывается в строке 58 для инициализации информации о цвете таким образом, чтобы его можно было использовать в графическом контексте, а обращение к gdk__gc__set_f oreground() в строке 59 устанавливает основной цвет в графический контекст. Подобным образом вызовы функций в строках с 61 по 64 устанавливают в графический контекст цвет фона.
Обращение к функции gdk^gc_set_line_attributes () в строке 67 указывает фацетное соединение (miter joint) на линии толщиной 10 пикселов. Специально чертятся толстые линии, чтобы можно было легко увидеть детали построения. Фацетное соединение — это когда концы линий продлеваются до тех пор, пока линии не встретятся. Это хорошо работает при маленьких углах, но, когда углы начинают сужаться, точка движется дальше и изображение, которое вы хотите нарисовать, может исказиться. Вызов функции gdk_draw__polygon () в строке 72 рисует треугольник, заданный в виде массива точек, который объявлен в строке 48. Так как мы использовали новый графический контекст, линии закрашиваются синим цветом и имеют толщину 10 пикселов. Обраще-
ние к функции gdk_draw_string() в строке 77 создает надпись под первой фигурой, как изображено в верхнем левом углу рис. 11.2.
В цикле, начинающемся в строке 84, точки треугольника передвигаются на следующую позицию в окне. Идущие далее в строках с 86 по 100 вызовы функций рисуют другой треугольник. На этот раз рассматривается скругленное соединение (round join). Оно получается, если остановить процесс рисования, когда линии достигают крайних точек. После этого вокруг крайних точек рисуется окружность с диаметром, который совпадает с краями линий.
В строках со 105 по 119 треугольник еще раз передвигается вправо и рисуется косой стык (bevel join). Вы создаете косой стык, рисуя прямую линию между крайними точками двух линий. Это можно хорошо продемонстрировать при помощи угла в 90 градусов, прикладываемого снизу: обе линии заканчиваются в одной и той же точке, и скашивание происходит путем заливки сверху маленького треугольника.
В строках с 121 по 186 рисуются четыре линии с краями различных стилей. Торцевое окончание (butt ending) предполагает квадратный край, который включает пиксел на краях. Незавершенное окончание (not-last ending) — это то же самое, что и торцевое окончание, за исключением того, что последний пиксел не рисуется. Подобное окончание используется, когда создается некая рамка и из-за разницы в цвете одна линия не может перекрывать пикселы уже существующей на экране линии. Скругленное окончание (round ending) — это просто окружность, нарисованная вокруг крайних точек. Оно продлевает линию далее каждой конечной точки на половину толщины линии. Выступающее окончание (projecting ending) продлевает длину на половину собственной толщины так же, как и при скругленном окончании, а затем рисуется торцевое окончание.
Обычно рисуются сплошные (непрерывные) линии, но есть два пути рисования штрих- пунктирных линий. В строках с 205 по 224 рисуются двухпозиционные штрихпунктир- ные линии (on-off dashed lines). То есть основной цвет используется для рисования каждого второго сегмента, а другие сегменты пропускаются. В строках с 226 по 241 рисуется двойная штрихпунктирная линия (double dash), используя в качестве альтернативы основного цвета фоновый.
Можно создать штрихпунктирные линии по любому образцу. В этой программе образец штрихпунктирной линии задан при помощи массива dashList в строке 42. Каждый член массива указывает номер пиксела, который надо нарисовать основным или фоновым цветом. Обычная линия с использованием dashlist рисуется так: 5 пикселов, затем пропуск 15 пикселов, еще рисуется 20 пикселов, затем пропуск 30 пикселов, а после этого возвращение в начало, и снова рисуется 5 пикселов и т.д. до края линии. Если существует нечетное количество членов массива, двухпозиционный выбор реверсируется с каждым прохождением через массив. Например:
char dashList[3]={5, 10, 15};
Строка начинается с прорисовки 5 пикселов, затем 10 пикселов один раз пропускаются, 15 рисуются, 5 пропускаются, 10 рисуются и т.д. Это справедливо, если в массиве шесть членов с одинаковыми значениями, которые дублируются в последние три.
Обращение к функции gdk_gc_set_dashes() выполняется в строке 207 и содержит в качестве второго аргумента индекс массива, который указывает начальный член: будет нарисован отрезок первой линии. Последний аргумент — это количество значений в массиве.
Гравировка пунктиром
Рисунок 11.3.Монохромное изображение, использующееся как маска гравировки пунктиромРисунок 11.3.Монохромное изображение, использующееся как маска гравировки пунктиромИспользование монохромного (черно-белого) растрового изображения с гравировкой дает вам побитный контроль за тем, какие пикселы рисуются, а какие — нет. Монохромное изображение (bitmap) — это разновидность цветного растрового изображения (pixmap) с единичной глубиной, вид маски, предполагающей один бит на пиксел, которая распознает, какой пиксел рисуется. Монохромное изображение создается с использованием специальной утилиты bitmap, описанной в главе 7. Монохромное изображение, используемое в следующем примере, именуется stipple . xbm и, когда оно загружается в редактор bitmap, выглядит, как на рис. 11.3.
Рисунок 11.3.
Монохромное изображение, использующееся как маска гравировки пунктиром
Рисунок 11.3.
Монохромное изображение, использующееся как маска гравировки пунктиром
Монохромное растровое изображение хранится как исходный код на языке С в файле stipple*xbm. Этот файл содержит информацию о высоте и ширине вместе с массивом бит, предполагается один бит на пиксел:
Idefine stipple_width 16
Idefine stipple_height 16 static unsigned char stipple_bits[] = {
0x00,
0x20,
Oxaa,
0x2a,
0x54,
0x25,
Oxaa,
0x2a,
0x54,
0x25,
Oxaa,
0x2a,
0x54,
0x25,
0x00,
0x00,
Oxfc,
0x3f,
Oxlc,
0x00,
0x9c,
0x7f,
0x3c,
0x00,
Oxef,
Oxfc,
OxOe,
0x00,
Oxce,
0x3f,
0x00,
0x20}
В следующей программе используется гравировка пунктиром для рисования двух прямоугольников. Один прямоугольник нарисован прозрачным, то есть пикселы, соответствующие единичным битам, рисуются основным цветом в то время, как пикселы, соответствующие нулевым битам, не рисуются. Во втором прямоугольнике единичные биты рисуются основным цветом, а нулевые — фоновым цветом, все пикселы рисуются непрозрачными.
/♦* stipple.с **/
finclude <gnome.h>
3
tinclude "stipple.xbm"
Iinclude "terminal.xpm"
6
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
* 10GdkEvent *event,gpointer data);
gboolean eventDraw(GtkWidget *widget,
GdkEvent *event,gpointer data);
13
Idefine WIDTH 250
Idefine HEIGHT 420
16
17 int main(int argc,char *argv[])
{
GtkWidget *арр;
GtkWidget *агеа;
21
gnome_init(* stipple","1.0",argc,argv);
app = gnome_app_new("stipple","Stipple and Tile");
gtk_signal_connect(GTK_OBJECT(app),"delete_event",
GTK_SIGNAL_FUNC(eventDelete),NULL);
gtk_signal_connect(GTKOBJECT(app),"destroy",
GTK_SIGNAL_FUNC(eventDeStroy) ,NULL) ;
28
area = gtk_drawing_area_new();
gtk_widget_set_usize(area,WIDTH,HEIGHT);
gnome_app_set_contents(GNOME_APP(app),area);
gtk_signal_connect(GTK_OBJECT(area),"event",
GTK_SIGNAL_FUNC(eventDraw),NULL);
34
gtk_widget_show_all(app);
gtk_main();
exit(0);
}
gboolean eventDraw(GtkWidget *widget,
GdkEvent *event,gpointer data) {
GdkGC *gc;
GdkBitmap *mask;
GtkStyle *style;
GdkPixmap *stipple;•
GdkPixmap *terminal;*
GdkColormap *colormap;
GdkColor foreground;
GdkColor background;
49
colormap = gdk_colormap_get_system();
gc = gdk_gc_new(widget->window);
if(gdk_color_parse("blue",&foreground)){
gdk_color_alloc(colormap,&foreground);
gdk_gc_set_foreground(gc,&foreground);
}
if(gdk_color parse("yellow",&background)){
7gdkcoloralloc(colormap,&background);
gdkgcset_background(gc,&background);
}
•
stipple = gdk_bitmap_create_fromdata(widget->window,
stipple_bits,
stipple_width,
stipple_height);
gdk_gc_set_stipple(gc,stipple);
•
style = gtk_widget_get_style(widget);
terminal = gdk_pixmap_create_from_xpm_d(widget->window,
&mask,
& style->bg[GTK_STATE_NORMAL],
(gchar **)terminal_sun_xpm);
gdk_gc_set_tile(gc,terminal);
73
gdk_gc_set_ts_origin(gc,30,30);
gdk_gc_set_fill(gc,GDK_STIPPLED);
76gdk_draw_rectangle(widget->window,
77gc,
78TRUE,
7930,30,
80200,100);
81
82gdk_gc_set_ts_origin(gc,30,160);
83gdk_gc_set_fill(gc,GDK_OPAQUE_STIPPLED);
84gdk_draw_rectangle(widget->window,
85gc,
86TRUE,
8730,160,
88200,100);
89
90gdk_gc_set_ts_origin(gc,30,280);
91• gdk_gc_set_fill(gc,GDK_TILED);
92gdkdraw_rectangle(widget->window,
93gc,
94TRUE,
9530,280,
96200,100);
97
98return(TRUE);
99 }
100 gint eventDelete(GtkWidget *widget,
101GdkEvent *event,gpointer data) {
102 return(FALSE);
103 }
104 gint eventDestroy(GtkWidget ♦widget,
105GdkEvent *event,gpointer data) {
106gtk_main_quit();
107return(O);
108 }
Файл с монохромным растровым изображением для гравировки включается в строке 4, а цветное растровое изображение, используемое для покрытия, — в строке 5. В строках с 29 по 33 создается область для рисования, вставляется в окно приложения и к ней присоединяется функция обратного вызова eventDraw().
При помощи обращения к функции gdk__colormap_get_system() в строке 50 выбирается адрес системной карты цветности, а вызов функции gdk_gc_new() в строке 51 создает новый графический контекст. В строках с 52 по 59 определяются и устанавливаются основной и фоновый цвета.
Функция gdk_bitmap_create_from_data() вызывается в строке 61 для создания цветного растрового изображения по данным монохромного изображения, которое вставляется (компилируется) в программу. В результате получается цветное растровое изображение, в котором один бит соответствует одному пикселу. Аргумент stipple_bits — это массив бит, используемых как значения в цветных изображениях. Значения stipple_height и stipple__width определяют прямоугольный размер цветного изображения. Как только цветное растровое изображение построено, вызов функции gdk_gc_set_stipple() в строке 65 вставляет его в графический контекст как цветное изображение, используемое для гравировки пунктиром.
В строках с 67 по 72 создается цветное растровое изображение покрытия и устанавливается в графический контекст. Путем обращения к функции gdk_pixmap_create_from_xpm_d() в строке 68 преобразуются данные формата
ХРМ, включенные в программу, в цветное растровое изображение. Дополнительная информация об этом процессе приводится в главе 7. Вызов gdk_gc_set__tile() в строке 72 устанавливает цветное изображение в графический контекст.
В строках с 74 по 80 создается прямоугольная область, отображаемая наверху окна на рис. 11.4. Обращение к функции gdk_gc_set_ts_origin() присваивает началу шаблона для гравировки пунктиром те же значения х и у, как и для рисования прямоугольника. Шаблон гравировки пунктиром начинается с верхнего левого угла прямоугольника вместо значения по умолчанию (0,0) — верхнего левого угла области для рисования. Шаблон гравировки повторяется так часто, как это необходимо для заполнения всего прямоугольника. Функция gdk_gc_set_f ill () вызывается для установки режима заполнения в GDK__STIPPLED, поэтому рисуются только пикселы, соответствующие единичному биту в монохромном изображении для гравировки пунктиром. Другие пикселы
остаются такими, как на прозрачном рисунке.
В строках с 82 по 88 создается прямоугольная область, изображенная в центре на рис. 11.4. Аналогично предыдущему прямоугольнику начало координат устанавливается таким же образом путем обращения к gdk_gc_set_ts_origin ().
Функция gdk_gc_set_f ill () вызывается для установки режима заполнения (заливки) в GDK_OPAQUE_STIPPLED. В результате все пикселы закрашены, таким образом, полностью покрывается каждый пиксел, который уже находится в окне. Пикселы, соответствующие единичным битам в изображении для гравировки пунктиром, закрашиваются основным цветом, а соответствующие нулевым битам — цветом фона.
В строках с 90 по 96 путем покрытия ее цветным растровым изображением полностью заполняется прямоугольная область в нижней части рис. 11.4. При обращении к функции gdk_gc_set_ts_origin () начало координат покрытия устанавливается в то же место, где находится начало координат заполняемого прямоугольника, значит, элемент покрытия в верхнем левом углу полностью сформирован.
Рисунок 11.4.Два вида гравировки пунктиром и один вид покрытияРисунок 11.4.Два вида гравировки пунктиром и один вид покрытияРежим заполнения GDK_TILED устанавливается при
Рисунок 11.4.
Два вида гравировки пунктиром и один вид покрытия
Рисунок 11.4.
Два вида гравировки пунктиром и один вид покрытия
помощи обращения к функции gdk_gc_set_f ill ( ), поэтому обращение к gdk_draw_rectangle() заполняет область цветным растровым изображением для покрытия, определенным в строках с 67 по 72, повторяя его, пока не заполнится весь
прямоугольник.
ПРИМЕЧАНИЕ.
Существуют другие способы нанесения покрытия и гравировки пунктиром. По умолчанию для рисования пикселов в этих примерах используется функция GKK_CkPY, то есть пиксел источника просто перезаписывает результирующий пиксел. Как показано ранее в этой главе в табл. 11.2, существуют другие способы рисования пикселов. Комбинируя различные монохромные растровые изображения с разнообразными функциями закрашивания, можно создавать практически любое количество комбинаций.
Функции, которые устанавливают значения в GdkGC
Есть два способа вставки значений в GdkGC. Все предыдущие примеры используют вызов функции для установки каждого индивидуального значения. В качестве альтернативы во время создания графического контекста можно использовать структуру GdkGCValues для установки нескольких значений за один раз. Следующий пример демонстрирует два различных метода.
/♦♦ setgc.с **/
#include <gnome.h>
3
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
gboolean eventDraw(GtkWidget *widget,
GdkEvent *event,gpointer data);
static GdkGC *functionCreateGC(GdkWindow *window);
static GdkGC *valueCreateGC(GdkWindow *window);
12
tdefine WIDTH 300
tdefine HEIGHT 100
15
int main(int argc,char *argv[])
{
GtkWidget *app;
GtkWidget *area;
20
gnome_init("setgc","1.0",argc,argv);
app = gnome_app_new("setgc","Setting GdkGC Values");
gtksignalconnect(GTK_OBJECT(app),"deleteevent",
GTKSIGNALFUNC(eventDelete),NULL);
gtk_signal_connect(GTKOBJECT(app),"destroy",
GTK_SIGNAL_FUNC(eventDestroy),NULL);
27
area = gtk_drawing_area_new();
gtk_widget_set_usize(area,WIDTH,HEIGHT);
gnome_app_set_contents(GNOME_APP(app),area);
gtksignalconnect(GTK_OBJECT(area),"event",
2GTK_SIGNALFUNC(eventDraw),area);
33
gtk_widget_show_all(app);
gtk_main();
exit(0);
}
gboolean eventDraw(GtkWidget *widget,
GdkEvent *event,gpointer data) {
GdkGC *gc;
GtkWidget *area;
42
area = GTK_WIDGET(data);
44
gc = functionCreateGC(area->window);
/****
gc = valueCreateGC(area->window);
♦***/
495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106gdk_draw_line(area->window, gc, 20,HEIGHT/2, WIDTH-20,HEIGHT/2);
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
return(TRUE);
}
static GdkGC *functionCreateGC(GdkWindow *window) <
GdkGC *gc;
GdkColormap *colormap;
GdkColor foreground; gchar dash[2] = { 1, 20 };
gc = gdk_gc_new(window);
colormap = gdk_colormap_get_system();
if(gdk_color_parse("white",&foreground)) { gdk_color_alloc(colormap,&foreground); gdk_gc_set_foreground(gc,&foreground);
}
gdk_gc_set_line_attributes(gc, 15, GDK_LINE_ON_OFF_DASH, GDK_CAP_ROUND, GDK_JOIN_MITER);
gdk_gc_set_dashes(gc,0,dash,2);
return(gc);
}
static GdkGC *valueCreateGC(GdkWindow *window) <
GdkGC *gc;
GdkColormap *colormap;
GdkColor foreground;
gchar dash[2] = { 1, 20 };
• GdkGCValues values;
colormap = gdk_colormap_get_system();
if(gdkcolorparse("white",&foreground)) gdk_color alloc(colormap,&foreground);
values.foreground = foreground;
values.linewidth = 15;
values.linestyle = GDK_LINE_ON_OFF_DASH;
values.capstyle = GDKCAPROUND;
values.join_style = GDK_JOIN_MITER;
gc = gdk_gc_new_with_values(window,&values, GDKGCFOREGROUND | GDK_GC_LINE_WIDTH | GDK_GC_LINE_STYLE | GDK_GC_CAP_STYLE | GDK_GC_JOIN_STYLE);
gdk gcsetdashes(gc,0,dash,2);
return(gc);'
} gint eventDelete(GtkWidget *widget, GdkEvent *event,gpointer data) {
return(FALSE);
107 }
108 gint eventDestroy(GtkWidget *widget,
109GdkEvent *event,gpointer data) {
110gtk_main_quit();
111return(O);
112 }
В строках с 28 по 32 строится область для рисования и к ней подключается функция обратного вызова eventDraw().
Рисунок 11.5.Линия из круглых штриховРисунок 11.5.Линия из круглых штриховФункция обратного вызова eventDraw(), начинающаяся в строке 38, вызывает функцию для создания графического контекста, а затем использует контекст, чтобы нарисовать линию через центр области. Результат изображен на рис. 11.5. Для создания графического контекста может использоваться либо functionCreateGC() в строке 45, либо valueCreateGC() в строке 47 — результат один и тот же. Единственная разница — способ создания объекта GdkGC.
Рисунок 11.5.
Линия из круглых штрихов
Рисунок 11.5.
Линия из круглых штрихов
Функция f unctionCreateGC (), начинающаяся в строке 56, создает графический контекст по умолчанию, а затем для установки значений вызывает серию функций. Обращение к функции gdk_gc_set_foreground ( ) в строке 68 устанавливает основной цвет, используемый для прорисовки линии. В строке 70 вызов функции gdk_gc_set_line_attributes() задает размер и стиль линии. Вызов функции gdk_gc_set_dashes() указывает образец штриха, используемого при рисовании линии.
Начинающаяся со строки 79 функция valueCreateGC() заполняет инициализированными данными структуру GdkGCValues и использует ее для создания графического контекста. В строках с 87 по 94 разнообразные переменные вставляются в структуру GdkGCValues. Объект GdkGC создается обращением к функции gdk__gc_new_with_values () в строке 96. Первый аргумент — это окно, на котором будет базироваться графический контекст. Второй аргумент — это указатель на структуру, содержащую значения, а третий аргумент — набор разрядов флагов, указывающих, какие значения включены в структуру. Только те аргументы, для которых установлен набор флагов, включаются в GdkGC. Обращение к функции gdk_gc_set_dashes () в строке 100 необходимо, так как в структуре GdkGCValues нет специальных установок для образцов штрихов.
В этом примере не видно большого преимущества использования одного метода по сравнению с другим. Однако если вы собираетесь построить несколько объектов GdkGC с одинаковым базовым набором значений, то можете один раз создать структуру GdkGCValues и многократно ее использовать. Также если хотите выделить некоторые значения из одного графического контекста и вставить его в другой, то можно это сделать при помощи обращений к функциям gdk_gc_get_values () (для выделения значений из начального объекта GdkGC) и gdk_gc_new_with_values () (для создания нового GdkGC, содержащего выбранные значения).
Табл. 11.4 построена как краткое описание устанавливаемых значений и способа их установки. В первой колонке описываются функции, которые можно использовать для установки одного или нескольких значений прямо в GdkGC. Во второй колонке перечне-
лены имена полей структуры GdkGCValues, а третья колонка содержит маски, которые можно использовать при установке значения.
Таблица 11.4. Значения GdkGC устанавливаются при помощи какой-либо функции или структуры GdkGCValues
Обращение к функции
Поле GdkGCValues
Маска GdkGCValues
gdk_gc_set_background
( GdkGC *gc, GdkColor * color)
Background
GKK_GC_BACKGRkUNK
gdk_gc_set_cli p_mask
( GdkGC *gc, GdkBitmap *mask)
Clip_mask
GKK_GC_CLIP_MASK
gdk_gc_set_cli p_origin
Cli p__x_origin
GKK_GC_CLIP_X_kRIGIN
( GdkGC *gc, gint x, gint y) gdk_gc__set_cli p_recta ngle
Clip^y^origin
GKK_GC__CLIP_Y__kRIGIN
( GdkGC *gc, GdkRecta ngle *rectangle) gdk_gc_set_cli p_region
( GdkGC *gc, GdkRegion *region)
gdk_gc_set_dashes(GdkGC *gc, gint dash_offset, gchar dash_list[], gint list_iengthj
gdk_gc_set_exposures
( GdkGC *gc, gint exposures)
Graphics__ exposures
GKK_GC_EXPkSURES
gdk_gc_set_fill
( GdkGC *gc, GdkFill fill)
Fill
GKK__GC_FILL
gdk_gc_set_font( GdkGC
*gc, GdkFont *font)
Font
GKK_GC_FkNT
gdk_gc_set_ foreground
( GdkGC *gc, GdkColor *color)
Foreground
GKK_GC_FkREGRkUNK
gdk_gc_set_fucntion
( GdkGC *gc, GdkFunction function)
Function
GKK_GC_FUNCTIkN
gdk_gc_set_line_
Line_width
GKK_GC_LINE_WIKTH
attributes( GdkGC *gc, gint line__width,
Line_style
GKK_GC_LINE_STYLE
GdkLineStyle line_style,
Cap_style
GKK_GC_CAP_STYLE
GdkCapStyle cap_style, GdkJoinStyle join_style)
Join_style
GKK_GCJkIN_STYLE
gdk_gc_set_sti pple
( GdkGC *gc, GdkPixmap *stipple)
Sti pple
GKK_GC_STIPPLE
gdk_gc_set_subwindow
( GdkGC *gc,
GdkSubwindowMode mode)
Subwindow_mode
GKK_GC_SUBWINKkW
gdk qc set tile( GdkGC
*gc, GdkPixmap *tile)
Tile
GKK_GC_TILE
gdk_gc_set_ts_origin
ts_x_origin
GKK_GCJTS_X_kRIGIN
( GdkGC *gc, gint x, gint y)
ts_y_origin
GKK_GC_TS_Y_kRIGIN
Диалоговое окно для выбора цветов
Существует диалоговое окно, которое позволяет пользователю произвести выбор цвета. Следующий образец программы отображает диалоговую панель и постоянно обновляет ее окно для сопоставления с текущими установками.
/** selection.с **/
#include <gnome.h>
'
GtkWidget *makeColorBox();
void showColorsei(GtkWidget *widget,gpointer data);
void changeColor(GtkWidget *widget,
GtkColorSelection *colorSel);
void destroyColorsel(GtkWidget *widget,
gpointer data);
void helpColorsel(GtkWidget *widget,gpointer data);
11
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
16
static GtkWidget *csDialog = NULL;
static GtkWidget *area;
.
int main(int argc,char *argv[])
{
GtkWidget *app;
GtkWidget *colorBox;
24
gnome_init("selection","1.0",argc,argv);
app = gnome_app_new("selection","Color Selection");
gtk_signal_connect(GTK_OBJECT(app),"delete_event",
GTK_SIGNAL_FUNC(eventDelete),NULL);
gtk_signal_connect(GTK_OBJECT(app),"destroy",
GTK_SIGNAL_FUNC(eventDestroy),NULL);
31
colorBox = makeColorBox();
33
gnome_app_set_contents(GNOME_APP(app),colorBox);
gtk_widget_show_all(app);
gtk_main();
exit(0);
}
GtkWidget *makeColorBox()
{'
GtkWidget *colorbox;
GtkWidget *button;
43
colorbox = gtk_vbox_new(FALSE,0);
gtk_container_set_border_width(
GTK_CONTAINER(colorbox),10);
47
48area = gtk_drawing_area_new();
49gtk_widget_set_usize(area,300,200);
50gtk_box_pack_start(GTKBOX(colorbox),
51area,FALSE,FALSE, 0);
52 53button = gtk_button_new_with_label("Select");
54gtk_box_pack_start(GTK_BOX(colorbox),
55button,FALSE,FALSE, 0) ;
56gtk_signal_connect(GTK_OBJECT(button),"clicked",
57GTK_SIGNAL_FUNC(showColorsei),NULL);
58
59return(colorbox);
60 }
61 void showColorsel(GtkWidget *widget,gpointer data) {
62GtkWidget *colorSel;
63GtkWidget *button;
64
65if(csDialog == NULL){
66csDialog = gtk_color_selection_dialog_new(
67"Selected color fills the rectangle");
68gtk_signal_connect(GTK_OBJECT(csDialog),
69"destroy",
70GTK_SIGNAL_FUNC(destroyColorsei),NULL);
71
72colorSel =
73GTK_COLOR_SELECTION_DIALOG(csDialog)->colorsei;
74gtk_signal_connect(GTK_OBJECT(colorSel),
75"color_changed",
76GTK_SIGNAL_FUNC(changecolor),colorSel);
77
7879808182838485868788899091929394959697989910010110210310410510610710810978798081828384858687888990919293949596979899100101102103104105106107108109button = GTK_COLOR_SELECTION_DIALOG( csDialog)->ok_button;
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
gtk_signal_connect(GTK_OBJECT(button),"clicked", GTK_SIGNAL_FUNC(destroyColorsel),NULL);
button = GTK_COLOR_SELECTION_DIALOG( csDialog)->cancel_button;
gtk_signal_connect(GTK_OBJECT(button),"clicked", GTK_SIGNAL_FUNC(destroyColorsei),NULL);
button = GTK_COLOR_SELECTION_DIALOG( csDialog)->help_button;
gtk_signal_connect(GTK_OBJECT(button),"clicked", GTKSIGNALFUNC(helpColorsel),NULL);
}
gtk_widget_show(csDialog);
}
void changeColor(GtkWidget *widget, GtkColorSelection *colorSel) {
gdouble colorArray[4];
GdkColor color;
GdkColormap *colormap;
gtk_color_selection_get_color(colorSel,colorArray); color.red = (gushort)(OxFFFFF * colorArray[0]);
color.green = (gushort)(OxFFFFF * colorArray[1]);
color.blue = (gushort)(OxFFFFF * colorArray[2]); colormap = gdk_colormap_get_system();
gdk__color_alloc(colormap, &color); gdk_window_set_background(area->window,&color);
gdk_window_clear(area->window);
}
void destroyColorsel(GtkWidget *widget,gpointer data) { if(csDialog != NULL) {
110gtk_widget_destroy(csDialog);
111csDialog = NULL;
112}
113 }
114 void helpColorsel(GtkWidget ♦widget,gpointer data) {
115gnome_ok_dialog("Sorry.\nNo help available");
116 }
117 gint eventDelete(GtkWidget *widget,
118GdkEvent *event,gpointer data) {
119return(FALSE);
120 }
121 gint eventDestroy(GtkWidget *widget,
122GdkEvent *event,gpointer data) {
123gtk_main_quit();
124return(O);
125 }
В строках с 25 по 30 программа инициализируется. Вызов makeColorBox() в строке 32 создает виджет, который вставляется в главное окно при обращении к функции gnome_app_set_contents() в строке 34.
Главное окно приложения создается функцией makeColorBox(), начинающейся со строки 39. Вертикальный контейнер строится в строках с 44 по 46. В это окно вставляются два виджета. В строках с 48 по 51 создается область для рисования и вставляется в вертикальное окно как самый верхний виджет. В строках с 53 по 55 создается кнопка и вставляется ниже области для рисования. В строке 56 кнопке назначается функция обратного вызова showColorsel().
Функция обратного вызова showColorsel(), начинающаяся в строке 61, вызывается для появления окна выбора цвета. Указатель к виджету, заданный как csDialog в строке 17, объявлен статическим, поэтому окно надо создавать только один раз. Если проверка в строке 65 показывает, что csDialog — NULL, то это должно быть первое обращение к этой функции и необходимо построить диалоговое окно. Полностью диалоговое окно строится при помощи функции gtk_color__selection_dialog_new() в строке 66. Все, что осталось сделать, — это установить функцию обратного вызова. Поэтому вызов функции gtk_signal_connect() в строке 68 форсирует обращение к функции destroyColorsel() всякий раз, когда окно закрывается менеджером окон (подобно тому, как если бы пользователь выбрал кнопку закрытия в верхнем правом углу). В самом низу функции showColorsel() в строке 91 располагается обращение к функции gtk_widget_show(), выполняющее высвечивание диалогового окна. Если окно уже отображается на экране, то вызов этой функции безрезультатен. Таким образом, можно нажать кнопку Select в главном окне несколько раз, но появиться может только одно диалоговое окно. Результат показан на рис. 11.6.
Обратный вызов, определенный в строках с 72 по 76, инициирует вызов функции changeColor() каждый раз, когда пользователь меняет установки цвета в диалоговом окне. В окне имеются три кнопки, и, чтобы сделать окно полнофункциональным, необходимо назначить им функции обратного вызова. В строках с 78 по 85 кнопкам ОК и Cancel назначается функция обратного вызова destroyColorsel(). В строках с 86 по 89 кнопке Help приписывается функция обратного вызова helpColorsel().
Функция обратного вызова changeColor(), начинающаяся со строки 93, вызывается всякий раз, когда пользователь изменяет установки цвета в диалоговом окне. Эта функция выделяет цвет и использует его для раскрашивания области для рисования глав-
Рисунок 11.6.Виджет выбора цвета и его родительское окноРисунок 11.6.Виджет выбора цвета и его родительское окно
Рисунок 11.6.
Виджет выбора цвета и его родительское окно
Рисунок 11.6.
Виджет выбора цвета и его родительское окно
ного окна. Обращение к gtk_color_selection_get_color() в строке 99 выбирает текущую информацию о цвете из массива значений с плавающей запятой. Каждое из трех значений цвета (четвертый член массива — это значение alpha, или установка прозрачности) в массиве лежит в диапазоне от 0.0 до 1.0, поэтому в строках с 100 по 102 они масштабируются для правильного диапазона объекга GdkColor. Карта цветности, полученная в строке 103, используется для выделения цвета с помощью функции gdk_color_alloc() в строке 104. В строках 105 и 106 сначала вызывается функция gdk_window_set_background () для вставки нового цвета как фонового, а затем вызывается функция gdk_window_clear () для закрашивания фоновым цветом полного окна.
Функция обратного вызова destroyColorself) в строке 108 вызывается для закрытия диалогового окна. Диалоговое окно разрушается, и его указатель принимает значение NULL; для создания нового диалогового окна необходим другой вызов функции showColorself).
Функция обратного вызова для оказания помощи, заданная в строке 114, вызывается всякий раз, когда бы в диалоговом окне ни нажималась кнопка Help. Всплывает диалоговое окно кнопки ОК, информирующее, что помощь недоступна.
О структуре GtkStyle
Внутри каждого виджета имеется структура GtkStyle, содержащая графические контексты и цвета, которые используются для прорисовки виджета в каждом из его состояний. Есть составные графические контексты, так как виджет может иметь несколько видов. Например, кнопка изменяет цвет при ее нажатии. Или затенение вокруг кнопки меняет цвета, чтобы выделить ее. Любая кнопка выглядит по-другому, когда она недоступна, как это часто случается с кнопками меню. Кнопка может быть украшена цветными растровыми изображениями вместо текста. Виджеты - это более сложные компоненты, нежели кнопки, и требуют дополнительных установок.
Чтобы извлечь копию структуры GtkStyle из виджета, используйте функцию gtk_widget_get_style():
GtkWidget *widget;
GtkStyle *style;
style = gtk_widget_get_style(widget);
Возвращаемое значение — это указатель на структуру, используемую в виджете. Данные такой структуры достаточно низкого уровня, и с ними следует осторожно обращаться. Возможно, не следует использовать поля, описанные ниже тега /* private */, так как они предназначены для внутренних операций и их можно изменить таким образом, что произойдет сбой программы. Структура выглядит следующим образом:
struct _GtkStyle { GtkStyleClass *class; GdkColor fg[5]; GdkColor bg[5]; GdkColor light[5]; GdkColor dark[ 5 ]; GdkColor mid[5]; GdkColor text[5]; GdkColor base[5]; GdkColor black; GdkColor white;
GdkFont *font; GdkGC *fg_gc[5]; GdkGC *bg_gc[5]; GdkGC *light_gc[5]; GdkGC *dark_gc[ 5 ]; GdkGC *mid_gc[ 5 ]; GdkGC *text_gc[5]; GdkGC *base_gc[5]; GdkGC *black_gc; GdkGC *white_gc;
GdkPixmap *bg_pixmap[ 5 ];
/* private */ gint ref_count; gint attach_count; gint depth;
GdkColormap *colormap; GtkThemeEngine *engine; gpointer engine_data; GtkRcStyle *rc_style; GSList *styles;
В этой структуре определены большая часть графического контекста и цвета. Наиболее общая причина получения доступа к этой структуре — выбор по умолчанию черного и белого цветов, или черных и белых графических контекстов. Существуют массивы цветов и графических контекстов, которые используются виджетом для собственной прорисовки в разнообразных состояниях. Пять состояний задаются энумератором (перечислимым типом) GtkStateType:
typedef enum {
GTK_STATE_NORMAL,
GTK_STATE_ACTIVE,
GTK_STATE_PRELIGHT,
GTK_STATE_INSENSITIVE } GtkStateType;
Каждое из этих состояний зависит от виджета. Значение GTK_STATE_NORMAL — это виджет в состоянии ожидания инструкций (например, кнопка, которой еще не коснулась
мышь). Состояние GTK_STATE_ACTIVE используется, когда активизируется виджет (нажатие кнопки). Состояние GTK_STATE_PRELIGHT обозначает, что указатель мыши находится внутри виджета, но никакая кнопка мыши не нажата. Состояние GTK_STATE_INSENSITIVE указывает, что виджет недоступен (стала серой кнопка меню).
Выводы
Использование графических контекстов и цветных объектов может упростить рисование и закрашивание в окне. Применяя различные опции, вы можете создать любое окно, какое только захотите. В этой главе описано, как:
^ Нарисовать все пикселы с использованием объекта GdkGC, называемого графическим контекстом.
В Информация о цвете хранится в объекте GdkColor. Сам объект GdkColor может храниться в объекте GdkGC или как основной цвет, или как фоновый. Обычно виджет содержит большое число объектов GdkGC и GdkColor и использует их в разное время.
$* Можно выбрать пикселы для рисования, используя монохромное растровое изображение (bitmap) как прямоугольный набор флагов, которые распознают, какие пикселы уже нарисованы.
> Полноцветное растровое изображение (PixMap) может быть загружено в память, включено в графический контекст и раскрашено прямо в окне.
^ Три различные опции могут быть сконфигурированы для рисования линий. Толщина линии может принимать значение, отличное от заданного по умолчанию значения, равного одному пикселу. По умолчанию рисуется непрерывная линия, но в то же время существуют функции, позволяющие изменять ее в соответствии с любым шаблоном штриховой линии. Линия также может быть нарисована со скругленными, остроконечными или тупыми концами или уголками (точками соединения линий).
В этой главе изложены некоторые требования к созданию полноцветных изображений. Информацию следующей главы можно использовать для оживления дисплея, отвечая на сигналы от мыши или клавиатуры. Множеством установок и характеристик дисплея также можно управлять при помощи аргументов командной строки приложения GNkME.
332332ГЛАВА12ГЛАВА12Мышь и клавиатураМышь и клавиатура
332
332
ГЛАВА
12
ГЛАВА
12
Мышь и клавиатура
Мышь и клавиатура
В этой главе
Как считывать и интерпретировать движение мыши и нажатия кнопок
' Как считывать и интерпретировать нажатия клавиш клавиатуры
/ Захват изображения с помощью мыши для получения ответа из диалогового окна
Обработка опций командной строки внутри приложения GNkME
В наипростейшей форме информация о мыши включает ее расположение на экране и сведения о щелчке кнопкой, но это еще не все. Вначале сервер X выясняет, какое окно содержит указатель мыши, и сообщает о событии владельцу этого окна. Однако если владелец окна захватил мышь, то все события отсылаются программе захвата изображения требуемой области экрана независимо от положения мыши. В действительности все несколько сложнее: программа может воспринимать события мыши от нескольких окон. В дополнение к этому надо знать, какая кнопка (или кнопки) была нажата, удерживается кнопка или нет, был ли произведен двойной щелчок или даже какие клавиши клавиатуры были нажаты во время действий мышью.
А ведь еще есть клавиатура. Одни ее клавиши отображаемы (нажатие клавиши способствует появлению на экране символа), а другие — нет. Некоторые используются просто для того, чтобы модифицировать значения других клавиш: например, клавиша Shift позволяет набирать большие (прописные) буквы. В большинстве приложений текстовые виджеты могут поддерживать это, но бывают случаи, когда необходимо, чтобы информация о каждом нажатии клавиши поступала именно в вашу программу.
К счастью, вся эта информация доступна в любом используемом вами окне в виде событий мыши и клавиатуры.
Реагирование на события мыши
В следующей программе используется канва из GNOME для выполнения рисования с некоторыми специальными возможностями.
/** mousefoliow.c **/
Iinclude <gnome.h>
3
struct stateStruct {
5 6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
gboolean havePoints;
gboolean drawing;
" gint x;
gint y;
GdkGC *lineGC;
gint eventDelete(GtkWidget *widget, GdkEvent ♦event,gpointer data);
gint eventDestroy(GtkWidget *widget, GdkEvent *event,gpointer data);
gboolean canvasEvent(GtkWidget *widget, GdkEvent *event,struct stateStruct *state);
♦define WIDTH 400
♦define HEIGHT 300
♦define INTERVAL 30
♦define RADIUS 20
int main(int argc,char *argv[]) {
GtkWidget *app;
GtkWidget *canvas;
struct stateStruct state;
gnome_init("mousefollow","1.0",argc,argv);
app = gnome_app_new("mousefollow",
"Following Mouse Events");
gtk_signal_connect(GTK_OBJECT(app),"delete_event", GTK_SIGNAL_FUNC(eventDelete),NULL);
gtksignalconnect(GTKOBJECT(app),"destroy", GTK__SIGNAL__FUNC( event Destroy) ,NULL);
canvas = gnome_canvas_new();
gtk_widget_set_usize(canvas,WIDTH,HEIGHT); gnomeappsetcontents(GNOME_APP(app),canvas); gtksignalconnect(GTKOBJECT(canvas),"event", GTKSIGNALFUNC(canvasEvent),&state);
gtk_widget_show_all(app);
gtk_main();
exit(0);
}
gboolean canvasEvent(GtkWidget *widget,
GdkEvent *event,struct stateStruct *state) {
GdkColor color;
GdkEventMotion *eventMotion;
GdkEventCrossing *eventcrossing;
GdkEventButton *eventButton;
GdkEventExpose *eventExpose;
static gint counter = 1;
static GdkColormap *colormap;
5960616259606162switch(event->type) {
59
60
61
62
59
60
61
62
case GDK_MAP:
g_print("%4d MAP\n",counter++);
colormap = gdk_colormap_get_system();
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
state->lineGC = gdk_gc_new(widget->window); state->havePoints = FALSE;
state->drawing = FALSE;
break;
case GDK_ENTER_NOTIFY:
gprint("%4d ENTER_NOTIFY\n",counter++);.
eventcrossing = (GdkEventCrossing *)event; state->x = eventCrossing->x;
state->y = eventCrossing->y; state->havePoints = TRUE;
break;
case GDK_LEAVE_NOTIFY:
g_print("%4d LEAVE_NOTIFY\nM,counter++); break;
case GDK_BUTTON_PRESS:
g_print("%4d BUTTON_PRESS\n",counter++); eventButton = (GdkEventButton *)event; if(eventButton->button == 1) { state->x = eventButton->x;
state->y = eventButton->y; state->havePoints = TRUE; state->drawing = TRUE;
} else if(eventButton->button == 3) {
color.red=(((double)rand()*0xFFFF)/RAND_MAX); color.green=(((double)rand()*OxFFFF)/RAND_MAX); color.blue=(((double)rand()*0xFFFF)/RANDMAX); gdk_color_alloc(colormap,&color);
gdk_gc_set_foreground(state->lineGC,Scolor);
}
break;
case GDK_BUTTON_RELEASE;
gprint("%4d BUTTON_RELEASE\n",counter++); eventButton = (GdkEventButton *)event;
if(eventButton->button == 1) { state->drawing = FALSE;
state->havePoints = FALSE;
}
break;
case GDK_2BUTTON_PRESS:
g_print("%4d 2BUTTON_PRESS\n",counter++); eventButton = (GdkEventButton *)event;
if(eventButton->button == 1) {
gdk_draw_arc(eventButton->window,state->lineGC, TRUE, eventButton->x - RADIUS, eventButton->y - RADIUS, 2 ♦ RADIUS,2 * RADIUS, 0,360*64);
}
break;
case GDK3BUTTONPRESS:
g_print("%4d 2BUTTON_PRESS\n",counter++); eventButton = (GdkEventButton *)event;
if(eventButton->button == 2)
exit(0);
break;
119120119120case GDKMOTIONNOTIFY:
119
120
119
120
g_print("%4d MOTION_NOTIFY\n",counter++);
eventMotion = (GdkEventMotion *)event;
if(state->havePoints && state->drawing) {
gdk_draw_line(eventMotion->window,
state->lineGC,
state->xrstate->yr
(gint)(eventMotion->x),
(gint)(eventMotion->y));
}
state->x=(gint)(eventMotion->x);
state->y=(gint)(eventMotion->y);
state->havePoints = TRUE;
break;
case GDKEXPOSE:
eventExpose = (GdkEventExpose *)event;
g_print("%4d EXPOSE\n",counter++);
state->drawing = FALSE;
state->havePoints = FALSE;
gdk_window_cLear(eventExpose->window);
break;
default:-
g_print("%4dOther:%d\n",counter++,event->type);
break;
}
return(TRUE);
}
gint eventDelete(GtkWidget *widget,
GdkEvent ♦event,gpointer data) {
return(FALSE);
}
gint eventDestroy(GtkWidget *widget,
GdkEvent *eventrgpointer data) {
gtk_main_quit();
return(O);
}
В этой программе с помощью некоторых комбинаций кнопок мыши рисуются окружности, меняется цвет и можно выйти из программы:
Выполнение захвата (протаскивание) с помощью левой кнопки мыши рисует линию текущего цвета.
Двойной щелчок левой кнопкой мыши позволяет нарисовать окружность.
Путем нажатия правой кнопки мыши можно изменить цвет, используемый для прорисовки линий и окружностей.
Тройной щелчок средней кнопкой мыши приводит к выходу из программы.
Раскрытие окна или любой части окна очищает его.
В строках с 38 по 42 создается виджет GnomeCanvas и происходит его присоединение к функции обратного вызова canvasEvent(). Функция обратного вызова, начинающаяся в строке 48, вызывается при первом создании окна, а после этого для каждого события мыши, происшедшего на канве. Все, что делает эта программа, происходит в функции обратного вызова под управлением мыши. Детали каждого из этих событий описаны в главе 9.
Структура, заданная в строке 4, — это список значений, определяющих состояние. При работе эти значения требуются на периоды от одного обращения к функции обратного
вызова до другого. Например, когда мышь перемещается в новое положение и рисуется линия, то необходимо знать предыдущее положение мыши, чтобы соединить точки. Образец структуры объявляется в основной ветви программы в строке 28, а в строке 35 при включении ее в обращение к функции gtk_signal_connect () адрес структуры передается функции обратного вызова в форме указателя данных.
Функция обратного вызова начинается в строке 48. В строке 56 задается счетчик counter, который используется для отображения номера каждого события. Всякий раз при вызове функции номер и тип события выводятся на стандартный вывод. Как только вы запустите программу и просмотрите список событий, то заметите, что практически каждое событие — это событие перемещения мыши, для каждого перемещения возникает одно событие. Кроме того, если кнопка мыши удерживается во время передвижения указателя мыши, то события, сообщающие о движении, продолжают передаваться этому окну, даже когда указатель мыши находится вне окна.
В строке 60 возникает реакция на событие GDK_MAP. Это событие происходит всякий раз, когда окно впервые создается и готово для отображения. Можно быть уверенным, что о нем будет сообщаться перед любым событием мыши. Эта программа имеет преимущество в том, что инициализация происходит только однажды. GdkGC строится в строках 62 и 63, а булевы переменные устанавливаются в значение FALSE, чтобы указать, что в структуре не содержатся точки координат и в настоящее время не выполняется рисование линии.
В строке 67 возникает реакция на событие GDK_ENTER_NOTIFY. Одно из этих событий происходит всякий раз, когда мышь входит в окно из какого-либо места на экране дисплея. Такая ситуация может возникнуть при первом появлении вновь созданного окна прямо под мышью, когда указатель мыши перемещается через край этого окна или входит прямо в центр этого окна из частично закрытого окна. В любом случае одно из этих событий происходит всякий раз, когда мышь входит в окно. В строках с 70 по 72 принимается копия точки входа и меняется состояние, чтобы показать правильность точек в структуре state.
В строке 74 возникает реакция на событие GDK_LEAVE_NOTIFY. Это событие происходит всякий раз, когда мышь покидает окно. Оно неэффективно в этой программе, так как ничего не выполняется.
В строке 77 возникает реакция на событие GDK_BUTTON_PRESS. Это событие извещает, что одна из кнопок мыши была нажата. В строке 80 проверяется, нажата ли левая кнопка (кнопка номер 1): если да, то текущее положение в окне устанавливается в текущее положение указателя мыши. Состояние обновляется для отображения проверяемой точки в структуре state и рисования линии. Если была нажата правая кнопка (кнопка номер 3), что проверяется в строке 85, то создается новый цвет и сохраняется в графическом контексте как основной цвет.
В строке 93 возникает реакция на событие GDK__BUTTON_RELEASE. В этой программе событие освобождения имеет значение, только если нажата левая кнопка (номер 1), что должно обозначать окончание рисования. Если действительно нажимается левая кнопка, то состояние меняется и рисование не выполняется.
ПРИМЕЧАНИЕ
Эти события полностью независимы друг от друга. Например, можно удерживать левую кнопку и выполнять перемещение для прорисовки линии и в то же время щелкнуть правой кнопкой для изменения цвета линии.
В строке 101 возникает реакция на событие GDK_2BUTTON_PRESS — это двойной щелчок. Только это событие в программе реагирует на левую кнопку, оно вызывает обращение к функции gdk_draw_arс() в строке 105 и рисует заполненную (залитую) окружность там, где расположена мышь.
В строке 113 возникает реакция на событие GDK_3BUTTON_PRESS — это тройной щелчок. Проверка в строке 116 определяет, нажата ли средняя кнопка (кнопка 2); если да, то происходит немедленный выход из программы.
ПРИМЕЧАНИЕ
Когда бы ни происходил двойной или тройной щелчок, регистрируется одиночное событие. Это случается, когда происходит событие GKK IBUTTkN PRESS, а также при GKK_BUTTkN_PRESS или GKK_BUTTkN__RELEASE. Последние два известны как действительные события (real events), так как они представляют реальные события оборудования, в то время как двойной щелчок называется псевдособытием (pseudo event), так как он генерируется программным обеспечением — это когда близки по времени два действительных события. Такая же ситуация и с тройным щелчком: происходит по два каждого из событий нажатия и освобождения кнопок мыши.
В строке 119 возникает реакция на событие GDK_MOTION_NOTIFY. Это событие происходит, когда бы ни передвигалась мышь. В строке 122 проверяется текущее состояние, и если в структуре state имеются допустимые точки и программа в настоящее время
Рисунок 12.1.Рисование окружностей и линий с помощью мышиРисунок 12.1.Рисование окружностей и линий с помощью мышивыполняет прорисовку линий, то линия рисуется от старой точки к новой. Независимо от того, рисуется линия или нет, значения х и у в структуре state обновляются для отображения нового положения мыши.
Рисунок 12.1.
Рисование окружностей и линий с помощью мыши
Рисунок 12.1.
Рисование окружностей и линий с помощью мыши
В строке 133 возникает реакция на событие GDK_EXPOSE. Это событие происходит, когда раскрывается часть окна. В реальном приложении обычно перерисовывается экран, но поскольку в этой программе не требуется сохранять данные, экран очищается и устанавливается режим, который указывает, что точки отсутствуют и рисование не производится.
Результат, который можно получить при работе этой программы, показан на рис. 12.1.
Захват и освобождение мыши
Пришло время научить вашу программу получать некоторые указания от пользователя перед продолжением работы. Чтобы это сделать, можно создать всплывающее окно и захватить мышь, не позволяя тем самым продолжать работу до указаний пользователя.
Для выполнения захвата мыши приходящие от нее события просто перехватываются в окне. Вторая и дополнительная цель захвата — ограничение движения мыши. Следующая программа — это пример захвата мыши, меняющего курсор для отображения ее состояния, и ожидание нажатия кнопки перед ее освобождением.
/** mousegrab.с ♦♦/
#include <gnome.h>
-
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
void grabMousefGtkWidget *widget,GtkWidget *containWidget);
void ungrabMouse(GtkWidget *widget,gpointer data);
10
int main(int argc,char *argv[])
{.
GtkWidget *window;.
GtkWidget *box;
GtkWidget *button;
16
gnome__init( "mousegrab", "1.0",argc,argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_container_set_border_width(
GTK_CONTAINER(window), 30);
gtk_signal_connect(GTK_OBJECT(window),"delete_event",
GTK_SIGNAL_FUNC(eventDelete),NULL);
gtk_signal_connect(GTK_OBJECT(window),"destroy",
GTK__SIGNAL__FUNC( event De stroy),NULL);
25
box = gtk_vbox_new(FALSE,0);
27
button = gtk_button_new_with_label("Grab Mouse");
gtk_box_pack_start(GTKBOX(box),button,FALSE,FALSE,0) ;
gtk_signal_connect(GTK_OBJECT(button),"clicked",
GTK_SIGNAL_FUNC(grabMouse),window);
32
button = gtk_button_new_with_label("Ungrab Mouse");
gtkboxpackend(GTK_BOX(box),button,FALSE,FALSE, 0);
gtk_signal_connect(GTK_OBJECT(button),"clicked",
GTK_SIGNAL_FUNC(ungrabMouse),NULL);
37
gtk_container_add(GTK_CONTAINER(window),box);
gtk_widget_show_all(window);
gtk_main();
exit(0);
}
void grabMouse(GtkWidget *widget,GtkWidget *containWidget)
{
GdkWindow *window = containWidget->window;
GdkCursor *cursor • gdkcursornew(GDKCROSSHAIR);
gdk_pointer_grab(window,
TRUE,
(GdkEventMask)O,
window,
cursor,
2GDK_CURRENT_TIME);
}
void ungrabMouse(GtkWidget *widget,gpointer data) {
if(gdk_pointer_is_grabbed())
gdk_pointer_ungrab(GDK_CURRENT_TIME);
}
58
59 gint eventDelete(GtkWidget *widget,
60GdkEvent ♦event,gpointer data) {
61return(FALSE);
62 }
63 gint eventDestroy(GtkWidget *widget,
64GdkEvent ♦event,gpointer data) {
65 if(gdk_pointer_is_grabbed())
66gdk_pointer_ungrab(GDK_CURRENT_TIME);
67gtk_main_quit();
68return(O);
69 }
В строке 26 строится вертикальный контейнер. В строках с 28 по 36 создается пара кнопок, добавляется в контейнер и каждой из них назначается функция обратного вызова. Функция обратного вызова захвата мыши называется grabMouse (), а функция ее освобождения — ungrabMouse(). При подключении к grabMouse () в строке 31 основное окно используется как данные, передаваемые функции.
Функция обратного вызова grabMouse (), начинающаяся со строки 43, обращается к функции gdk_pointer_grab () для ограничения движения мыши в прямоугольной области указанного окна.
В строке 45 из GtkWidget извлекает GdkWindow, передаваемое функции обратного вызова как указатель данных. Это окно используется как первый аргумент в строке 47, а затем — как четвертый аргумент в строке 50. Первый аргумент указывает окно, которое получает все события мыши: в процессе Захвата мыши это окно становится единственным, которое может получать события мыши независимо от ее положения. Еще одно использование в этом примере окна как четвертого аргумента ограничивает передвижение мыши в нем. В этом примере одно и то же окно используется для двух целей, поэтому указатель мыши не может покинуть окно, в котором принимаются события.
Второй аргумент в строке 48 принимает значение TRUE, так что входящие события передаются от захваченного окна к его подокнам. В этом примере в качестве подокон выступают две кнопки. Если кнопки принимают значение FALSE, то они не получают никаких событий от мыши и нет способа освободить окно.
ПРИМЕЧАНИЕ
Всегда оставляйте себе возможность выхода. Если вы выполняете захват мыши и ваша программа не может освободить ее, то вы застряли. Даже завершение программы для закрытия окна не приведет к освобождению мыши: захват остается активным в прямоугольной области, которая ранее была окном. Сервер X фактически выполняет захват мыши и удерживает ее до тех пор, пока не получает определенную команду об освобождении.
Строка 49 — это маска события для указания того, какие события надо отправить захваченному окну. В этом примере нет необходимости добавлять какие-нибудь события, потому что уже запланированные события все равно будут доставлены кнопкам, являющимся дочерними окнами захваченного окна, позволяя выполнять щелчки на них. Если вы собираетесь создавать свои собственные события, то можно использовать любые комбинации масок событий, показанных в табл. 12.1. Например, если вы хотите получить уведомление всякий раз, когда были нажаты кнопки мыши или клавиши клавиатуры, то используйте это для значения маски:
GDK_BUTTON_PRESS_MASK | GDK_KEY_PRESS MASK
Таблица 12.1. Поразрядные маски для требуемых событий
МаскаМаскаGKK_EXPkSURE_MASKGKK_PkINTER_MkTIkN__MASK GKKJWNTER_MkTIkNJ4INT_MASKGKK_BUTTkN_MkTIkN_MASKGKK_BUTTkN1_MkTIkN_MASKGKK_BUTTkN2_MkTIkN_MASKGKK_ BUTTkN3_MkTIkN_MASKGKK_BUTTkN_PRESS_MASK GKK_BUTTkN_RELEASE_MASK GKK_KEY__PRESS_MASK GKK_KEY_RELEASE _MASK GKK_ENTER_NkTIFY_MASK GKK_LEAVE_NkTIFY_MASK GKK_FkCUS_CHANGE_MASKGKK_STRUCTURE_MASKGKK_PRkPERTY_CHANGE_MASKGKK__VISIBILITY_NkTIFY__MASKGKK_PRkXIMITYJN_MASKGKK_PRkXIMITY_kUT_MASKGKK_SUBSTRUCTURE_MASKGKK_ALL_EVENTS_MASKGKK_EXPkSURE_MASKGKK_PkINTER_MkTIkN__MASK GKKJWNTER_MkTIkNJ4INT_MASKGKK_BUTTkN_MkTIkN_MASKGKK_BUTTkN1_MkTIkN_MASKGKK_BUTTkN2_MkTIkN_MASKGKK_ BUTTkN3_MkTIkN_MASKGKK_BUTTkN_PRESS_MASK GKK_BUTTkN_RELEASE_MASK GKK_KEY__PRESS_MASK GKK_KEY_RELEASE _MASK GKK_ENTER_NkTIFY_MASK GKK_LEAVE_NkTIFY_MASK GKK_FkCUS_CHANGE_MASKGKK_STRUCTURE_MASKGKK_PRkPERTY_CHANGE_MASKGKK__VISIBILITY_NkTIFY__MASKGKK_PRkXIMITYJN_MASKGKK_PRkXIMITY_kUT_MASKGKK_SUBSTRUCTURE_MASKGKK_ALL_EVENTS_MASKСобытие
Маска
Маска
GKK_EXPkSURE_MASK
GKK_PkINTER_MkTIkN__MASK GKKJWNTER_MkTIkNJ4INT_MASK
GKK_BUTTkN_MkTIkN_MASK
GKK_BUTTkN1_MkTIkN_MASK
GKK_BUTTkN2_MkTIkN_MASK
GKK_ BUTTkN3_MkTIkN_MASK
GKK_BUTTkN_PRESS_MASK GKK_BUTTkN_RELEASE_MASK GKK_KEY__PRESS_MASK GKK_KEY_RELEASE _MASK GKK_ENTER_NkTIFY_MASK GKK_LEAVE_NkTIFY_MASK GKK_FkCUS_CHANGE_MASK
GKK_STRUCTURE_MASK
GKK_PRkPERTY_CHANGE_MASK
GKK__VISIBILITY_NkTIFY__MASK
GKK_PRkXIMITYJN_MASK
GKK_PRkXIMITY_kUT_MASK
GKK_SUBSTRUCTURE_MASK
GKK_ALL_EVENTS_MASK
GKK_EXPkSURE_MASK
GKK_PkINTER_MkTIkN__MASK GKKJWNTER_MkTIkNJ4INT_MASK
GKK_BUTTkN_MkTIkN_MASK
GKK_BUTTkN1_MkTIkN_MASK
GKK_BUTTkN2_MkTIkN_MASK
GKK_ BUTTkN3_MkTIkN_MASK
GKK_BUTTkN_PRESS_MASK GKK_BUTTkN_RELEASE_MASK GKK_KEY__PRESS_MASK GKK_KEY_RELEASE _MASK GKK_ENTER_NkTIFY_MASK GKK_LEAVE_NkTIFY_MASK GKK_FkCUS_CHANGE_MASK
GKK_STRUCTURE_MASK
GKK_PRkPERTY_CHANGE_MASK
GKK__VISIBILITY_NkTIFY__MASK
GKK_PRkXIMITYJN_MASK
GKK_PRkXIMITY_kUT_MASK
GKK_SUBSTRUCTURE_MASK
GKK_ALL_EVENTS_MASK
GdkEventExpose. Окно вышло на передний план и его надо нарисовать.
GdkEventMotion. Мышь была передвинута.
Сокращается число событий, когда используется с GKK_PkINTER_MkTIkN_MASK.
GdkEventMotion. Мышь перемещается с одной или несколькими удерживаемыми кнопками.
GdkEventMotion. Мышь перемещается, пока удерживается кнопка 1 (левая кнопка).
GdkEventMotion. Мышь перемещается, пока удерживается кнопка 2 (средняя кнопка).
GdkEventMotion. Мышь перемещается, пока удерживается кнопка 3 (правая кнопка).
GdkEventButton. Была нажата кнопка мыши.
GdkEventButton. Кнопка мыши была отпущена. GdkEventKey. Была нажата клавиша клавиатуры. GdkEventKey. Была отпущена клавиша клавиатуры. GdkEventCrossing. Указатель мыши вошел в окно. GdkEventCrossing. Указатель мыши покинул окно. GdkEventFocus. Окно либо потеряло фокус, либо попало в фокус для клавиатуры.
GcflcEventStructure. Изменился размер или положение окна.
GdkEventProperty. Изменилось внутреннее свойство окна.
GdkE vent Visibility. Окно сделалось частично или полностью видимым или стало невидимым.
GdkE ventProximity. Палец был помещен на сенсорный экран или перо было помещено на планшет.
GdkE ventProximity. Палец был убран с сенсорного экрана или перо было поднято с планшета.
GdkEventConfigure. Событие возникло для каждого подокна выбранного окна.
Получение всех событий.
Пятый аргумент на строке 51 — это курсор. Указатель мыши становится курсором, когда 1цышь захвачена, и возвращается к исходному виду, когда она освобождается. Использование указателя NULL для курсора приводит к тому, что курсор остается неизменным. На рис. 12.2 показано окно с измененным курсором в форме перекрестия.
Последний аргумент в строке 52 — это предполагаемое время захвата мыши. Как одно из преимуществ, константа GDK_CURRENT_TIME автоматически конвертируется в текущее время, то, которое вы обычно хотите.
ИИШЕЦ+Grab Mouse |Ungrab Mouse]ИИШЕЦ+Grab Mouse |Ungrab Mouse]Рисунок 12.2.Захваченная мышь с измененным курсоромРисунок 12.2.Захваченная мышь с измененным курсоромСуществует два способа отказаться от захвата. Нажатие кнопки " Ungrab " исполняет функцию обратного вызова ungrabMouse ( ) из строки 54. Если обращение к gdk_pointer_is_grabbed () возвращает TRUE, то мышь была захвачена и может быть освобождена. Обращение к gdk_pointer_ungrab() освобождает указатель. Эта программа не позволяет мыши покинуть окно, так что мышь не может закрыть окно, пока действует захват. Однако все равно желательно освобождать захваченную мышь при выходе из
ИИШЕЦ+Grab Mouse |Ungrab Mouse]
ИИШЕЦ+Grab Mouse |Ungrab Mouse]
Рисунок 12.2.
Захваченная мышь с измененным курсором
Рисунок 12.2.
Захваченная мышь с измененным курсором
программы. Функция eventDestroy() в строке 63 вызывается при разрушении окна, поэтому если мышь захвачена, то путем вызова gdk_pointer_ungrab() из строки 66 происходит ее освобождение.
Чтение символов с клавиатуры
Если вы набираете что-либо на клавиатуре, то информация о нажатии клавиш переходит только одному окну, в свою очередь, она переходит одному приложению. Если окно установлено для приема входной информации с клавиатуры, то говорят, что оно получило фокус (focus) для клавиатуры. Иногда происходит нечто, после чего окно получает фокус. В основном это происходит для того, чтобы мышь выбрала окно. На окне с текущим фокусом строка заголовка наверху изменяет цвет.
В большинстве случаев приходится использовать виджеты ввода текста для прочтения информации с клавиатуры, но если потребуется произвести чтение прямо с клавиатуры, то можно сделать и это. Просто в таком случае потребуется установить корректный набор обратных вызовов. Существует два основных вида событий клавиатуры: один, когда клавиша нажимается, а другой, когда отпускается (освобождается). Если надо просто нажимать клавиши, то используйте событие нажатия клавиши. Событие отпускания клавиши необходимо, если требуется знать, нажата ли какая-нибудь из клавиш.
В следующем примере производится чтение с клавиатуры и отображается информация о нажатых и отпущенных клавишах.
/*♦ keylisten.с ♦♦/
Iinclude <gnome.h> 3
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventFocus(GtkWidget *widget,
GdkEvent*event,gpointerdata);
gint eventPressKey(GtkWidget *widget,
GdkEvent*event,gpointerdata);
gint eventReleaseKey(GtkWidget *widget,
GdkEvent*event,gpointerdata);
14
staticGtkWidget*keyLabel;
staticGtkWidget*scrollLabel;
staticGtkWidget*focusLabel;
18
gboolean altKeyDown = FALSE;
gboolean controlkeyDown = FALSE;
gboolean metaKeyDown = FALSE;
2223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787922232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879gboolean leftShiftKeyDown = FALSE;
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
gboolean rightShiftKeyDown = FALSE;
int main(int argc,char *argv[])
{.
GtkWidget «window;
GtkWidget «box;
gnome_init("key1i sten","1.0",argc,argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_widget_set_usize(window,500,120);
gtk_container_set_border_width(
GTKCONTAINER(window),30);
gtk_signal_connect(GTK_OBJECT(window),"delete_event", GTK_SIGNAL_FUNC(eventDelete),NULL);
gtk_signal_connect(GTK_OBJECT(window),"destroy", GTK_SIGNAL_FUNC(eventDestroy),NULL);
gtk_signal__connect (GTK_OBJECT (window), "focus__in_event", GTK_SIGNAL_FUNC(eventFocus),NULL);
gtk_s ignal_connect(GTK_OBJECT(window), "focus_out_event", GTK_SIGNAL_FUNC(eventFocus),NULL);
gtk_signal_connect(GTK_OBJECT(window), "key_press_event", GTK_SIGNAL_FUNC(eventPressKey),NULL);
gtk_signal_connect(GTK_OBJECT(window), "key_release_event", GTK_SIGNAL_FUNC(eventReleaseKey),NULL);
gtk_widget_add_events(window,GDK_KEY_RELEASE_MASK);
box = gtk_vbox_new(FALSE,0);
keyLabel = gtk_label_new(" ");
gtk_box_pack_start(GTKBOX(box),keyLabel, FALSE,FALSE,0);
scrollLabel = gtk_label_new(" ");
gtk_box_pack_start(GTKBOX(box),scrollLabel, FALSE,FALSE,0);
focusLabel = gtk_label_new("Focus?");
gtk_box_pack_end(GTKBOX(box),focusLabel, FALSE,FALSE,0);
gtk_container_add(GTK_CONTAINER(window),box);
gtk_widget_show_all(window);
gtk_main();
exit(0);
} ■
gint eventFocus(GtkWidget «widget, GdkEvent «event,gpointer data) { GdkEventFocus «focus;
if(event->type == GDK_FOCUS_CHANGE) { focus = (GdkEventFocus ♦)event; if(focus->in)
gtk_label_set_text(GTK_LABEL(focusLabel), "Focus acquired");
80818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361378081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137else
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
gtk_label_set_text(GTK_LABEL(focusLabel), "Focus lost");
}
return(TRUE);
}
gint eventPressKey(GtkWidget *widget, GdkEvent *event,gpointer data) { static char keyList[80] = " ";
char lastKey[80];
int i;
int shift;
char work[10];
GdkEventKey *key = (GdkEventKey *)event;
switch(key->keyva|) {
case GDK_Alt_L:
case GDK_Alt_R:
altKeyDown = TRUE;
break;
case GDK_Control_L:
case GDK_Control_R:
controlKeyDown = TRUE;
break;
case GDK_Meta_L:
case GDK_Meta_R:
metaKeyDown = TRUE;
break;
case GDK_Shift_L:
leftShiftKeyDown = TRUE;
break;
case GDK_Shift_R:
rightShiftKeyDown = TRUE; break;
}
strcpy(work,gdk_keyval_name(key->keyval));
strcat(keyList," ");
strcat(keyList,work);
shift = strlen(keyList) - 60;
if(shift > 0) {
for(i=shift; keyList[i-l] 1= '\0'; i++) keyList[i-shift] = keyList[i];
}
gtk_label_set_text(GTK_LABEL(scrollLabel),keyList);
sprintf(lastKey,"GDK_%s",work);
if((key->keyval >= 0x20) && (key->keyval < 0x7F)j { sprintf(work,"%c",(gchar)key->keyval);
strcat(lastKey,work);
}
if(gdk_keyval_is_lower(key->keyval)) strcat(lastKey," (not upper case)");
else if(gdk_keyval_isupper(key->keyval)) strcat(lastKey," (upper case)");
sprintf(work,"[%02X]",key->keyval);
strcat(lastKey,work);
if(altKeyDown)
138strcat(lastKey,"ALT");
139if(controlKeyDown)
strcat(lastKey,"CONTROL");
if(metaKeyDown)
strcat(lastKey,"META");
if(leftShiftKeyDown)
strcat(lastKey,"LeftSHIFT");
if(rightShiftKeyDown)
strcat(lastKey,"RightSHIFT");
gtk_label_set_text(GTK_LABEL(keyLabel),lastKey);
148
return(TRUE);
}
gint eventReleaseKey(GtkWidget *widget,
GdkEvent *event,gpointer data) {
GdkEventKey *key = (GdkEventKey *)event;
154
switch(key->keyval) {
caseGDK_Alt_L:
caseGDK_Alt_R;
altKeyDown = FALSE;
break;
caseGDK_Control_L:
caseGDK_Control_R:
controlKeyDown = FALSE;
break;
caseGDK_Meta_L:
caseGDK_Meta_R:
metaKeyDown = FALSE;
break;
caseGDK_Shift_L:
leftShiftKeyDown = FALSE;
break;
caseGDK_Shift_R:
rightShiftKeyDown = FALSE;
break;
}
return(TRUE);
}
177
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data) {
return(FALSE);
}
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data) {
gtk_main_quit();
return(0);
}
В строках с 35 no 51 события присоединяются к главному окну приложения. Для выяснения того, получило окно фокус или нет, в строках с 39 по 44 к окну присоединяется функция обратного вызова eventFocus () таким образом, что вызывается всякий раз, когда окно попадает в фокус и теряет его. Обращение к gtk_signal_connect() в строке 45 назначает функцию обратного вызова eventPressKey() для каждого нажатия клавиши, а обращение к gtk_signal_connect() в строке 48 назначает функцию обратного вызова eventReleaseKey () для каждого освобождения клавиши. Хотя это
работает не совсем так, как вы ожидаете. Собственно все работает кроме обратного вызова для освобождения клавиш. По умолчанию виджет устанавливается для получения событий фокуса и нажатия клавиши, но не для событий освобождения клавиши. Обращение к gtk_widget_add_events( ) в строке 51, используя маску GDK_KEY_RELEASE_MASK, отмечает окно для получения событий освобождения клавиш и передает их любым зарегистрированным функциям обратного вызова.
ПРИМЕЧАНИЕ НАУЧНОГО РЕДАКТОРА
В литературе встречаются выражения иметь фокус, получить фокус или попасть в фокус (как в фотографии). Все эти выражения являются синонимами и обозначают выход окна, получившего фокус, на передний план.
На строках с 53 по 65 создаются три метки (надписи), которые затем вставляются в вертикальное окно. Верхняя надпись, которая называется key Label, содержит описание последнего нажатия клавиши. Вторая надпись, которая называется scrollLabel, перемещается справа налево, показывая наиболее свежие наборы нажатий клавиш. Третья надпись, которая называется f ocusLabel, указывает текущее состояние фокуса главного окна.
Функция eventFocus (), начинающаяся со строки 72, вызывается, когда окно получает или теряет фокус. Оператор условия в строке 77 проверяет, получен ли или потерян фокус, и устанавливает текст надписи для отображения текущего состояния.
Всякий раз, когда нажимается клавиша клавиатуры, функция eventPressKey() в строке 86 вызывается с информацией об этой клавише. Событие GdkEventKey содержит поле, которое называется keyval. Это поле содержит числовой ID (идентификатор) для самой клавиши. Существуют отдельные коды для всех специальных клавиш. ASCII- коды клавиш имеют такие же значения, как и ASCII-символы. Благодаря разнообразию клавиатур и интернционализации программного обеспечения существует более 1300 кодов клавиш. Если вы хотите посмотреть весь список, то просмотрите файл-заголовок gdkkeysyins.h.
Оператор switch в строке 95 выбирает некоторые специальные клавиши в соответствии с их значениями. В строках с 96 по 99 булевой переменной присваивается значение TRUE, которое указывает, что нажата клавиша Alt. Подобным образом в строках с 100 по 107 те же индикаторы устанавливаются для клавиш Control и Meta. Заметьте, что имеется два значения для каждой из этих клавиш (L и R — левая и правая), так как на клавиатуре могут быть две клавиши, а приложение возможно захочет узнать, какая из этих клавиш нажата. В строках со 108 по 113 для левой и правой клавиш Shift устанавливаются отдельные индикаторы.
На строках со 116 по 124 исправляется показываемый текст в передвигающемся окне и демонстрируются последние нажатые клавиши. Описательное имя значения клавиши копируется в работающие строки при помощи обращения к функции gdk_keyval_name() в строке 116. Такое описание — это просто сами символы, если они показываются; иначе — это слова, описывающие клавишу. Строки 117 и 118 присоединяют пробел и имя клавиши к строке key List, которая используется для обновления текста надписи. Цикл, заданный в строке 120, выполняется каждый раз, когда строка достигает своей максимальной длины. Для уменьшения длины строки символы слева не учитываются. В строке 124 запускается новая надпись при помощи gtk__label_set__text (). Реальное количество показываемых клавиш зависит от того, сколько символов необходимо для описания каждой из них.
В строках со 126 по 147 создается строка с описательной информацией о таком символе. В строке 126 начинается описание путем присоединения впереди имени, которое запрашивается от предыдущего обращения к функции gdk_keyval_name (), приставки GDK_. Эта форма имени определяется константой, которую можно использовать для идентификации символа (например, оператор switch в строке 95). В строке 127 проверяется, является ли символ распечатываемым символом ASCII, и если является, то сам символ добавляется в описание. В строках с 131 по 134 происходит определение того, является ли символ прописной буквой или нет. Заметьте, что несмотря на макрос islower() из стандартной библиотеки языка С, функция gdk_keyval_is_lower () возвращает TRUE для каждого символа кроме прописных букв. В строках 135 и 136 само значение клавиши печатается как шестнадцатеричное число и происходит его добавление в строку. В строках со 137 по 146 проверяются Значения булевых переменных, чтобы определить, удерживается ли нажатой какая-нибудь из специальных клавиш, если да, то эта информация добавляется в строку-описание. Обращение к функции gtk_label_set_text () в строке 147 вставляет новый текст в надпись.
Функция обратного вызова eventReleaseKey () в строке 151 вызывается всякий раз при освобождении клавиши. Только те из клавиш, что имеют к ней отношение, оператор switch в строке 95 определяет как нажатые. Если это одна из рассматриваемых клавиш, то соответствующее значение булевой переменной устанавливается в значение FALSE для указания того, что эта клавиша более не удерживается.
Рис. 12.3 отображает информацию о последней нажатой клавише и немного информации о клавише, нажатой перед ней. В верхней строке показан текущий символ как строчная буква с. Шестнадцатеричное значение с равно 0X63. Кроме того, когда была нажата клавиша, также удерживалась клавиша Control. Начиная с правого конца средней строки, можно увидеть, что последней нажатой клавишей была буква с. Левая клавиша Control была нажата прямо перед ней. Вы видите, что перед этим был нажат восклицательный знак (exclam).
GDK_c с (not upper case) f63] CONTROLol_L exclam a ShilLL J Control_L Shilt_L exclam ControlJ. c■Focus acquiredGDK_c с (not upper case) f63] CONTROLol_L exclam a ShilLL J Control_L Shilt_L exclam ControlJ. c■Focus acquiredРисунок 12.3.Наблюдение за нажатием клавишРисунок 12.3.Наблюдение за нажатием клавиш
GDK_c с (not upper case) f63] CONTROLol_L exclam a ShilLL J Control_L Shilt_L exclam ControlJ. c
■Focus acquired
GDK_c с (not upper case) f63] CONTROLol_L exclam a ShilLL J Control_L Shilt_L exclam ControlJ. c
■Focus acquired
Рисунок 12.3.
Наблюдение за нажатием клавиш
Рисунок 12.3.
Наблюдение за нажатием клавиш
Опции командной строки GNOME
Каждое GNOME-приложение имеет набор доступных опций командной строки. При обращении к функции gnome_init() в качестве аргументов берутся argc и argv и ищутся могущие быть опции. Вы можете определить опции, доступные в любом приложении, запустив приложение с опцией —help, или -?. Можете использовать следующую простую программу для демонстрации этого.
/*♦ showoptions.с *♦/
Iinclude <gnome.h>
int main(int argc,char *argv[])
{
gnome^init(*showoptions","1.0",argc,argv);
exit(O);
}
Эта программа не имеет своих собственных опций, но доступны опции для GNOME, GTK+ и X. Чтобы увидеть их все, наберите
showoptions —help I more
Вывод — полный список доступных опций:
Usage: showoptions [OPTION...]
GNOME Options
—disable-sound
—enable-sound
—espeaker=HOSTNAME:PORT
Disable sound server usage Enable sound server usage Host:port on which the sound server to use is running
Help options -?, —help —usage
Show this help message Display brief usage message
GTK options
—gdk-debug=FLAGS
—gdk-no-debug=FLAGS
—display=DISPLAY
—sync
—no-xshm
Gdk debugging flags to set Gdk debugging flags to unset X display to use Make X calls synchronous Don't use X shared memory extension
—name=NAME
Program name as used by the window manager
—class=CLASS
Program class as used by the window manager
—gxid_host=HOST
—gxid_port=PORT
—xim-preedit=STYLE
—xim-status=STYLE
—gtk-debug=FLAGS
—gtk-no-debug=FLAGS
—g-fatal-warnings
—gtk-module=MODULE
Gtk+ debugging flags to set Gtk+ debugging flags to unset Make all warnings fatal Load an additional Gtk module
GNOME GUI options -Vf —version
Help options -?, —help —usage
Show this help message Display brief usage message
Session management options —sm-client-id=ID
—sm-config-prefix=PREFIX
Specify session management ID Specify prefix of saved configuration
—sm-disable
Disable connection to session manager
Эти опции доступны в каждом GNOME-приложении. Например, чтобы найти номер версии программы mousef ollow в начале этой главы, вводимая команда и получаемый ответ могут выглядеть следующим образом:
% mousefollow -V
Gnome mousefollow 1.0
GNOME-приложение может отображать краткое описание всех аргументов при помощи опции -usage:
% showoptions -usage
Usage; showoptions [-?V?] [—disable-sound] [—enable-sound] [—espeaker=HOSTNAMEsPORT] [—usage] [—gdk-debug»FLAGS] [—gdk-no-debug-FLAGS] [—display=DISPLAY] [—sync] [—no-xshm] [—name=NAME] [—class=CLASS] [—gxid_host=HOST] [—gxid_port=PORT] [—xim-preedit=STYLE] [—xim-status=STYLE] [—gtk-debug=FLAGS] [—gtk-no-debug=FLAGS] [—g-fatal-warnings]
•[—gtk-module=MODULE] [—usage] [—sm-client-id=ID]
[—sm-config-prefix=PREFIX] [—sm-disable]
Добавление опций командной строки
Можно добавлять свои собственные опции командной строки, и система будет интерпретировать их точно так же, как и встроенные опции. Таким образом, добавленные опции будут подвергаться синтаксическому анализу и храниться, чтобы позднее ваша программа смогла их использовать. Они будут выводиться с помощью опций help и -usage вместе с предопределенными опциями. Это программное обеспечение известно как popt.
Вы задаете ваши собственные опции как массив структур poptOption. Каждый член массива — это одна опция. Структура содержит всю описательную информацию для опции:
struct poptOption {
const char *longName; char shortName; int arginfo;
void *arg; int val; char *descrip; char *argDescrip;
};
longName и shortName содержат символы, которые, как предполагается, должны быть получены из командной строки. Длинное имя (опция longName) используется с парой тире (знак минуса), а короткое имя (опция shortName) — это символ с тире. Например, длинное имя ’’nocolor” и короткое ”п” позволяют указывать опцию в командной строке или как —nocolor, или как -п.
Строка с descrip — это краткое описание аргумента. Если он указан, то при использовании опции —help появляется строка описания. Строка с argDescrip также применяется в описании, чтобы показать, как можно определить значение. Например, если аргумент с длинным именем border-color имеет argDescrip COLOR, то с помощью опции —help мы получим, что —border-color==COLOR.
Поле arginfo задает вид аргумента и тип данных, ожидаемых из командной строки. Табл. 12.2 представляет возможные значения для arginfo. В табл. 12.3 описаны побитовые маски, которые можно использовать при установке опций для каждого типа аргу
ментов.
Таблица 12.2. Типы аргументов, известные как Popt
Имя типа аргумента
Описание
PkPT_ARG_NkNE
Опция типа переключатель включить-выключить, поэтому не требует значения в командной строке.
PkPT_ARG_STRING
В командной строке значение представлено в форме строки в кавычках.
PkPT^ARGJNT
Значение в командной строке ограничено диапазоном
PkPT_ARG_LkNG
значений inf.
Значение в командной строке ограничено диапазоном значений long.
PkPT_ARGJNCLUKE_TABLE
Это не опция командной строки. Указатель arg в структуре — это адрес другого включаемого массива poptKption.
PkPT_ARG_CALLBACK
Это не опция командной строки. Указатель arg — это адрес функции обратного вызова, которую можно использовать для проведения синтаксического анализа командной строки. Его следует поместить в начало массива опций.
PkPT_ARGJNTL_KkMAIN
Значение arg — это указатель на строку, задающую преобразующий домен, который используется с этой таблицей.
PkPT_ARG_VAL
Это не опция командной строки, хотя ее можно использовать для установки значения по умолчанию. Расположение, указанное arg, следует взять из значения val.
Таблица 12.3. Флаги опций для модификации аргументов Popt
Имя опции
Описание
PkPT_ARGFLAG_kNEKASH
Позволяет использовать одиночное тире в длинном имени
PkPT_ARGFLAG_KkC_HIKKEN
так же, как и в коротком.
Запрещает выводить эту опцию с другими при помощи —help иги —usage.
PkPT_CBFLAG_PRE
Используется с PkPT_ARG__CALLBACK для обращения к функции обратного вызова перед синтаксическим анализом.
PkPT_CBFLAG_PkST
Используется с PkPT_ARG_CALLBACK для обращения к функции обратного вызова после синтаксического анализа. '
Это может показаться более сложным, чем необходимо, но эти сложности возникают только тогда, когда вы выполняете с аргументами что-то очень специальное. Практически в каждом случае это просто способ создания массива описаний опций, место для хранения вводимых значений и единственный вызов функции. В следующей программе задаются и принимаются пять аргументов командной строки.
/** readparm.с **/
tinclude <gnome.h>
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
int toolbarFarm = FALSE;
char *titleParm = NULL;
char *backgroundParm = NULL;
int widthParm = 100;
int heightParm = 50;
struct poptOption opt[] = {
< "title",'t', POPT_ARG_STRING, &titleParm,0, "The text to appear on the title bar", "TITLE"
"width",'w',
POPT_ARG_INT, &widthParm,0, "The width of the window", "WIDTH"
"height",'h',
POPT_ARG_INT, &heightParm,0, "The height of the window", "HEIGHT"
>,{
"toolbar",'T',
POPT_ARG_NONE, &toolbarParm,0, "Dislay the toolbar", NULL
"background",'\0',
POPT_ARG_STRING, (backgroundParm,0, "The background color for the window", "COLORNAME"
},{
NULL,0,0,NULL,0,NULL,NULL }};
int main(int argc,char *argv[]) <
poptContext context;
gnome_init_with_popt_table("readparm","1.0",argc,argv, opt,0,&context);
g_print("toolbar: %s\n", toolbarParm ? "TRUE" : "FALSE");
g_print("title; %s\n",titleParm ? titleParm : "NULL"); g_print("background; %s\n", backgroundParm ? backgroundParm ; "NULL");
g_print("width; %d\n",widthParm); g_print("height; %d\n",heightParm);
6060poptFreeContext(context);
60
60
61 exit(O);
62 }
В строках с 4 по 8 декларируются поля, которые получают значения, вводимые в командной строке. Если опция не появляется в командной строке, ее значение здесь не меняется; если хотите, можете сохранить в этих полях значения по умолчанию, как показано в этой программе при помощи widthParm и heightParm.
Каждый параметр задается как член массива структур poptOption, которые начинаются в строке 10. Первая опция, начинающаяся в строке 12, требует из командной строки в качестве своего значения строку в кавычках и имеет длинное и короткое имена. Длинная форма может содержать знак равенства, предшествующий некоторому значению. Можно вводить аргумент в любой из следующих форм:
readparm —title "Title Text"
readparm —titles"Title Text"
readparm -t "Title Text"
readparm —title TitleText •
readparm —title=TitleText
readparm -t TitleText
Кавычки необходимы только при условии, если строка содержит пробелы или начинается с дефиса (в ряде случаев это будет восприниматься как тег аргумента). Когда некая строка считывается с командной строки, то указатель на нее хранится в titleParm в строке 5, адрес указывается в таблице из строки 14.
Параметры height и width, определенные в строках с 18 по 28, задают для возврата данные типа int. Место хранения данных — соответственно widthParm и heightParm, объявленные со значениями по умолчанию в строках 7 и 8.
Аргумент панели инструментов, заданный в строке 30, — это обычный переключатель. Однако в командной строке отсутствуют значения, связанные с ним. Программа трактует присутствие или отсутствие этих значений как флаги. Значение флага, заданное как toolbarParm в строке 4, — это int со значением FALSE в качестве начального. Значение изменяется на TRUE, только если в командной строке указывается toolbar или -Т.
Аргумент, заданный в строке 36, можно использовать для принятия названия цвета в качестве строки. Этот аргумент можно использовать только с длинной формой, так как буква короткой формы — это нулевой символ. Указатель названия цвета хранится в backgroundParm, объявленном в строке 6.
Все считываемые с командной строки аргументы проходят синтаксический анализ, конвертируются в соответствующие типы данных и сохраняются в указанных полях путем единственного обращения к функции gnome_init_with_popt_table () в строке 49. Этот вызов заменяет обращение к gnome^init () при помощи добавления еще трех параметров. Пятый аргумент — это адрес массива структур poptOption, задающих параметры. Последний аргумент — это адрес poptContext (который сам является указателем), который получает адрес описания poptContext. Можете использовать этот контекст для запроса опций, если по ним требуется более детальная информация.
Для хранения poptContext выделяется память, которую надо возвратить системе. Однако ее нельзя возвращать до тех пор, пока вам требуется хранимая в ней информация вроде строковых аргументов, которые были возвращены вам как указатели.
Задаваемые в вашей программе параметры добавляются в список этих отображаемых параметров. В этом примере для просмотра параметров введите нижеследующую команду:
readparm —help
readparm options-t, —title=TITLE-w, —width=WIDTH-h, —-height=HEIGHT-T, —toolbar—background=COLORNAMEreadparm options-t, —title=TITLE-w, —width=WIDTH-h, —-height=HEIGHT-T, —toolbar—background=COLORNAMEВ результате получим список, описанный ранее, с этой добавкой внизу:
readparm options
-t, —title=TITLE
-w, —width=WIDTH
-h, —-height=HEIGHT
-T, —toolbar
—background=COLORNAME
readparm options
-t, —title=TITLE
-w, —width=WIDTH
-h, —-height=HEIGHT
-T, —toolbar
—background=COLORNAME
The text to appear on the title bar The width of the window The height of the window Dislay the toolbar
The background color for the window
Выводы
Большинство виджетов реагируют на мышь, а многие воспринимают нажатия клавиш клавиатуры, но в то же время можно получить эту информацию непосредственно, не ожидая реакции виджета. В этой главе объясняется несколько методов, которые не используют виджеты, для получения ввода от пользователя:
Любой виджет, который содержит окно, можно сделать восприимчивым к движению мыши, кнопкам мыши, а также к вводу с клавиатуры.
? Одно окно может захватить мышь, в результате этому окну сообщается обо всех событиях мыши. Иногда захват может ограничивать движение мыши в пределах работающего окна.
' Каждая нажатая или отпущенная (освобожденная) клавиша считывается с клавиатуры в окно, которое имеет текущий фокус. Каждая клавиша имеет индивидуальное значение ID — даже те, которые располагаются более чем в одном месте клавиатуры (вроде клавиши Shift).
. Существует встроенная в GNOME утилита, которая считывает аргументы командной строки и извлекает их значения и установки.
Следующая глава посвящена шрифтам. Существуют тысячи доступных шрифтов. Одни включены как часть системы Х11, остальные — с другими пакетами программного обеспечения. Существует большое разнообразие внешнего вида шрифтов, но все они используют стандартные размеры и измерение положения.
ГЛАВА
13 Шриф™
В этой главе
Как измеряются шрифты и оцениваются их размеры.
Г Понятие о принятых соглашениях в части наименований шрифтов Х11 и о том, как имена описывают сами шрифты.
- Использование виджета-указателя для выбора шрифта.
\ Считывание информации о размерах строки и использование ее для показа шрифта.
Вначале способ, которым шрифты используются системой X (и соответственно GTK4- и GNkME), может удивить. Но если вы видите, как это делается, то все становится намного проще. Предложенный метод позволяет очень гибко, но в то же время непосредственно работать со шрифтами. В вашем приложении можно использовать именно тот шрифт, который вы хотите, или можно уклониться от выбора и разрешить каждой системе указать шрифт, который наилучшим образом соответствует критериям выбора. Существует также вцджет, который позволяет пользователю выбрать шрифт.
Шрифты по-разному варьируют свои размеры и форму. К шрифтам прилагается специальный набор метрик. Используя стандартные значения для расположения символов на экране дисплея, вы можете обращаться со шрифтами единообразно (не имеет значения сколь радикально).
Анатомия шрифта
Существует ряд различных измерений, которые могут быть применены к символу или строке символов в шрифте. Сам факт, что одни символы выше, некоторые опускаются ниже, чем другие, а некоторые символы шире других, — все несколько усложняет. Вполне возможно, что один символ перекрывает другой, если они расположены рядом в строке — это довольно часто встречается в курсивном шрифте, где верхушка высокого символа возвышается над нижней частью символа, стоящего справа.
На рис. 13.1 показано, какие обмеры каждого символа можно выполнить. Для прорисовки символа используется начало координат осей х и у. Другими словами, когда вы рисуете букву / в указанной с помощью координат точке, то она появляется выше и правее этой точки. С другой стороны, буква р появляется справа от указанной точки, но одновременно выше и ниже ее. Растровый рендеринг, или графический дизайн, символа но-
сит название глиф (glyph), или глипт. Каждый глиф, или глипт, разработан по отношению к началу координат таким образом, что надо только выстроить символы на одной строке, то есть все, что надо сделать, — это расположить их начальные точки в строке.
Строка начальных точек называется базовой линией (baseline). Значения возвышающейся (ascent) и Опускающейся (descent) частей — это размеры от базовой линии соответственно до верха и до низа символа; сумма возвышающейся и опускающейся частей дает высоту (height) символа. Ширина (width) символа измеряется от начальной точки до правого края символа. Левый отступ (Ibearing — left bearing) — это расстояние от начальной точки до символа, а правый отступ (rbearing — right bearing) — это ширина графической части символа.
ascent heightascent heightIbearingIbearingrbearingrbearingorigin X -origin X -baselinebaselineascent height i originascent height i originrbeanngrbeanngdescentdescentIbearingIbearingwidth -Рисунок 13.1. Измерения шрифтов одиночных символовwidth -Рисунок 13.1. Измерения шрифтов одиночных символов
ascent height
ascent height
Ibearing
Ibearing
rbearing
rbearing
origin X -
origin X -
baseline
baseline
ascent height i origin
ascent height i origin
rbeanng
rbeanng
descent
descent
Ibearing
Ibearing
width -
Рисунок 13.1. Измерения шрифтов одиночных символов
width -
Рисунок 13.1. Измерения шрифтов одиночных символов
Как видно по измерениям возвышающейся, опускающейся частей и высоты символа на рис. 13.1, значение опускающейся части может быть равно нулю. Значение левого отступа тоже может быть равно нулю. Иногда это значение может быть даже отрицательным в случае, если глипт символа нарисован слева от начала. Например, это может случиться с нижней частью курсивного шрифта.
Рис. 13.2 демонстрирует набор измерений, которые можно выполнить в строке символов. Возвышающаяся, опускающаяся части и высота могут включать главную область, которая распространяется на максимальное расстояние только вверх, только вниз или одновременно вверх и вниз. То же можно сказать и о ширине. Граница вокруг строки позволяет вашей программе легко разместить куски текста и даже текст из различных шрифтов один за другим и получить правильный интервал между символами. Начало строки, координаты х иу которого используются для прорисовки, — это начальная точка самой левой буквы в строке. Начальные точки других букв используются внутри для размещения одной буквы за другой при рисовании строки. .
Рисунок 13.2. Измерения шрифта в строке символовРисунок 13.2. Измерения шрифта в строке символов
Рисунок 13.2. Измерения шрифта в строке символов
Рисунок 13.2. Измерения шрифта в строке символов
Наименования шрифтов
Шрифты хранятся в файлах на диске. Файлы со шрифтами — это часть стандартного дистрибутива X. Когда приложение требует шрифт, то он загружается из файла, который находится на Х-сервере, а не в приложении. Поскольку шрифты находятся на сервере, то в процессе отображения нет смысла в дополнительных расходах по передаче детальной информации о шрифтах от приложения к серверу. Это уменьшение загрузки трафика позволит сохранить немало времени, так как в общем случае процесс открытия локального окна X (с его локальным сервером) управляется приложением на другом компьютере. Кроме того, если более одного приложения используют один шрифт, то будет загружена только одна копия.
Файлы со шрифтами обычно хранятся в подкаталогах каталога /usr/lib/Xll/fonts. В каждом подкаталоге имя файла со шрифтами имеет суффикс .pcf или .pcf .gz. В том же самом каталоге со шрифтами есть файл по имени fonts .dir, который отображает имена псевдонимов в действительные имена файлов со шрифтами. Есть также файл fonts .alias, который можно использовать для назначения альтернативных имен шрифтам, заданным в fonts.dir. Например, можно использовать файл шрифтов с именем 10x20.pcf .gz, указав его имя следующим образом:
10x20
Или можно использовать назначенное ему имя псевдонима:
-misc-fixed-medium-r-normal—20-200-75-75-c-100-iso8859-l
Достоинство короткого названия в том, что оно легко запоминается, а достоинство длинного — в наглядности. Программное обеспечение позволяет производить выбор с использованием символов подстановки для различных частей имени. На рис. 13.3 показан образец длинного имени шрифта с каждой его помеченной частью, а в табл. 13.1 описано, что обозначает каждая часть.
font family font foundryfont family font foundryslantslantpoints pixelspoints pixelspixel width vertical dpipixel width vertical dpi
font family font foundry
font family font foundry
slant
slant
points pixels
points pixels
pixel width vertical dpi
pixel width vertical dpi
-adobe-courier-bold-r-normal—ll-80-100-160-m-60-iso8859-2
weightweightproportional widthproportional widthhorizontal dpihorizontal dpispacingspacingcharacter setcharacter set
weight
weight
proportional width
proportional width
horizontal dpi
horizontal dpi
spacing
spacing
character set
character set
Рисунок 13.3. Длинное наименование шрифта и его частей
Таблица 13.1. Части длинного имени шрифта
Часть
Описание
font foundry
Название компании или организации, которая создала шрифт. Некоторые наиболее общие имена — это adobe, b&h, bitstream, dec, Schumacher, Sony и sun. Если неизвестен производитель шрифта, то принимается название misc.
font family
Наименование набора родственных шрифтов, членом которого является этот шрифт. Возможные названия — это lusida, times, courier, helvetka и
weight
Насыщенность шрифта (толщина его штрихов). Она обычно принимает значение или medium (средняя), или bold (жирная), но может быть black (черная), book (нормальная), demibold (полужирная), light (светлая) или regular (тоже нормальная).
slant
Наклон каждой буквы: italic (курсив), oblique (тоже тип курсива) или г (сокращение от roman, означает прямой, или отвесный).
proportional width
Отношение между высотой и шириной определяет пропорции шрифта. Обычно это normal (нормальный шрифт), но может быть condensed (сжатый), semi-condensed (полусжатый), narrow (узкий) или double (двойной).
pixels
Размер шрифта в пикселах. Обычно размер шрифта измеряется в типографских пунктах (пункт — это 1/72 дюйма). Чтобы получить значение размера в пикселах, размер в пунктах переводится в значение в пикселах. Это означает, что размер в пунктах округляется по границе пиксела.
points
Размер шрифта в пунктах выражается в десятых долях типографского пункта. В примере (см. рис. 13.3) значение 80 означает, что размер шрифта равен 8 пунктам. Отношение между размерами в пунктах и пикселах определяется вертикальным и горизонтальным значениями dpi (dots per inch — точки на дюйм). Как в этом примере, в случае 100 dpi шрифт размером 8 пунктов имеет размер в пикселах, равный 11. При том же значении dpi шрифт размером 12 пунктов имеет размер 17.
horizontal dpi
Горизонтальное разрешение — количество горизонтальных пикселов на дюйм. Это значение используется для подсчета размеров в пикселах и пунктах, а также используется как коэффициент с вертикальным dpi для определения горизонтального и вертикального dpi, что способствует правильному отображению шрифта.
vertical dpi
Вертикальное разрешение — количество вертикальных пикселов на дюйм.
spacing
Пробел, или шпация. Может принимать значение m для моноширинного (monospace) шрифта, р — для пропорционального (proportional) или с — для шрифта с ячейками символов (character cell). Моноширинный шрифт содержит все символы одинаковой ширины. Пропорциональный шрифт имеет символы различной ширины (например, буква w шире, чем буква iY Третий — это шрифт фиксированной ширины, основанный на шрифтах пишущей машинки с пробелом.
pixel width
Средняя ширина в десятых долях пиксела для всех символов в шрифте.
Таблица 13.1. (продолжение)
ЧастьОписание
character set Это версия стандарта, используемого для задания набора символов.
ISk (International Krganization for Standardization — Международная Организация по Стандартизации) установила стандарты для наборов символов, которые включены в алфавиты различных языков.
Длинные имена шрифтов не только более описательны, они идут в таком виде, который позволяет использовать символы подстановки для поиска шрифта. Таким образом, нужно только указать то, что вам необходимо, и позволить установить остальные части имени шрифта по умолчанию. Например, в обращении к функции gdk_font_load() можно использовать следующее выражение как имя шрифта:
-*-bookman-light-r-normal—14-*-*-*-p-*-iso8859-l
Части шрифта, указанные в наименовании, должны точно совпадать с актуальным шрифтом, в то время как звездочки можно сопоставить с любым значением. Конечно, могут совпасть несколько шрифтов, но возвращается первое встреченное совпадение. Представленный выше пример мог бы выбрать этот шрифт:
-adobe-bookman-light-r-normal—14-135-75-75-p-82-iso8859-l
При задании имени шрифта необходимо указать только те части, которые необходимы. Таким образом, увеличится шанс, что выбранное наименование шрифта совпадет с имеющимся. Если ваши спецификации не совпали ни с одним существующим именем шрифта, то по умолчанию используется шрифт, названный fixed, а этот шрифт почти никогда не совпадет с тем, что вы желаете.
Виджет-указатель шрифта
Это виджет GNOME, позволяющий выбрать и отобразить шрифт. Виджет размещается в вашем приложении как кнопка в диалоговом окне или меню. В следующей программе показано, как можно использовать виджет для выбора шрифта и как затем можно применить этот шрифт в тексте другого виджета.
12345678910111213141516171819201234567891011121314151617181920/** fontpicker.с **/ tinclude <gnome.h>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
gint eventDelete(GtkWidget *widgety GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget, GdkEvent *event,gpointer data);
void eventFontSet(GtkWidget *widget, gchar *string,GtkWidget *label);
int main(int argc,char *argv[]) {
GtkWidget *app;
GtkWidget *fontpicker;
GtkWidget *label;
GtkWidget *box;
gnome_init("fontpicker","1.0",argc,argv);
app = gnome^app_new("fontpicker","Font Picker");
gtk_container_set_border_width(GTK_CONTAINER(app),30);
gtk_signal_connect (GTK_OBJECT (app), * deletesvent",
GTK_SIGNAL_FUNC(eventDelete),NULL);
gtk_signal_connect(GTK_OBJECT(app),"destroy",
GTK_SIGNAL_FUNC(eventDestroy),NULL);
25
box = gtk_vbox_new(FALSE, 0);
27
label = gtk_label_new(
"Select the button below and the font picker\n"
"window will appear.\n"
"The font you select will be used to\n"
"rewrite this text.");
gtk_box_pack_start(GTK_BOX(box),label,
FALSE,FALSE,0);
35
fontpicker = gnome_font_picker_new();
gtk_signal_connect(GTK_OBJECT(fontpicker),"font-set",
GTKSIGNALFUNC(eventFontSet),label);
gtk_box_pack_start(GTK_BOX(box),fontpicker,
FALSE,FALSE,0);
41
gnome_app_set_contents(GNOME_APP(app),box);
gtk_widget_show_all(app);
gtk_main();
exit(0);
}
void eventFontSet(GtkWidget *widget,
gchar *string,GtkWidget *label) {
GtkStyle*oldStyle;
GtkStyle*newStyle;
GdkFont *font;
52
font = gdkfontload(string);
oldStyle= gtk_widget_get_style(label);
newStyle= gtk_style_copy(oldStyle);
newStyle->font = font;
gtk_widget_set_style(label,newStyle);
gtk_style_unref(oldStyle);
}
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data) {
return(FALSE);
}
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data) {
gtk_main_quit();
return(0);■
}
В строке 26 создается вертикальное окно с текстовой меткой (надписью) и кнопкой GnomeFontPicker. В строках с 28 по 34 создается метка с текстом и происходит ее установка в верхнюю часть окна. Виджет-указатель шрифта создается в строке 36. Функция обратного вызова eventFontSet ( ) присоединяется к виджету-указателю в строке 37, а сам указатель шрифта упаковывается в ящик и сразу же вставляется в окно под надписью.
Функция обратного вызова eventFontSet (), заданная в строке 47, вызывается всякий раз, когда нажимается кнопка ОК в диалоговом окне указателя шрифта. Обращение
Select the button below and the font picker window will appear.The font you select will be used to rewrite this text.Select the button below and the font picker window will appear.The font you select will be used to rewrite this text.к функции gdk_font_load() в строке 53 использует имя выбранного шрифта для создания объекта GdkFont. Это создание называется ’’загрузка", так как часть процесса посвящена обращению к Х-серверу, который должен загрузить шрифт. Возвращаемый объект GdkFont содержит информацию об 1D шрифта, которая передается серверу всякий раз, когда предстоит использовать шрифт. В зависимости от выбранного шрифта окно выглядит примерно так, как изображено на рис. 13.4.
Select the button below and the font picker window will appear.
The font you select will be used to rewrite this text.
Select the button below and the font picker window will appear.
The font you select will be used to rewrite this text.
Рисунок 13.4.
Выбираемый пользователем шрифт
Виджет содержит указатель на объект GtkStyle, который, помимо прочего, содержит информацию о цвете и шрифте. Обращение в строке 54 к функции gtk_widget_get_style () возвращает указатель на объект GtkStyle. Тот же объект GtkStyle может одновременно использоваться рядом виджетов, поэтому приложение не может модифицировать его напрямую. Вместо этого выполняется обращение к функции gtk_style_copy () для создания дубликата объекта GtkStyle, затем в строке 56 для копирования назначается новый шрифт. Вызов функции gtk_widget_set_style () в строке 57 заменяет оригинал объекта GtkStyle копией. И наконец, в строке 58 функция gtk_style_unref () опускает ссылку на старый объект GtkStyle. Если нет других ссылок, память, используемая объектом GtkStyle, возвращается в систему, в противном случае — счетчик ссылок уменьшается на единицу.
Рис. 13.5 демонстрирует одну из трех панелей, отображаемую указателем шрифта диалогового окна. Из этого окна можно выбрать три базовых характеристики шрифта: наименование, толщину и наклон, а также размер шрифта. Для облегчения поиска можно использовать две другие панели, чтобы указать иные части имени шрифта. Показанное далее окно обновляется всякий раз, когда меняется выбор.
Font I Font Information I FilterFont I Font Information I Filter
Font I Font Information I Filter
Font I Font Information I Filter
Preview.Preview.HhlUjKkLIMmNnOoPpQqRrSsTtUuVvWwXxYyZi ;HhlUjKkLIMmNnOoPpQqRrSsTtUuVvWwXxYyZi ;
Preview.
Preview.
HhlUjKkLIMmNnOoPpQqRrSsTtUuVvWwXxYyZi ;
HhlUjKkLIMmNnOoPpQqRrSsTtUuVvWwXxYyZi ;
Рисунок 13.5.
Виджет GnomeFontPicker
l|" OK ~| Cancel |
Метрики и размещение шрифтов
В следующей программе текст размещается в области для рисования. Для указанной' строки здесь используется информация метрик шрифта, позволяющая определить верхний, нижний, правый и левый края, а также середину прямоугольной области, содержа-' щей шрифт. Затем эти измерения используются для центрирования текста и размещения его напротив краев.
/** fontposition.с **/
tinclude <gnome.h>
3
tdefine HEIGHT 100
tdefine WIDTH 300
6
tdefine STRING_LEFT 1
tdefine STRING_CENTER 2
tdefine STRINGJUGHT 3
tdefine STRING_TOP 1
tdefine STRING_MIDDLE 2
tdefine STRINGJBOTTOM 3
13
typedef struct {
GdkFont *font;
GtkWidget *drawingArea;
gint horizontal;
gint vertical;
} Context;
20
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
void eventFontSet(GtkWidget *widget,
gchar *string,Context *context);
gboolean eventDraw(GtkWidget *widget,
GdkEvent *event,Context *context);
void topButton(GtkWidget *widget,Context *context);
void middleButton(GtkWidget *widget,Context *context);
void bottomButton(GtkWidget *widget,Context *context);
void leftButton(GtkWidget *widget,Context *context);
void centerButton(GtkWidget *widget,Context *context);
void rightButton(GtkWidget *widget,Context *context);
static GtkWidget *createPositionWidget(Context *context);
36
int main(int argc,char *argv[])
{
GtkWidget *app;
GtkWidget *position;
Context context =
43444546474344454647{ NULL, NULL, STRING_RIGHT,STRING_MIDDLE };
43
44
45
46
47
43
44
45
46
47
gnome_init("fontposition", "1.0",argc,argv);
app = gnome_app_new("fontposition","Font Position");
gtk container set borderwidth(GTK_CONTAINER(app),30) gtksignal connect(GTK_OBJECT(app),"delete_event",
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
GTK_SIGNAL_FUNC(eventDelete),NULL); gtk_signal_connect(GTK_OBJECT(app),"destroy",
GTK_SIGNAL_FUNC(eventDestroy),NULL);
position = createPositionWidget(&context);
gnome_app_set_contents(GNOME_APP(app),position);
gtk_widget_show_all(app);
gtk_main();
exit(0);
}
static GtkWidget *createPositionWidget(Context *context) {
GtkWidget *position;
GtkWidget *box;
GtkWidget *button;
GtkWidget *frame;
GtkWidget *fontpicker;
position = gtk_vbox_new(FALSE,0);
box = gtk_hbox_new(TRUE,10);
button = gtk_button_new_with_label("Top");
gtk_signal_connect(GTK_OBJECT(button),"clicked",
GTK_SIGNAL_FUNC(topButton),context);
gtk_box_pack_start(GTK_BOX(box),button,
FALSE,TRUE,0);
button = gtk_button_new_with_label("Middle");
gtk_signal_connect(GTK_OBJECT(button),"clicked", GTK_SIGNAL_FUNC(middleButton),context);
gtk_box packstart(GTKBOX(box),button,
FALSE,TRUE,0);
button = gtk_button_new_with_label("Bottom");
gtk_signal_connect(GTK_OBJECT(button),"clicked",
GTKSIGNALFUNC(bottomButton),context);
gtkboxpackstart(GTKBOX(box),button,
FALSE,TRUE,0);
gtk_box_pack_start(GTK_BOX(position),box,
FALSE,FALSE,0);
context->drawingArea = gtk_drawingarea_new();
gtk_drawing_area_size(
GTK_DRAWING_AREA(context->drawingArea),
WIDTH,HEIGHT);
gtk signal connect(GTK_OBJECT(context->drawingArea), "event",GTK_SIGNAL_FUNC(eventDraw),context);
frame = gtk_frame_new(NULL);
gtk_container_add(GTKCONTAINER(frame), context->drawingArea);
gtk_box pack start(GTK_BOX(position),frame,
FALSE,FALSE,0);
101102 юз104105101102 юз104105box = gtk_hbox_new(TRUE,10);
101
102 юз
104
105
101
102 юз
104
105
button = gtkbutton new_with_label("Left");
gtk_signal_connect(GTK_OBJECT(button),"clicked GTK_SIGNAL_FUNC(leftButton),context);
gtk boxpackstart(GTKBOX(box),button,
106
FALSE,TRUE,0);.
107
button = gtk_button_new_with_label( "Center");
108
gtk_signal_connect(GTK_OBJECT(button),"clicked",
109
GTK_SIGNAL_FUNC(centerButton),context);
110
gtk_box_pack_start(GTK_BOX(box),button,
111
FALSE,TRUE,0);
112
button = gtk_button_new_with_label("Right");
113
gtk_signal_connect(GTK_OBJECT(button),"clicked",
114
GTK_SIGNAL_FUNC(rightButton),context);'
115
gtk_box_pack_start(GTK_BOX(box),button,
116
FALSE,TRUE,0);
117
gtkboxpackstart(GTKBOX(position),box,
118
FALSE,FALSE,0);
119
120
fontpicker = gnome_font_picker_new();
121
gtk_signal_connect(GTK_OBJECT(fontpicker),"font-set"
122
GTK_SIGNAL_FUNC(eventFontSet),context);
123
gtk_box_pack_start(GTKBOX(position),fontpicker,
124
FALSE,FALSE,0);
125
126
127 }
return(position);
128 void eventFontSet(GtkWidget *widget,
129
gchar *string,Context *context) {
130
131
if(context->font 1= NULL)
132
gdk_font_unref(context->font);
133
context->font = gdk_font_load(string);
134
gdk_window_clear_area_e(context->drawingArea->window
135
136 }
0,0,WIDTH,HEIGHT);
137 gboolean eventDraw(GtkWidget *widget,
138
GdkEvent *event,Context *context) {
139
gchar outstring[40];
140
gint Ibearing;
141
gint rbearing;
142
gint width;
143
gint ascent;
144
gint descent;
145
gint x;
146
gint y;
147
148
if(context->font == NULL) {
149
context->font = gdk_font_load(
150
"-*-bookman-light-r-normal—14-*-*-*-p-*-iso8859-l
151
}
152
153
switch(context->vertical) {
154
case STRING_TOP:
155
strcpy(outstring,"Top");
156
break;
157
case STRING MIDDLE:
158
strcpy(outstring,"Middle");
159
break;
160
case STRINGBOTTOM:
161
strcpy(outstring,"Bottom");
162
break;
163
}
164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
switch(context->horizontal) { case STRING_LEFT: strcat(outstring," Left"); break;
case STRING_CENTER: streat(outstring," Center"); break;
case STRING_RIGHT: strcat(outstring," Right"); break;
}
gdk_text_extents(context->font, outstring, strlen(outstring), &lbearing, irbearing, 6width, 6ascent, 6descent);
switch(context->vertical) { case STRING_TOP: у = ascent;
break;
case STRING_MIDDLE: у = HEIGHT / 2; у += (ascent - descent) / 2; break;
case STRINGBOTTOM: у = HEIGHT - descent; break;
} switch(context->horizontal) { case STRINGLEFT: x = 0; break;
case STRING_CENTER:
x = (WIDTH / 2) - (width /2); break;
case STRINGRIGHT: x = WIDTH - width; break;
}
gdk_draw_string(widget->window, context->font, context->drawingArea->style->black_gc, x,y, outstring);
return(TRUE); } void topButton(GtkWidget *widget,Context *context) { context->vertical = STRING_TOP;
gdk_window_clear_area_e(context->drawingArea->window, 0,0,WIDTH,HEIGHT);
222 void middleButton(GtkWidget ‘widget,Context ‘context) {
223context->vertical = STRINGMIDDLE;
224gdk_window_clear_area_e(context->drawingArea->window,
2250,0,WIDTH,HEIGHT);
226 }
227 void bottomButton(GtkWidget ‘widget,Context ‘context) {
228context->vertical = STRINGBOTTOM;
229gdk_window_clear_area_e(context->drawingArea->window,
2300,0,WIDTH,HEIGHT);
231 }
232 void leftButton(GtkWidget ‘widget,Context ‘context) {
233context->horizontal = STRING_LEFT;
234gdk_window_clear_area_e(context->drawingArea->window,
2350,0,WIDTH,HEIGHT);
236 }
237 void centerButton(GtkWidget ‘widget,Context ‘context) {
238context->horizontal = STRING_CENTER;
239gdk_window_clearareae(context->drawingArea->window,
2400,0,WIDTH,HEIGHT);
241 }
242 void rightButton(GtkWidget ‘widget,Context ‘context) {
243context->horizontal = STRINGRIGHT;
244gdk_window_clear_area_e(context->drawingArea->window,
2450,0,WIDTH,HEIGHT);
246 }
247 gint eventDelete(GtkWidget ‘widget,
248GdkEvent ‘event,gpointer data) {
249return(FALSE);
250 }
251 gint eventDestroy(GtkWidget ‘widget,
252GdkEvent ‘event,gpointer data) {
253gtkmainquit();
254return(0);
255 }
В стержневой ветви программы — в строках с 37 по 58 — устанавливается GNOME- приложение с единственным окном. Обращение к функции createPositionWidget() в строке 52 создает виджет, который включается в главное окно в строке 54 путем вы
зова gnome_app_set_contents().
Тор | Middle | BottomТор | Middle | BottomMiddle RightMiddle RightLeft | Center | RightLeft | Center | RightРисунок 13.6.Использование метрик для размещения текстаРисунок 13.6.Использование метрик для размещения текстаОкно приложения изображено на рис. 13.6. Верхний ряд кнопок переставляет строку вертикально, а нижний ряд кнопок — горизонтально. Кнопка внизу предназначена для выбора шрифта, ее можно использовать для изменения шрифта в размещаемой строке.
Тор | Middle | Bottom
Тор | Middle | Bottom
Middle Right
Middle Right
Left | Center | Right
Left | Center | Right
Рисунок 13.6.
Использование метрик для размещения текста
Рисунок 13.6.
Использование метрик для размещения текста
Функция createPositionWidget() из строки 59 создает все виджеты для отображения и назначает им функции обратного вызова. Структура Context, объявленная в строке 14, применяется для передачи информации этой функции и всем функциям обратного вызова вместо использования глобальных данных. Все виджеты, содержащиеся в вертикальном ящике, создаются в строке 67 путем вызова gtk_vbox_new().
В строках с 69 по 86 происходит создание горизонтального ящика и заполнение его кнопками. Горизонтальный ящик вставляется в верхнюю часть вертикального. Каждой кнопке назначена ее собственная функция обратного вызова с контекстным указателем в качестве передаваемых ей данных.
В строках с 88 по 93 создается область для рисования, используемая для отображения текста. Вызов gtk_drawing_area_size() устанавливает размер области для рисования в значения WIDTH и HEIGHT, определенные в строках 4 и 5. Функция обратного вызова eventDraw() присоединяется к области для рисования, поэтому, когда бы ни случилось событие, связанное с экспозицией (выход окна на передний план), вызывается функция для окрашивания окна.
В строках с 95 по 118 создаются кнопки, которые управляют горизонтальным размещением отображаемого текста. Каждой кнопке назначена своя собственная функция обратного вызова.
Виджет GnomeFontPicker создается в строках со 120 по 124 при помощи вызова функции gnome^f ont_picker_new (). Его функцией обратного вызова является eventFontSet (), и она упаковывается в вертикальный ящик последней.
Функция обратного вызова eventFontSet () из строки 128 вызывается указателем шрифта всякий раз при выборе нового шрифта. Если шрифт уже включен в контекст, то обращение к функции gdk__font_unref () в строке 132 отменяет локальное размещение шрифта и в сервере X (за исключением того случая, когда этот шрифт используется другим процессом). Вызов gdk_f ont_load () в строке 133 создает новый шрифт на основе строки, возвращенной от указателя шрифта. Обращение к функции gdk_window_clear_ar еа_е () в строке 134 необходимо для обновления отображения. Этот вызов делает две вещи: стирает ранее нарисованную строку, заполняя область для рисования фоновым цветом, и создает событие экспозиции. Такое событие заставляет обратиться к функции обратного вызова eventDraw(), рисующей текст с использованием нового шрифта.
Функция обратного вызова eventDraw() из строки 137 вызывается всякий раз, когда надо нарисовать строку в области для рисования. В строке 148 выполняется проверка, загружен ли какой-нибудь шрифт, и если нет, то загружается шрифт, принятый по умолчанию. Текст строки определяется ее расположением в окне, поэтому оператор switch в строках 153 и 164 используется для построения строки на основе двух наименований, описывающих ее размещение. Так как известны и шрифт, и строка, то обращение к функции gdk_text_extents () в строке 176 возвращает метрики строки, как только она появится на экране. Эти значения можно использовать для расположения текста в окне.
Вертикальное размещение устанавливается с помощью оператора switch, начинающегося со строки 185. Если строка находится наверху окна, то значение у — это возвышающаяся часть, то есть высота самого высокого символа над базовой линией. Если строка размещается внизу окна, то значение у — это высота окна минус размер опускающейся части, то есть нижняя часть символа с наибольшей опускающейся частью располагается прямо по низу окна. Для подсчета точного центрирования по вертикали требуется немного больше. Для большинства приложений нужно просто разделить высоту пополам и в этой точке использовать базовую линию. Однако если требуется точное центрирование по вертикали, то надо учитывать смещение базовой линии, как это сделано в строке 191.
Горизонтальное размещение устанавливается с помощью оператора switch, начинающегося со строки 197. Если предполагается, что строка будет слева, то просто надо расположить начало по левой границе, установив координату х равной нулю. В строке 205
выполняется размещение строки с правой стороны, при этом значение х устанавливается равным ширине окна минус длина строки. В строке 202 выполняется центрирование строки по горизонтали, при этом ширина окна делится пополам и вычитается половина длины строки.■
Каждая кнопка имеет свою функцию обратного вызова, располагающуюся в строках с 217 по 245. Каждый обратный вызов устанавливает в контекст индикатор размещения. Кроме того, на каждом обратном вызове выполняется обращение к gdk_window_clear_area_e (), чтобы очистить область для рисования и вызвать событие экспозиции, заставляющее функцию eventDraw() нарисовать в окне новую строку.
Выводы
Из всех элементов, отображаемых как часть графического интерфейса пользователя, глаз наиболее восприимчив к буквам, цифрам и пунктуации. Мы читаем и пишем всю жизнь, поэтому наш мозг сразу же распознает символы и их образцы. Одни символьные шрифты смотрятся хорошо и дружелюбно, даже привлекательно, в то время как другие неуклюжи и трудны для восприятия. Фактическое различие между теми, которые нам нравятся, и теми, которые не нравятся, может быть незначительно. Даже среди символов, обычно отображаемых очень мелкими на экране, можно сразу легко распознать детали их формы. Вот почему, когда мы смотрим на символы, нам кажется, что они имеют такие разительные отличия. В этой главе были описаны следующие основы управления шрифтами:
# Каждый шрифт хранится в своем собственном файле, поэтому легко можно добавлять новые шрифты или удалять старые.
^ Ваше приложение может обращаться к определенным шрифтам по имени; в нем также можно выбрать шрифт с использованием описательных терминов, таких, как семейство шрифта или размер в пунктах.
’ ^ Имеется стандартный набор метрик, которые можно использовать для размещения текста в окне и для определения размера отображаемого текста.
^ Виджет GnomeFontPicker может быть включен в вашу программу, чтобы пользователь мог указать шрифт.
В следующей главе виджеты рассматриваются более подробно. Каждый виджет содержит отображаемое окно и может работать с мышью и клавиатурой. Но это еще не все о виджетах. Если вы знаете, как работают виджеты, то можете заставить их делать все, что вам необходимо. Кроме того, может оказаться, что некоторые функции вашего приложения будут работать лучше именно в качестве виджета.
ГЛАВА14ГЛАВА14В этой главеВ этой главеПриемы работы с виджетами
ГЛАВА
14
ГЛАВА
14
В этой главе
В этой главе
S Исследование внутренней структуры виджета
# Коммуникационное общение с виджетом
# Управление появлением, исчезновением и изменением формы виджета
# Настройка виджета через установку совокупности характеристик стиля
Эта глава посвящена виджетам. У каждого воспроизводимого на экране дисплея объекта GNkME есть, как у его родителя или прародителя, объект GtkWidget. Он содержит установочные параметры и настройки, которые могут быть сделаны для виджета. Следует отметить, что виджет — очень сложный программный объект в том плане, как он отслеживает поступающую информацию, передает сведения о событиях прикладной программе и знает, как и когда обновить свой вид на экране дисплея.
Поскольку у всех воспроизводимых объектов GNkME одинаковая наследственность, все они суть виджеты. У каждого виджета есть некоторые общие черты с другим виджетом. Большим преимуществом является то, что функция любого уровня, которая работает для одного виджета, работает и для другого. Например, на уровне виджетов можно изменять цвет и параметры шрифта. Также существуют стандартные способы изменить размер и положение виджета; вызовы функций одинаковы независимо от того, является ли виджет меню, меткой, областью для рисования или чем-либо другим, разработанным специально для приложения.
Изучение виджета ■
Через наследование каждый виджет в вашей программе — комбинация частей, которые включают GtkOb ject, GtkWidget и, возможно, другие виджеты. Например, виджет GtkButton возводится над виджетом GtkBin, который, в свою очередь, возведен над виджетом GtkContainer, а тот — над GtkWidget, который является производным от GtkOb ject. Такая форма наследования придает GTK+ объектно-ориентированные свойства. Виджеты GNOME — дальнейшее расширение виджетов GTK+, поэтому они также сохраняют объектно-ориентированную форму. В главе 18 подробно описывается внутренняя структура виджетов.
У каждого виджета есть внутренние установки, которые прикладная программа может читать или записывать. И так как каждый виджет является агрегатом — видом стека различных виджетов, — то необходимо было разработать интерфейс, который может ис-
пользовать ваше приложение для адресации определенного значения внутри указанного виджета, найденного в дереве иерархии. Чтобы прочитать или записать одно из этих значений, ваша программа должна знать имя виджета, имя переменной и тип данных.
ПРИМЕЧАНИЕ
Существует ряд терминов, используемых для обращения к этим доступным через программу значениям, хранящимся в виджете. Они известны как аргументы объекта, параметры виджета, установки, значения, опции и т. д. Однако термин аргумент, вероятно, подходит лучше всего, потому что три буквы "arg" фигурируют внутри виджетов GTK+ и GNkME.
В следующей программе отображается список имен и типов аргументов виджета.
12345678910111213141516171819202122232425262728293031323334353637383940414243441234567891011121314151617181920212223242526272829303132333435363738394041424344/*♦ argnames.с **/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <gnome.h>
void showArgs(GtkWidget ♦);
int main(int argc,char *argv[]) {
GtkWidget *clist;
GtkWidget ♦window;
gnome_init("argnames","1.0",argc,argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
clist = gtk_clist_new(4);
showArgs(clist);
exit(0);
}
void showArgs(GtkWidget *widget) {
GtkType objectType;
GtkArg *arg;
gint argCount;
guint32 *argFlags;
GtkArglnfo ♦arginfo; gint i;
objectType = GTK_OBJECT_TYPE(widget);
while(objectType != GTK_TYPE_INVALID) { arg = gtk_object_query_args(objectType, &argFlags,&argCount);,
g_print("%s::\n",gtk_type_name(objectType));
for(i=0; i<argCount; i++) { gtk_object_arg_get_infо(objectType, arg[i].name,&arglnfо);
g_print(" \"%s\" %s", arglnfo->name, gtk_type_name(arglnfo->type));
if((arglnfo->arg_flags & GTK_ARG_READWRITE) == GTKARGREADWRITE) g_print(" Read/Write");
else if(arglnfo->arg_flags & GTKARGREADABLE) g_print(" Readonly");
4546474849505152535455 }4546474849505152535455 }else if(argInfo->arg_flags & GTK_ARG_WRITABLE) g_print(" Writeonly");
45
46
47
48
49
50
51
52
53
54
55 }
45
46
47
48
49
50
51
52
53
54
55 }
if(arglnfo->arg_flags & GTKARG CONSTRUCTONLY)
• g_print(" (Not writable after realized)"); g_print("\n");
}
g_free(arg);
g_free(argFlags);
objectType = gtk_type_parent(objectType);
Стержневая ветвь этой программы минимальна: все, что нам нужно, — чтобы был создан виджет и передан функции showArgs () для перечисления доступных установок. Виджет GtkCList создается в строке 14, а в строке 15 он используется при обращении к showArgs (). Функция showArgs (), начинающаяся в строке 19, содержит вложенный цикл. Внешний цикл выполняется единожды для каждого виджета в иерархииии. Внутренний цикл выполняется единожды для каждого аргумента, найденного в этом виджете.
Сначала вы должны получить тип объекта. Это делается с помощью макроса GTK-OBJECT_TYPE() в строке 28. В начале виджетного цикла в строке 31 выполняется обращение к gtk_object_query_args() с использованием типа объекта для выборки массива структур GtkArg, числа членов в массиве и набора флагов. Обращение к функции g_print() в строке 33 вызывает gtk_type_name () для извлечения наименования типа объекта и печатает его. В конце внешнего цикла, в строках 51 и 52, освобождаются ресурсы массива GtkArg и флагов, так как они были выделены динамически.
Внутренний цикл, начинающийся в строке 34, выполняется единожды для каждого аргумента, найденного в виджете. В строке 35 выполняется обращение к gtk_ob ject__arg_get_inf о ( ) с использованием типа объекта и наименования аргумента. Как возвращаемое значение функция сохраняет адрес в указателе структуры GtkArglnf о, определенном в строке 25. Эта структура содержит все, что требуется знать относительно аргумента.
Проверка в строке 40 определяет, установлены ли оба флага GTK_ARG_READABLE и GTK_ARG_WRI TABLE. Если оба вместе не установлены, программа проверяет, который из них установлен. Проверка в строке 47 отлавливает состояние перезаписи аргумента, но только перед реализацией виджета. Вывод этой программы выглядит следующим образом:
GtkCList:;
"n_columns" guint Read/Write (Not writable after realized) "shadow_type" GtkShadowType Read/Write
"selection_mode" GtkSelectionMode Read/Write
"row_height" guint Read/Write
"reorderable" gboolean Read/Write
"titles_active" gboolean Read/Write
"use_drag_icons" gboolean Read/Write
GtkContainer::
"border_width" gulong Read/Write
"resize_mode" GtkResizeMode Read/Write
"child" GtkWidget Writeonly
GtkWidget::
"name" GtkString Read/Write
"parent" GtkContainer Read/Write
"х" gint Read/Write
"у* gint Read/Write
"width" gint Read/Write
"height" gint Read/Write
"visible" gboolean Read/Write
"sensitive" gboolean Read/Write
"appjaaintable" gboolean Read/Write
"canfocus" gboolean Read/Write
"has^focus" gboolean Read/Write
"can_default" gboolean Read/Write
"has_default" gboolean Read/Write
"receivesdefault" gboolean Read/Write
" compos ite__chi Id" gboolean Read/Write
"style" GtkStyle Read/Write
"events* GdkEventMask Read/Write
"extensionevents" GdkEventMask Read/Write
GtkObject::
"user_data" gpointer Read/Write
"signal" GtkSignal Writeonly
"signal-after" GtkSignal Writeonly
"object_signal" GtkSignal Writeonly
"object_signal_after" GtkSignal Writeonly
На выходе вы можете видеть четыре части этого виджета. На самом низком уровне находится GtkOb ject, который является общим для всех виджетов; он выполняет рутинные операции перехвата сигналов и передачи пользовательских данных функциям обратного вызова. Расширение GtkOb ject — это GtkWidget. Он отвечает за размер, форму, оформление и другую информацию, необходимую для работы любого виджета. Следующий виджет — GtkContainer, который может использоваться для содержания других виджетов. Причем виджет самого верхнего уровня, который был создан в программе — это объект GtkCList. У него есть установки по информации относительно строк и столбцов, режима выбора и отображения заголовка. В результате доступны все аргументы листинга, если у вашей программы имеется объект GtkCList.
ПРИМЕЧАНИЕ_ .
Каждый виджет GNkME и GTK+ базируется на GtkWidget, который, в свою очередь, базируется на Gtkxbject. Эта общая база дает каждому виджету общий интерфейс, стандартный вид и беспрепятственную способность к взаимодействию. Например, вы можете дать команду любому виджету изменить его координаты х и у, так как GtkWidget контролирует эти установки.„
Каждый аргумент имеет тип данных и полномочия чтения/записи, связанные с ним. Большинство аргументов разрешены для чтения/записи. Однако в GtkOb ject некоторые аргументы определены только для записи, и вы можете найти подобное в других виджетах. У GtkContainer также есть аргумент только для записи. У этого виджета отсутствуют аргументы только для чтения, но некоторые виджеты их имеют. Первый распечатанный аргумент — специальный случай, так как предназначен для чтения/записи, но он не может быть записан, если уж виджет реализован. То есть, как только вы создаете и реализуете объект GtkCList, нельзя менять число столбцов, которые он содержит.
Обращение с виджетом
Есть два способа установить значение аргумента внутри виджета. Вы можете использовать функцию, закрепленную к одному или двум специфическим аргументам, или можете передать массив объектов GtkArg. Способ, который Вы будете использовать, зависит от вашего личного предпочтения, а также от того, какие функции доступны. Функции доступны для большинства обычно используемых установок, но вовсе не для всех.
У многих виджетов есть закрепленные функции, которые вы можете использовать для установки значений аргументов. Например, у объекта GtkWidget есть аргумент по имени ’’name”, который может быть установлен вызовом функции gtk_widget_set_name() и выбран через вызов gtk_widget__get_name ().
В следующей программе показано, как можно вызвать функцию для установки размера и размещения кнопки. Эта программа создает GnomeCanvas и помещает в него GtkButton. Как обсуждалось в главе 9, на канве можно располагать виджеты в соответствии с парой значений координат х и у. Оказывается, значения координат х и у сохраняются в виджете, а не в канве. То же самое касается и высоты с шириной, так что если вы изменяете одно из этих значений, виджет изменяет свои размеры и перемещается в
новое местоположение.
/*♦ setl.c ♦*/
linclude <gnome.h>
3
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
void eventchange(GtkWidget *widget,GtkWidget *button); 9
Idefine WIDTH 300
#define HEIGHT 200
12
int main(int argc,char *argv[])
{
GtkWidget*app;
GtkWidget*canvas;
GtkWidget*button;
GnomeCanvasGroup *rootGroup;
GnomeCanvasItem *item;
20
21gnome_init("setl","1.0",argc,argv);
app = gnome_app_new("Set 1",
"Gnome Canvas Widget");
gtk_signal_connect(GTK_OBJECT(app),"delete_event",
GTKSIGNALFUNC(eventDelete),NULL);
gtk_signal_connect(GTKOBJECT(app),"destroy",
GTK_SIGNAL_FUNC(eventDestroy),NULL);
28
canvas = gnome_canvas_new();
gtkwidgetsetusize(canvas,WIDTH,HEIGHT);
gnome_canvas_set_scroll_region(GNOME_CANVAS(canvas),
0.0,0.0,WIDTH,HEIGHT);
rootGroup = gnomecanvasroot(GNOMECANVAS(canvas));
gnomeappsetcontents(GNOMEAPP(app),canvas);
35
button = gtk_button_new_with_label("Change");
gtksignalconnect(GTK_OBJECT(button),"clicked",
GTK_SIGNAL_FUNC(eventchange),button);
item = gnome_canvas_item_new(rootGroup,
4 0gnome_canvas_widget_get_type(),
41"widget",button,
42"x",(double)(5),
43"y",(double)(5),
44"anchor",GTK_ANCHOR_NW,
45NULL);
46 47gtk_widget_show_all(app);
48gtk_main();
49exit(O);
50 } 51 void eventchange(GtkWidget *widget,GtkWidget *button) 52 { 53gintw;
ginth;
gintx;
56ginty;
57 58w= (gint)((random() % (WIDTH/2))+10);
59h = (gint)((random() % (HEIGHT/2))+10);
60gtk_widget_set_usize(GTK_WIDGET(button),w,h);
61 62x = (gint)((random() % (WIDTH/2))+25);
63у = (gint)((random() % (HEIGHT/2)))+25;
64gtk_widget_set_uposition(GTK_WIDGET(button),x,y);
65 } 66 gint eventDelete(GtkWidget *widget, 67GdkEvent *event,gpointer data) {
68 return(FALSE);
69 }
70 gint eventDestroy(GtkWidget *widget, 71GdkEvent *event,gpointer data) {
gtk_main_quit();
return(O);
}.
В строках с 29 по 34 создается канва и назначается как виджет для отображения главным окном приложения. Кнопка создается в строке 36 и связывается с обратным вызовом в строке 37. Затем кнопка присоединяется как новый компонент канвы путем вызова gnome_canvas_item_^new() в строке 39. При этом присоединении включаются четыре значения аргумента. Аргумент ’’widget” сообщает канве, что виджет запущен, и его значение — собственно сам виджет. Аргумент ’’anchor” сообщает канве: часть кнопки должна быть связана с координатами местоположения, что подробно обсуждалось в главе 9. Значения аргументов х и у передаются кнопке, так как эта кнопка отслеживает свое положение на лицевой стороне канвы.
Обращение к функции обратного вызова eventchange () из строки 51 выполняется всякий раз, когда осуществляется щелчок кнопкой. Размер кнопки настраивается в строках с 58 по 60 путем создания пары случайных чисел и вызова функции gtk_widget_set_usize (). Также через использование случайных чисел в строках с
62 по 64 при помощи вызова gtk_widget_set_uposition() меняется местоположение кнопки.
ПРИМЕЧАНИЕ
Автоматическое обновление — одно из положительных свойств виджетов. Всякий раз, когда вы устанавливаете одно из значений аргументов, виджет немедленно изменяет свои характеристики и в случае необходимости перерисовывает изображение на экране. Ваша программа ничего не должна больше делать после того, как значение установлено.
Следующая функция — альтернативный способ записать функцию eventchange (). Она делает то же, что и указанная выше функция, кроме того, сначала вычисляет все значения, а затем для их одновременной установки вызывает gtk_object_set().
void eventchange(GtkWidget {gint w;gint h;gint x;gint y;void eventchange(GtkWidget {gint w;gint h;gint x;gint y;♦widget,GtkWidget *button)♦widget,GtkWidget *button)
void eventchange(GtkWidget {
gint w;
gint h;
gint x;
gint y;
void eventchange(GtkWidget {
gint w;
gint h;
gint x;
gint y;
♦widget,GtkWidget *button)
♦widget,GtkWidget *button)
w = (gint)((random() % (WIDTH/2))+10);
h = (gint)((random() % (HEIGHT/2))+10);
x = (gint)((random() % (WIDTH/2))+25); у = (gint)((random() % (HEIGHT/2)))+25;
gtkobject_set(GTK_OBJECT(button),
"x",x,
"У^У,
"width",w,
"height",h, NULL);
}
Функция gtk_object_set() принимает список аргументов переменной длины. Каждый аргумент есть пара — собственно имя аргумента и его значение. Указатель NULL завершает список. Поскольку это список аргументов переменной длины, NULL необходим для определения последнего аргумента в массиве.
ПРИМЕЧАНИЕ
При вызове gtk_objecf_set() убедитесь, что вы передаете правильный тип данных для каждого значения аргумента. Различные типы данных занимают различный объем памяти в стеке, и несоответствие между тем, что вы посылаете, и тем, что ожидаете, может засорить стек и привести к аварийному отказу вашей программы.
В вышеуказанном примере при вызове gtk_ob ject_set () используется простое имя для идентификации аргументов. Имя аргумента фиксируется путем просмотра наследования виджета до тех пор, пока не находится соответствие. Например, для объекта GtkCList, описанного ранее в этой главе, поиск начинается с GtkOb ject и, если аргумент не найден, поиск перемещается к GtkWidget, затем к GtkContainer и, наконец, к GtkCList. Однако ничего не мешает двум виджетам иметь одно и то же название аргумента, так что идея определить и виджет, и значение себя оправдывает. Это заставляет при каждом поиске пропускать все виджеты кроме того, который указан:
gtkobjectset(GTKOBJECT(button),
"GtkWidget::x",x,
"GtkWidget::y",y,
"GtkWidget:swidth",w, "GtkWidget:sheight",h, NULL);
Прислушайтесь к виджету
Так как существует много типов данных, то куда труднее получить значение аргумента из виджета, чем установить его. Чтобы получить значение, вы передаете в имени значение аргумента и структуру GtkArg. Если имя, которое вы передаете, найдено и его значение удобно для чтения, значение сохраняется в структуре GtkArg. Чтобы выполнять эту работу, структура GtkArg должна принимать все возможные типы данных. В структуре имеется три компонента: поле GtkType, которое определяет тип данных, указатель на строку, определяющую имя аргумента, и набор различных типов данных:
typedef struct _GtkArg GtkArg;
struct __GtkArg {
GtkType type;
gchar *name;
union {.
gchar chardata;
guchar uchardata;
gboolean booldata;
gint int_data;•
guint uint_data;
glong long_data;
gulong ulong—data;
gfloat float-data;
gdouble double-data;
gchar ♦string-data;
gpointer pointer-data;
GtkObject *object-data;
struct {
GtkSignalFunc f;
gpointer d;
} signal-data;
struct {
gint П-args;
GtkArg *args;
} args_data;
struct {
GtkCallbackMarshal marshal;
gpointer data;
'' GtkDestroyNotify notify;
callback-data;
struct {
GtkFunction func;
gpointer funC-data;
} C-Callback-data;
struct {
gpointer data;
GtkDestroyNotify notify;
} foreign-data;
} d;
Следующая программа создает объект GtkCList, устанавливает некоторые значения аргументов и, когда виджет отображен, считывает обратно некоторые из значений и отображает их.
/** get.с **/
finclude <gnome.h>
3
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
void eventShow(GtkWidget *widget,gpointer data);
9
fdefine WIDTH 300
tdefine HEIGHT 200
12
int main(int argc,char *argv[])•
{
GtkWidget*app;.
GtkWidget*clist;
static char *titles[] = {
"First",
"Second",
"Third",
"Fourth"
};*
23
gnome_init("get","1.0",argc,argv);
app = gnome_app_new("Get","Get Arguments");
gtk_signal_connect(GTKOBJECT(app),"delete_event",
GTKSIGNALFUNC(eventDelete),NULL);
gtk_signal_connect(GTK_OBJECT(app),"destroy",
GTK_SIGNAL_FUNC(eventDestroy),NULL);
30
clist = gtk_clist_new_with_titles(4,titles);
gtk_object_set(GTKOBJECT(clist),
"GtkContainer::border_width",(gulong)12,
"GtkCList::reorderable",(gboolean)TRUE,
"GtkWidget::name", "fred"",
NULL);
gtk_signal_connect(GTK_OBJECT(clist),"show",
GTK_SIGNAL_FUNC(eventShow),NULL);
gnome_app_set_contents(GNOME_APP(app),clist);
40
gtk_widget_show_all(app);
gtk_main();
exit(0);
}
void eventShow(GtkWidget *widget,gpointer data)
{
int i;
GtkArg arg[5];
49
arg[0].name="GtkCList::reorderable";
arg[1].name="border_width";
arg[2].name * "GtkWidget::name";
arg[3].name = "GtkCList::n_columnsw;
arg[4].name = "row_height";
gtk_object_getv(GTK_OBJECT(widget),5,arg);
56
57for(i=0; i<5; i++) {
switch(arg[i].type) {
case GTKJTYPEJJINT:
g_print("%s=%u\n",arg[ij.name,
GTK_VALUE_UINT(arg[ i ]));
break;
case GTK_TYPE_ULONG:
g_print("%s=%lu\n",arg[i].name,
GTK_VALUE_ULONG(arg[ i ]));
break;
case GTK_TYPE_FLOAT:
g_print("%s=%g\n",arg[i].name,
GTK_VALUE_FLOAT(arg[ i ]));
break;
case GTK_TYPE_STRING:
g_print("%s=\"%s\*\n",arg[i].name,
GTK_VALUE_STRING(arg[i]));
break;
case GTKJTYPEBOOL:
g_print("%s=%s\n",arg[i].name,
GTK_VALUE_UINT(arg[i]) ? "TRUE" : "FALSE");
break;
defaults
g_print("%s is type %d\n",
arg[i].name,arg[i].type);
break;
}
}
}
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data) {
return(FALSE);
}
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data) {
gtk_main_quit();
return(O);
}
Объект GtkCList создается в строке 31 при вызове функции gtk_clist_new_with_titles (). Первый аргумент определяет число столбцов, а второй — текст заголовков столбцов. Вызов gtk_object_set() в строке 32 устанавливает некоторые из значений аргументов. Вызов gtk_signal_connect() в строке 37 вызывает функцию обратного вызова eventShow () для выполнения всякий раз, когда виджет скомплектован и появляется на экране.
Функция обратного вызова е vent Show () из строки 45 выбирает и отображает значения из виджета. В строках с 48 по 54 объявляется массив GtkArg и заполняется именами желаемых аргументов. Обратите внимание, что некоторые из строк имен определяют виджет, а некоторые этого не делают, что, впрочем, не имеет значения, если между любыми двумя виджетами в иерархии отсутствует конфликт имен. Используя этот мае-
сив и выполняя приведение типа GtkCList к GtkOb ject, массив заполняется данными из виджета. Для этого вызова — вместо завершения через NULL, как для функции gtk_ob ject^set в строке 36, — число членов массива передается как второй аргумент.
Цикл, начинающийся со строки 57, выполняется единожды для каждого члена массива. Оператор switch в строке 58 используется, чтобы отделить каждое значение аргумента от его типа данных и отобразить имя и значение. Вывод этой программы выглядит следующим образом:
GtkCList::reorderable*TRUE
border_width=l2
GtkWidget::name="fred"
GtkCList::n_columns=4.
row_height=0
Существует набор удобных макросов (подобно GTK__VALUE__UINT(), используемому в строке 61), который вы можете применять для извлечения значений из GtkArg. Макросы весьма просты, но вам не приходится иметь дело с внутренней структурой, и они возвращают данные корректного типа. Вот список всех макросов:
GTK_VALUE_ARGS(arg) GTKVALUEBOOL(arg) GTKVALUEBOXED(arg) GTKVALUECALLBACK(arg) GTKVALUECHAR(arg) GTKVALUECCALLBACK(arg) GTK_VALUE_DOUBLE(arg) GTK_VALUE_ENUM(arg) GTK_VALUE_FLAGS(arg) GTK_VALUE_FLOAT(arg)GTK_VALUE_ARGS(arg) GTKVALUEBOOL(arg) GTKVALUEBOXED(arg) GTKVALUECALLBACK(arg) GTKVALUECHAR(arg) GTKVALUECCALLBACK(arg) GTK_VALUE_DOUBLE(arg) GTK_VALUE_ENUM(arg) GTK_VALUE_FLAGS(arg) GTK_VALUE_FLOAT(arg)GTK_VALUE_FOREIGN(arg) GTK_VALUE_INT(arg) GTKVALUELONG(arg) GTKVALUEOBJECT(arg) GTKVALUEPOINTER(arg) GTKVALUESIGNAL(arg) GTKVALUESTRING(arg) GTK_VALUE_UCHAR(arg) GTKVALUEUINT(arg) GTK_VALUE_ULONG(arg)GTK_VALUE_FOREIGN(arg) GTK_VALUE_INT(arg) GTKVALUELONG(arg) GTKVALUEOBJECT(arg) GTKVALUEPOINTER(arg) GTKVALUESIGNAL(arg) GTKVALUESTRING(arg) GTK_VALUE_UCHAR(arg) GTKVALUEUINT(arg) GTK_VALUE_ULONG(arg)
GTK_VALUE_ARGS(arg) GTKVALUEBOOL(arg) GTKVALUEBOXED(arg) GTKVALUECALLBACK(arg) GTKVALUECHAR(arg) GTKVALUECCALLBACK(arg) GTK_VALUE_DOUBLE(arg) GTK_VALUE_ENUM(arg) GTK_VALUE_FLAGS(arg) GTK_VALUE_FLOAT(arg)
GTK_VALUE_ARGS(arg) GTKVALUEBOOL(arg) GTKVALUEBOXED(arg) GTKVALUECALLBACK(arg) GTKVALUECHAR(arg) GTKVALUECCALLBACK(arg) GTK_VALUE_DOUBLE(arg) GTK_VALUE_ENUM(arg) GTK_VALUE_FLAGS(arg) GTK_VALUE_FLOAT(arg)
GTK_VALUE_FOREIGN(arg) GTK_VALUE_INT(arg) GTKVALUELONG(arg) GTKVALUEOBJECT(arg) GTKVALUEPOINTER(arg) GTKVALUESIGNAL(arg) GTKVALUESTRING(arg) GTK_VALUE_UCHAR(arg) GTKVALUEUINT(arg) GTK_VALUE_ULONG(arg)
GTK_VALUE_FOREIGN(arg) GTK_VALUE_INT(arg) GTKVALUELONG(arg) GTKVALUEOBJECT(arg) GTKVALUEPOINTER(arg) GTKVALUESIGNAL(arg) GTKVALUESTRING(arg) GTK_VALUE_UCHAR(arg) GTKVALUEUINT(arg) GTK_VALUE_ULONG(arg)
Создание, реализация, преобразование и показ
Следующее описание предназначено для концептуального обзора рождения, жизни и смерти виджетов. Дело в том, что виджеты могут усложняться, а многие изменения происходят неявно, как бы за кулисами, так что действительный процесс изменяется от одного виджета к другому. Подробная информация относительно этого в главе 18.
Когда виджет рождается и проходит свой путь от шаблона бит в памяти до графического объекта, появляющегося на экране дисплея, то происходят процессы создания, реализации, преобразования и отображения виджета. Затем в конце жизни он скрывается, убирается соответствие, виджет деактивизируется и разрушается. Но это отнюдь не линейная последовательность. В течение жизни ваше приложение может перемещать виджет вперед и назад между отображением и сокрытием, заставляя его появляться и исчезать. Также в целях перемещения виджета из одного родительского окна в другое может уничтожаться его реализация, а затем он реализуется снова.
ПРИМЕЧАНИЕ НАУЧНОГО РЕДАКТОРА .
Процесс преобразования предполагает конвертирование логических координат устройства отображения в физические и обратно. Подобная установка соответствия обязательна и связана с выделением и освобождением памяти.
Создание и разрушение
У каждого виджета есть, по крайней мере, одна функция типа _new, которую вы можете использовать для создания его новых экземпляров. Например, gtk_label_new() может использоваться для создания виджетов GtkLabel, a gnome_about_new() — для создания виджетов GnomeAbout. Когда, виджет впервые создается, он представляет собой пустую оболочку: у него нет окна и родителя. Многое должно происходить прежде, чем он может быть использован.
Когда виджет уничтожен, вся занимаемая им память возвращается системе — он не может использоваться снова. Вы можете разрушить (уничтожить) виджет вызовом gtk_widget_destroy (). Если виджет относится к типу, имеющему более чем одну ссылку, он также может быть уничтожен вызовом gtk_widget_unref(), который уменьшает счетчик ссылок на единицу и, если значение счетчика достигает нуля, разрушает виджет. Обязанность этой функции удостовериться, что окно скрыто, удалено соответствие и уничтожена реализация прежде, чем он будет разрушен. Уничтожение виджета возвращает всю распределенную память назад системе.
Показ и сокрытие
Когда виджет отображается, окно (или окна) виджета появляется на экране дисплея. В этом состоянии окно активно и доступно для действий, связанных с клавиатурой и мышью. Вначале окно возникает в области, подготовленной для него менеджером окон. А затем отображается вызовом gtk_widget_show(), который в случае необходимости вызывает gtk_widget_map() и gtk_widget_realize().
Когда виджет сокрыт, его окно больше не видимо на экране. Для скрытого окна также не выполняется преобразование, позволяющее виджету-контейнеру повторно и автоматически установить соответствие для его других дочерних компонентов при обновлении экрана дисплея. Например, если вы скрываете кнопку из меню, оставшиеся кнопки перемещаются так, что не остается пустого пространства. Чтобы скрыть окно, вызовите функцию gtk_widgеt_hide( ), которая автоматически вызовет gtk_widget_unmap().
Установка преобразования и отказ от него
Вы можете вызвать из вашего приложения функции gtk_widget_map () и gtk_widget_unmap (), но это требуется редко. Функции отображения и сокрытия заботятся об этом вместо вас.
Для окна виджета выполняется преобразование (устанавливается соответствие), когда менеджер окон выбирает размер и место для него на экране дисплея. Преобразование неприменимо к виджетам, которые вы сохраняете в контейнерах или как-то иначе включаете в одно из ваших существующих окон, но применяется к каждому окну верхнего уровня, всплывающим диалоговым окнам и меню. Для меню должно быть установлено соответствие, потому что оно может свободно простираться в пределах его родительского окна. Вы можете выполнить преобразование окна путем обращения к gtk_widgеt_map(), которая в случае необходимости вызывает gtk_widget_realize().
Отказ от выполнения преобразований для виджета производится в том случае, когда менеджером окон получены инструкции для удаления всей информации, касающейся размеров и положения его окна. Для окна отмена преобразования может быть выполнена вызовом gtk widget unmap().
Реализация и деактивизация
Вы можете вызвать из вашего приложения функции gtk_widget_realize() и gtk_widget_unrealize(), но это требуется редко. Функции отображения и сокрытия заботятся об этом вместо вас. .
Виджет реализован, если его окно и другие внутренние ресурсы распределены (выделены). Когда окно виджета реализовано, оно должно быть уже назначено родительскому окну, которое также должно быть реализовано. Виджет реализуется с помощью вызова gtk_widget_realize().
Деактивизированный виджет возвращается к виду, имевшему место при его первоначальном создании. Его окно освобождает память, и любые события, предназначенные для него, удаляются из очереди событий. В случае необходимости для окна выполняется сокрытие и отмена преобразования прежде, чем оно будет деактивизировано. Виджет может быть деактивизирован с помощью вызова gtk_widget_unrealize().
Показ и сокрытие кнопки
Как прикладному программисту вам почти никогда не придется волноваться относительно реализации, деактивизации, преобразования или отказа от него. Лишь придется создавать новые виджеты и уничтожать их по концу работы. Фактически следует побеспокоиться об их разрушении, если ваша программа будет продолжать выполняться после того, как вы закончите работу с виджетами; когда ваша программа прекращает свое выполнение, вся память, распределенная для виджетов, возвращается системе.
Сокрытие и показ необходимы не столь уж часто, но возникают случаи, когда они могут быть весьма полезны. Следующий пример показывает, как сделать, чтобы кнопка возникла и исчезла.
/♦♦ hideshow.с ♦*/
tinclude <gnome.h>
3
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent ♦event,gpointer data);
void eventHideShow(GtkWidget *widget,GtkWidget *button);
GtkWidget *createLayout();
10
int main(int argc,char *argv[])
{
GtkWidget*app;
GtkWidget*hideshow;
GtkWidget*button;
16GtkWidget*box;
17
18 gnome_init("hideshow*,"1.0",argc,argv);
19 app « gnome_app_new("hideshow","Widget Hiding");
20gtk_container_set_border_width(GTK_CONTAINER(app),30);
21gtk_signal connect(GTK_OBJECT(app),"deleteevent",
GTK__SIGNAL__FUNC( event Delete),NULL);
gtk_signal_connect(GTKOBJECT(app),"destroy",
GTK SIGNAL_FUNC(eventDestroy),NULL);
“
26
box = gtk_hbox_new(FALSE,0);
hideshow = gtk_button_new_with_label("Hide/Show");
gtk_box_pack_start(GTKBOX(box),hideshow,
FALSE,TRUE,0);
button = gtk_button_new_with_label("Button");
gtk_signal_connect(GTK_OBJECT(hideshow),"clicked",
GTK_SIGNAL_FUNC(eventHideShow),button);
gtkboxpackstart(GTKBOX(box),button,
FALSE,TRUE,0);
gnome_app_set_contents(GNOME_APP(app),box);
gtk_widget_show_all(app);
38
gtk_main();
exit(0);
}
void eventHideShow(GtkWidget *widget,GtkWidget *button) {
if(GTK_WIDGET_VISIBLE(button))
gtk_widget_hide(button);
else
gtk_widget_show(button);
}
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data) {
return(FALSE);
}
gini eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data) {
gtk_main_quit();
return(O);
}
|Hide/Show| Button)|Hide/Show| Button)Рисунок 14.1.Показ двух кнопокРисунок 14.1.Показ двух кнопокВ строке 27 создается горизонтальный ящик. В строках с 28 по 37 создаются две кнопки, и одной из них назначается функция обратного вызова; они упаковываются в горизонтальный ящик, который устанавливается как виджет для дальнейшего отображения в окне приложения. В результате экран дисплея будет выглядеть, как показано на рисунке 14.1. Выбор кнопки слева выполняется в строке 42 путем обращения к функции обратного вызова eventHideShow(). В строке 43 макрос GTK_WIDGET_VISIBLE() определяет, отображается виджет в действительности или нет. Если он в настоящее время не видим, то может быть отображен при обращении к gtk_widget_show(). А если отображается, то при обращении к gtk_widget_hide() может быть скрыт и выглядеть, как на рисунке 14.2.
|Hide/Show| Button)
|Hide/Show| Button)
Рисунок 14.1.
Показ двух кнопок
Рисунок 14.1.
Показ двух кнопок
- я Х:
|Hide/Sho4
Рисунок 14.2.
Одна кнопка отображается, а другая — скрыта
В этом примере для демонстрации отображения и сокрытия используется простая кнопка, но вы можете использовать тот же прием для отображения и сокрытия составного виджета. Например, если у вас есть контейнер, заполненный другими виджетами (кнопками, метками и т.д.), все, что вы должны делать, — это отображать и скрывать контейнер, потому что никакой виджет не может быть видимым, если невидим его родитель.
ПРИМЕЧАНИЕ
С некоторыми контейнерами у вас могут возникнуть проблемы. Некоторые контейнеры в некоторых конфигурациях не способны взаимодействовать со скрываемым виджетом и снова делать его видимым. Если в том случае, когда виджет скрыт, контейнер собирается сомкнуть ряды других виджетов, чтобы заполнить пустое пространство, оставленное скрытым виджетом, то он не сможет сделать доступным место для скрытого виджета, когда тот появится вновь. Продолжайте и посмотрите, работает ли это, но имейте в запасе и альтернативный вариант.
Стили виджета
Стили (styles) виджета — это установки, которые определяют, как виджет отображает сам себя. Вы можете установить шрифты для виджетов, используемые при отображении текста. Вы также можете установить цвета виджетов или использовать фоновое цветное (растровое) изображение вместо цвета фона.
Существуют различные установки для каждого из пяти возможных состояний отображения виджета. Пять состояний перечислены в табл. 14.1. Не все виджеты способны находиться во всех состояниях (например, нет такой вещи, как активная метка), но кнопка — прекрасный пример виджета, который может находиться в любом из пяти состояний.
Таблица 14.1 Пять состояний виджета
Название состояния
Описание
GTK_STATE_NkRMAL
Это состояние, заданное по умолчанию. Все виджеты сначала появляются в этом состоянии и возвращаются к нему всякий раз,
когда не применяется ни одно из других.
GTK_STATE_ ACTIVE
Виджет указывает действие. Например, если кнопка нажимается, она активна. Вы можете установить, чтобы виджет изменял свой вид как индикатор становящегося активным фонового процесса
или открываемого файла.
GTK_STATE_PRELIGHT
Указатель мыши находится внутри виджета. Кнопки по умолчанию становятся более светлого цвета, как только мышь проходит по ним.
GTK_STATE_SELECTEK
Виджет — список (или некоторый другой контейнер, который позволяет компонентам быть выбранными) и в настоящее время
выбран.
GTK_STATEJNSENSITIVE
Вид виджета, когда он недоступен и не реагирует на мышь.
Обычно текст или изображение виджета выводятся в сером цвете
или в полутонах.
Все эти установки сохраняются в единой структуре. Каждый виджет содержит указатель на одну из этих структур. Общедоступная часть структуры выглядит следующим образом:
struct _GtkStyle {
GtkStyleClass *klass;
GdkColor fg[5];
GdkColor bg[5 ];
GdkColor light[5];
GdkColor dark[ 5 ];
GdkColor mid[5J;
GdkColor text[ 5 ];
GdkColor base[5];
GdkColor black;
GdkColor white;
GdkFont *font;
GdkGC *fg_gc[5);
GdkGC *bg_gc[5];
GdkGC *light_gc[5];
GdkGC *dark_gc[ 5 ];
GdkGC *mid_gc[5];
GdkGC *text_gc[ 5 ];
GdkGC *base_gc[ 5 ];
GdkGC *black_gc;
GdkGC *white_gc;
GdkPixmap *bg_pixmap[5];
Есть еще несколько полей внизу структуры, но они предназначены только для внутреннего использования. Следующая программа инициализирует GNOME и отображает содержимое структуры GtkStyle. В любом приложении каждому новому виджету назначается та же самая структура стиля, заставляющая все виджеты в приложении быть унифицированными, а значит, отображаться и действовать одинаково.
/** examine.с *♦/
Iinclude <gnome.h>
void showit();
5
int main(int argc,char *argv[])
{
int i;
GtkStyle *style;
GtkWidget *app;
11
gnome_init("examine","1.0",argc,argv);
app = gnome_app_new("examine","Examine");
14
gtk_widget_show(app);
style = app->style;
17
. printf("Normal Active Prelight"
" Selected InsensitiveXn");
printf(" fg:")r
21for(i*0; i<5; i++)
22printf(" 0x%081X",style->fg[i].pixel);
23printf("\nbg:");
24for(i=0; i<5;i++)
25printf(" 0x%081X",style->bg[i].pixel);
26printf("\n light:");
27for(i=0; i<5;i++)
28293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576 }28293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576 }
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76 }
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76 }
printf(" 0x%081X",style->light[i].pixel); print!(" \n dark:");
for(i=0; i<5; i++)
printf(" 0x%081X",style->dark[i].pixel);
printf("\nmid:");
for(i=0; i<5; i++)
printf(" 0x%081X",style->mid[i].pixel);
printf("\n text:");
for(i=0; i<5; i++)
printf(" 0x%081X",style->text[iJ.pixel);
printf("\n base:");
for(i=0; i<5; i++)
printf(" 0x%081X",style~>base[i].pixel);
printf("\n\nblack: 0x%081X\n",
style->black.pixel);
printf("white: 0x%081X\n"f
style->white.pixel);
printf("\nfg_gc:");
for(i=0; i<5; i++)
printf(" %p"fstyle->fg_gc[i]);
printf("\nbg__gc:");
for(i=0; i<5; i++)
printf(" %p",style->bg_gc[i]);
printf("\nlight_gc:"); for(i=0; i<5; i++)
printf(" %p",style->light_gc[i]);
printf("\n darkgc:");
for(i=0; i<5; i++)
printf(" %p",style->dark_gc[i]);
printf("\n mid_gc:"); for(i=0; i<5; i++)
printf(" Ip",style->mid_gc[ i J);
printf("\n textgc:"); for(i=0; i<5; i++)
printf(" %p",style->text_gc[i]);
printf("\n basegc:");
for(i=0; i<5; i++)
printf(" %p",style->base_gc[ i J);
printf("\n\nbgpixmap:"); for(i=0; i<5; i++) {
if(style->bg_pixmap[i] == NULL)
printf(" 0x0000000");
else printf(" %p",style->bg_pixmap[i]);
} printf("\n");
exit(0);
В строках 12 и 13 инициализируется среда GNOME и создается окно приложения. Обращение к gtk_widget__show() в строке 15 реализует окно и конфигурирует его для отображения — это должно быть выполнено, чтобы сделать стиль доступным, потому виджет, пока он реализован, установлен в GtkStyle. В остальной части программы (строки с 18 по 73) печатаются значения из структуры. Вывод программы выглядит следующим образом:
fg: bg: light: dark: mid: text: base:fg: bg: light: dark: mid: text: base:
fg: bg: light: dark: mid: text: base:
fg: bg: light: dark: mid: text: base:
Normal 0x00000000 0x00006B5A 0x00007FFF 0x00004A52 0x00006739 0x00000000 0x00007FFF
Active 0x00000000 0x00006318 0X00007FFF 0x00004631 0x00006318 0x00000000 0x00007FFF
Prelight 0x00000000 0x000077BD 0X00007FFF 0x00005294 0x00006B5A 0x00000000 0x00007FFF
Selected 0X00007FFF 0x00000013 0x00000019 0x0000084В 0x00000432 0x00007FFF 0x00007FFF
Insensitive 0x000039CE 0x00006B5A 0X00007FFF 0X00004A52 0x00006739 0X00O06B5A 0x00006B5A
black: 0x00000000white: 0x00007FFF
fg_gc: bg_gc: light_gc: darkgc:mid_gc: textgc: basegc:fg_gc: bg_gc: light_gc: darkgc:mid_gc: textgc: basegc:0x8075fb0 0x8076520 0x8076490 0x80765b0 0x8076640 0x8075fb0 0x80764900x8075fb0 0x8076520 0x8076490 0x80765b0 0x8076640 0x8075fb0 0x80764900x8075fb0 0x80766d0 0x8076490 0x8076760 0x80766d0 0x8075fb0 0x80764900x8075fb0 0x80766d0 0x8076490 0x8076760 0x80766d0 0x8075fb0 0x80764900x8075fb0 0x80767f0 0x8076490 0x8076880 0x8076520 0x8075fb0 0x80764900x8075fb0 0x80767f0 0x8076490 0x8076880 0x8076520 0x8075fb0 0x80764900x8076490 0x8076910 0x8076da8 0x8076e38 0x8076ec8 0x8076490 0x80764900x8076490 0x8076910 0x8076da8 0x8076e38 0x8076ec8 0x8076490 0x80764900x8076158 0x8076520 0x8076490 0x80765b0 0x8076640 0x8076520 0x80765200x8076158 0x8076520 0x8076490 0x80765b0 0x8076640 0x8076520 0x8076520
fg_gc: bg_gc: light_gc: darkgc:
mid_gc: textgc: basegc:
fg_gc: bg_gc: light_gc: darkgc:
mid_gc: textgc: basegc:
0x8075fb0 0x8076520 0x8076490 0x80765b0 0x8076640 0x8075fb0 0x8076490
0x8075fb0 0x8076520 0x8076490 0x80765b0 0x8076640 0x8075fb0 0x8076490
0x8075fb0 0x80766d0 0x8076490 0x8076760 0x80766d0 0x8075fb0 0x8076490
0x8075fb0 0x80766d0 0x8076490 0x8076760 0x80766d0 0x8075fb0 0x8076490
0x8075fb0 0x80767f0 0x8076490 0x8076880 0x8076520 0x8075fb0 0x8076490
0x8075fb0 0x80767f0 0x8076490 0x8076880 0x8076520 0x8075fb0 0x8076490
0x8076490 0x8076910 0x8076da8 0x8076e38 0x8076ec8 0x8076490 0x8076490
0x8076490 0x8076910 0x8076da8 0x8076e38 0x8076ec8 0x8076490 0x8076490
0x8076158 0x8076520 0x8076490 0x80765b0 0x8076640 0x8076520 0x8076520
0x8076158 0x8076520 0x8076490 0x80765b0 0x8076640 0x8076520 0x8076520
bgpixmap: 0x0000000 0x0000000 0x0000000 0x0000000 0x0000000
Имеются семь массивов установок цвета. Фактические значения пиксела разнятся при переходе от одной системы к другой. Отображенные здесь пикселы были созданы в системе, использующей 15 бит для каждого из основных цветов, так что белый — это 7FFF, а черный — 0000. Вы можете видеть, как меняются цвета при переходе от одного состояния к другому. Например, обычный цвет фона (bg) — серый цвет 6В5А, но при активизации он становится чуть более ярким, принимая значение 6318. Если виджет реагирует на присутствие указателя мыши, как это делает виджет кнопки, цвет меняется на почти белый (77BD). Когда виджет выбран в списке, то его основной цвет меняется на белый (7FFF), а его фоновый цвет — на почти черный (0013). Цвет текста также меняется от черного к белому. Значения светлого и темного цветов используются для окрашивания рамок вокруг окна виджета: будут ли кромки светлыми или темными зависит от того, должны ли тени виджета изображаться как скошенные внутрь или наружу.
Настройка стилей виджета
Со всей информацией о цвете и шрифте, содержащейся в одном месте, довольно просто настроить виджет. В следующей программе устанавливается вид кнопки путем задания значений для ее структуры GtkStyle.
/** stylemod.c **/
#include <gnome.h>.
3
#include "modulate.xpm"
5
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
void eventvisibility(GtkWidget *widget,gpointer data);
11
GdkColor red = {0, OxFFFF, 0x0000, 0x0000 };
GdkColor green = {0, 0x0000, OxFFFF, 0x0000 };
GdkColor cyan = {0, 0x0000, OxFFFF, OxFFFF };
-
int main(int argc,char *argv[))
{'
GtkWidget *app;
GtkWidget ♦button;'
GtkStyle *current;
GtkStyle *new;
22GdkBitmap *mask;
23
24gnome_init("stylemod","1.0",argc,argv);
25app = gnome_app_new("stylemod","GtkStyle");
26gtk_container_set_border_width(GTKCONTAINER(app),40);
27gtk_signal_connect(GTKOBJECT(app),"delete_event",
GTK_SIGNAL_FUNC(eventDelete),NULL);
gtksignalconnect(GTKOBJECT(app),"destroy"w
GTK__SIGNAL_FUNC( event De Stroy),NULL);
31
gtk_widget show(app);
~
button = gtkbuttonnewwithlabel("Button");
gtk_widget_set_usize(button,100,100);
36
current = gtk_widget_get_default_style();
new = gtk_style_copy(current);
39
new->bg[GTK_STATE_ACTIVE] = green;
new->bg[GTK_STATE_PRELIGHT] = red;
new->bg[GTK_STATE_NORMAL] = cyan;
new->bg_pixmap[GTK_STATE_NORMAL] =
4gdk_pixmap_create_f romxpmd (app->window,
&mask,&new->bg[GTKSTATEJiORMAL],
(gchar **)modulate);
gtk_widget_set style(button,new);
~
. gnomeappsetcontents(GNOME_APP(app),button);
gtkwidgetshowall(app);
-
gtk_main();
exit(0);
}.
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data) {
return(FALSE);
}
gint eventDestroy(GtkWidget *widget,
GdkEvent ♦event,gpointer data) {
gtk_main_quit();’
return(0);
}
Сразу после того, как в строках с 24 по 30 инициализируется среда GNOME, в обращении к gtk_widget_show() в строке 32 используется окно верхнего уровня этого приложения. Такая инициализация необходима, потому что она создает карту цветности и делает эту информацию доступной, что требуется для настройки стилей виджета. Стили могут быть установлены и позже, уже после того, как все виджеты отображены, но инициализация дает возможность конфигурировать виджеты перед их отображением.
11 лла
В строках 34 и 35 для создания большой кнопки вызываются функции gtk_button_new_with_label() и gtk_widget_set_usize().
В строке 37 выбирается текущее значение по умолчанию структуры GtkStyle. Это стиль, который применяется к каждому виджету, не имеющему своего собственного стиля. Можно создать полностью новый стиль, но это значило бы заполнить каждый член структуры GtkStyle, так что проще начать с заданного по умолчанию стиля и просто сделать необходимые изменения. Теперь, поскольку функцией gtk_widget_get_default_style() возвращен указатель и один и тот же указатель используется всеми виджетами в программе, внесение изменений непосредственно в заданный по умолчанию стиль меняет все виджеты приложения. Мы должны модифицировать его копию, так что в целях создания точного дубликата заданного по умолчанию значения GtkStyle в строке 38 выполняется вызов gtk_style_copy(). '
В строках с 40 по 42 в только что скопированную структуру GtkStyle назначаются цвета, которые должны использоваться для указания активного, подсвеченного и нормального состояний. Цвета определены в строках с 12 по 14, и нет необходимости распределять эти цвета, ибо они распределяются всякий раз, когда GtkStyle добавляется
к виджету.
В строке 43 создается цветное растровое изображение и устанавливается для использования кнопкой в ее обычном состоянии. В обращении к функции gdk_pixmap_create_from_xpm_d() используется окно и информация карты цветности от основного виджета приложения наряду с определением цветного растрового изображения, включенным в строке 4. Цветное растровое изображение установлено для активного состояния, а фоновый цвет для этого режима прилагается к функции создания растрового изображения в строке 45. Полученная кнопка показана на рис. 14.3. Цветное растровое изображение намного меньше, чем кнопка, но оно многократно повторяется и заполняет всю область кнопки.
Рисунок 14.3.Кнопка, демонстрирующая стиль цветного растрового изображенияРисунок 14.3.Кнопка, демонстрирующая стиль цветного растрового изображенияНовая информация о стиле устанавливается в виджет при обращении к gtk_widget_set_style() в строке 47. В строках 49 и 50 к главному окну добавляется кнопка, и вызов gtk_widget_show_all() вынуждает отображать окно, теперь содержащее кнопку.
Рисунок 14.3.
Кнопка, демонстрирующая стиль цветного растрового изображения
Рисунок 14.3.
Кнопка, демонстрирующая стиль цветного растрового изображения
Предшествующий пример показывает, как назначить стиль одиночному виджету. Чтобы применить специальные стили к нескольким виджетам, вы можете вызвать gtk_widget_set_style () для каждого из них или можете временно установить значение по умолчанию. Например, в следующем коде используется вновь созданный объект GtkStyle для создания более чем одного виджета:
current = gtk_widget_get_default_style(); new = gtk_style_copy(current);
/* Make modification to new style */ gtk_widget_push_style(new);
/* Create new widgets */ gtk_widget_pop_style();
Вызов gtk_widget_push_style() заменяет заданный по умолчанию стиль новым и сохраняет существующий, так что вызов gtk_widget_pop_style() восстанавливает его. Вы можете использовать это для специальной подстройки внешнего вида групп виджетов. Так как это ситуация push-pop (нажми-и-вытолкни), виджеты в пределах настроенной группы могут делать свои собственные регулировки. ■
Если у вас имеется виджет, стиль которого уже изменен, и вы должны создать другой виджет с теми же самыми изменениями, сделайте так:
style=gtk_widget_get_style(existingWidget);
gtk_widget_set_style(newWidget);
Конечно, если хотите выполнять дальнейшие модификации, следует работать с копией, потому что любые изменения, которые вы делаете с оригиналом, также воздействуют на существующий виджет.
Выводы
На самом низком уровне каждый отображаемый объект — это объект GtkWidget и в качестве такового может рассматриваться в вашей программе. Установка, сделанная на уровне виджета, может затрагивать дисплей и характер изменения его потомка — отображаемого объекта (любой объект с GtkWidget в его родословной называется виджетом). Что касается конфигурирования виджетов, то в этой главе рассматривались такие вопросы:,
Д Имеется несколько состояний существования виджета, простирающихся от низкоуровневого распределения до размещения на экране дисплее. Если Вам не нужно чего- нибудь специального, переход виджета от одного состояния к другому полностью автоматизирован.
: Если вашему приложению необходимо больше знать о виджете, то и такую информацию можно получить, что особенно полезно в случае виджета-контейнера, так как позволяет ознакомиться с геометрией любого содержащегося в нем виджета.
# Стиль виджета — его цветовые шаблоны и шрифты — может быть установлен для любого виджета в любое время. Также эти установки могут быть скопированы от одного виджета другому.
В следующей главе обсуждается специальный вид приложения. Он называется апплетом (applet) и отображает свое главное окно как кнопку на панели GNkME. Он обычнр используется для запуска приложений, но есть также виджеты специального назначения. Системное меню GNkME и часы — два примера апплетов специального назначения.
388
ГЛАВА15ГЛАВА15АпплетыАпплеты
ГЛАВА
15
ГЛАВА
15
Апплеты
Апплеты
В этой главе
® Создание апплета с окном внутри панели
# Использование апплета для запуска приложения
4 Отображение данных в панели с окном апплета
ф Корректировка размера и формы апплета с учетом ориентации панели
® Добавление опций в меню апплета
Апплет — прикладная программа GNkME с одной специальной характеристикой: она ^отображает свое главное окно как член панели рабочего стола GNkME. На панель возлагается ответственность за позиционирование и отображение окна. Апплет написать не труднее, чем приложение GNkME. Структура та же самая: вы вызываете функцию инициализации, создаете виджеты, которые будут отображены, и вызываете функцию цикла обработки событий. Виджет апплета и панель выполняют для вас большую часть работы. Как только ваш апплет запускается, вы можете делать с ним то же самое, что и с обычным приложением.
Упрощенный апплет
* Следующий пример демонстрирует минимальный код, необходимый для работы апплета. Его назначение<— отображать простую кнопку на панели.
/** simple_applet.c **/
linclude <gnome.h>
linclude <applet-widget.h>
4
Idefine APPLETNAME "simple-applet"
Idefine VERSION "1.0"
7
int main(int argc,char *argv[])
{
GtkWidget *applet;
GtkWidget *button;
12
applet_widget_init(APPLETNAME,VERSION,
argc,argv,
NULL,0,NULL);
' '
applet = applet_widget_new(APPLETNAME);
18
button » gtk_button_new_with_label("SimpleXnApplet");
gtk_widget_set_usize(button,48,48);
applet_widgetadd(APPLET_WIDGET(applet),button);
22
23gtk_widget_show_all(applet);
24
25appletwidgetgtkmain();
26•
27exit(0);
28 }'
Поскольку характеристики апплета обычно не являются частью приложения GNOME или GTK+, заголовочный файл апплета не включается через gnome.h. В строке 3 включается заголовочный файл applet-widget .h, который содержит определение AppletWidget и связанные с ним функции. Наследование апплета выглядит очень похоже на наследование любого другого воспроизводимого виджета:
AppletWidget->GtkPlug->GtkWindow->GtkBin->GtkContainer->GtkWidget->GtkObject
Вызов applet_widget_init() в строке 13 инициализирует сеанс. Такая функция делает для апплета то же самое, что делает gnome_init() для приложения GNOME. AppletWidget создается в строке 17 при помощи вызова applet_widget_new(). К тому же AppletWidget наследуется от GtkContainer, так что он может содержать любой воспроизводимый виджет, который вы захотите включить в него.
В строках с 19 по 22 создается кнопка и добавляется к виджету-апплету как компонент, который будет отображен. Размер кнопки установлен 48x48, чтобы соответствовать некоторым другим апплетам, обычно включаемым в панель. Однако панель автоматически изменяет свои размеры, чтобы разместить самый большой содержащийся в ней апплет, поэтому независимо от того, какой размер вы выбираете, ваш апплет будет видим.
В строке 23 для отображения апплета и всех его дочерних элементов вызывается gtk_widget_show_al1(). Точно так же, как любой другой виджет-контейнер, AppletWidget отображается сам и отображает все виджеты, которые он содержит. Функция applet_widget_gtk_main() вызывается в основном цикле в строке 25. Это апплетная версия gtk^main (). Она не выполняет возврата, пока программа не прекратит своего выполнения.
Рисунок 15.1.Простой апплет, появляющийся наРисунок 15.1.Простой апплет, появляющийся наВсякий раз, когда эта программа запущена, на панели появляется апплет, как показано на рис. 15.1. Кнопка реагирует на мышь, но, так как для кнопки не определен обратный вызов, никакого действия не происходит.
Рисунок 15.1.
Простой апплет, появляющийся на
Рисунок 15.1.
Простой апплет, появляющийся на
‘ Модули апплета не являются частью стандартного набора библиотек GNOME и GTK+ и должны быть включены отдельно. Далее следует make-файл, с помощью которого компилируется и компонуется эта программа.
СС=дсс
LDLIBS='gnome-config —libs gnomeui' -lpanel_applet -Ignorba
CFLAGS=-Wall -g 'gnome-config —cflags gnomeui'
all: simple_applet
simple applet: simple applet.о
Определение CFLAGS не меняется от приложения, но определение LDFLAGS должно включать библиотеки libpanel_applet и libgnorba.
Апплет, который запускает приложение
С апплетом можно проделать многое, но самое главное — при старте апплета запускать программу на выполнение. Щелкая на апплете, можно достичь всего, что вы достигаете вводом с командной строки. Следующая программа выполняет одну из утилит FTP:
/** ftp_applet.c **/
linclude <gnome.h>
linclude <applet-widget.h>
4
linclude "ftp.xpm"
6
void startcallback(GtkWidget *,gpointer data);
,
Idefine APPLETNAME "ftp-applet"
Idefine VERSION "1.0"
11
int main(int argc,char *argv[])
{
GtkWidget*applet;
GtkWidget*button;
GdkPixmap*pixmap;
GtkStyle *style;
GdkBitmap*mask;
GtkWidget*pixmapWidget;
20
applet_widget_init(APPLETNAME,VERSION,
argc,argv,
NULL,0,NULL);
.
applet = appletwidgetnew(APPLETNAME);
gtk_widget_show(applet);
27
style = gtk_widget_get_style(applet);
pixmap = gdk_pixmap_create_from_xpm_d(applet->window,
&mask,&style->bg[GTK_STATE_NORMAL],
(gchar **)ftp_xpm);.
pixmapWidget = gtk_pixmap_new(pixmap,mask);
'
button = gtk_button_new();
gtk_signal_connect(GTK_OBJECT(button),"clicked",
GTK_SIGNAL_FUNC(startcallback),NULL);
gtk_container_add(GTK_CONTAINER(button),pixmapWidget);
•
9applet_widget_add(APPLET_WIDGET(applet),button);
,
gtk_widget_show_all(applet);*
42
applet_widget_gtk_main();
44
exit(0);
}
void startcallback(GtkWidget *widget,gpointer data)
{'
system("wxftp &");
}
В строках с 21 по 25 инициализируется апплет и создается Appletwidget. Обращение к gtk_widget_show() в строке 26 реализует виджет — это необходимо, потому что программе для создания цветного растрового изображения, украшающего кнопку, нужна информация GtkStyle.
В строках с 28 по 32 используется информация окна апплета для создания цветного растрового изображения и его виджета. Цветное растровое изображение включено как файл ftp.xpm в строке 5. В строках с 34 по 37 создается кнопка, связывается с функцией обратного вызова startcallback (), и для художественного оформления кнопки назначается виджет растрового изображения.
Всякий раз, когда выбрана кнопка, выполняется обратный вызов startcallback() из строки 47. Есть только одна команда — вызов функции system() с командой для запуска программы. В этом примере запускается программа FTP под именем wxftp, но вы можете применять эту же методику для запуска любой программы, которая использует X как интерфейс пользователя. Обратите внимание, что в конце командной строки стоит амперсанд для запуска программы в фоновом режиме. Если амперсанд оставить, фоновый процесс порождает сам себя всякий раз, когда вы пытаетесь его закрыть.
Отображение меняющейся информации
Следующий апплет демонстрирует процент использования диска. Он отображает информацию, касающуюся одного дисковода, и постоянно обновляет ее.
/** status_applet.c **/
Iinclude <gnome.h> х
linclude <applet-widget.h>
linclude <stdio.h>
'
gint updateCallback(GtkWidget *label);•
void loadStats(void);
8
static int stlndex;
static int stLast;
static char stString[40][60];
*
Idefine APPLETNAME "status-applet"
Idefine VERSION "1.0"
15
int main(int argc,char *argv[])
{
GtkWidget *applet;
GtkWidget *label;
20
appletwidgetinit(APPLETNAME,VERSION,
argc,argv,
NULL,0,NULL); .
24
applet = applet_widget_new(APPLETNAME);*'
26
label • gtk_label_new("*\n 0% Used");-
gtkwidgetsetusize(label,75,47);
applet_widget_add(APPLET_WIDGET(applet),label);
gtk_widget_show(label);
31
loadStats();
updateCallback(label);
gtk_timeout_add(5000,(GtkFunction)updateCallback,
label);
36
gtk_widget_show_all(applet);
applet_widget_gtk_main();
exit(0);
}
gint updateCallback(GtkWidget *label)
{
if(stlndex > stLast)
loadStats();
gtk_label_set_text(GTK_LABEL(label),
6stString[stIndex++]);
return(TRUE);
}
void loadStats()
{
int i;
52FILE*df;
53charrawinput[80];
54charfileSystem[40];
55charpercent[40];
56
57stlndex = 0;
58stLast = 0;
59strcpy(stString[0],"No\nStats");
60
61if((df = popen("df","r"))==NULL)
62return;
63
64 fgets(rawinput,sizeof(rawinput),df);
65 while(fgets(rawinput,sizeof(rawinput),df) 1= NULL) {
66strtok(rawinput," \n");
67for(i=l; i<4; i++)
68strtok(NULL," \n");
69strcpy(percent,strtok(NULL," \n"));
70strcpy(fileSystem,strtok(NULL,” \n"));;
stLast * stlndex;
sprintf(stString[stIndex++],"%s\n%sUsed",
fileSystem,percent);
}
stlndex = 0;
pclose(df);
}
Рисунок 15.2.Апплет, постоянно обновляющий свое состояниеРисунок 15.2.Апплет, постоянно обновляющий свое состояниеВид полученного апплета показан на рис. 15.2.
Рисунок 15.2.
Апплет, постоянно обновляющий свое состояние
Рисунок 15.2.
Апплет, постоянно обновляющий свое состояние
В строках с 21 по 25 как обычно создается и инициализируется виджет типа апплет. В строках с 27 по 30 создается метка и добавляется к виджету как объект, который будет отображен. В отличие от многих виджетов область этой метки не квадратная: она сделана более широкой, чтобы помещались маршруты дисковых устройств.
Создается и вставляется исходный текст метки. Обращение к loadstats() в строке 32 создает массив текстовых строк, отображающих информацию. Вызов updateCallback() из строки 33 использует одну из строк массива как текст для метки. Вызов g tk__t imeou t_add () запускает пятисекундный интервальный таймер и назначает updateCallback() как функцию, которая будет вызываться.
Функция updateCallback() в строке 41 проверяет, все ли строки в массиве используются, и, если это так, вызывает loadStats() для создания нового набора строк. Вызов функции gtk_label_set_text() вставляет текст. Возвращаемое значение TRUE поддерживает таймер в рабочем состоянии. Если возвращается FALSE, таймер удаляется и эта функция повторно не вызывается. Если ваша программа желает изменить интервал таймера, функция updateCallback() может запустить новый таймер и затем вернуть FALSE, чтобы уничтожить предыдущий.
Функция loadStats (), начинающаяся в строке 49, считывает информацию о диске и создает массив строк текста для метки. Строки сохраняются в массиве stString, определенном в строке 11. Значение stLast установлено равным последнему допустимому индексу массива, и значение st Index установлено в нуль, так что updateCallback() отображает первую строку. Информация собирается путем выполнения утилиты df и возвращается через конвейер. В строке 64 считывается и отбрасывается первая строка вывода утилиты df, содержащая заголовки столбцов. Цикл, начинающийся со строки 64, выполняется по разу для каждой строки текста, пришедшей от df. Значения, которые вам нужны, — процент использования диска и точка монтирования — последние две лексемы в строке, так что программа пропускает все остальное и сохраняет эти лексемы в percent и filesystem. Функция sprintf () в строке 72 используется для форматирования текстовой строки метки.
Меню апплета
Выбор апплета с помощью правой кнопки мыши вызывает меню, показанное на рис. 15.3.• Заданное по умолчанию меню предоставляет два выбора: апплет может быть удален с панели (первая строка) или церемещен в другое местоположение (вторая строка). Вы можете добавлять элементы в меню и назначать для них обратные вызовы. Следующий апплет добавляет два элемента в меню, приводя его к виду, показанному на рис. 15.4./** menu_applet.с **/tinclude <gnome.h>Iinclude <applet-widget.h>4Idefine APPLETNAME "menu-applet"Idefine VERSION "1.0"'void changecallback(Appletwidget♦applet,GtkLabel *label);void aboutCallback(Appletwidget *applet,GtkLabel 10int main(int argc,char *argv[]){,GtkWidget *applet;Выбор апплета с помощью правой кнопки мыши вызывает меню, показанное на рис. 15.3.• Заданное по умолчанию меню предоставляет два выбора: апплет может быть удален с панели (первая строка) или церемещен в другое местоположение (вторая строка). Вы можете добавлять элементы в меню и назначать для них обратные вызовы. Следующий апплет добавляет два элемента в меню, приводя его к виду, показанному на рис. 15.4./** menu_applet.с **/tinclude <gnome.h>Iinclude <applet-widget.h>4Idefine APPLETNAME "menu-applet"Idefine VERSION "1.0"'void changecallback(Appletwidget♦applet,GtkLabel *label);void aboutCallback(Appletwidget *applet,GtkLabel 10int main(int argc,char *argv[]){,GtkWidget *applet;Remove from panel Move appletRemove from panel Move appletРисунок 15.3.Заданное no умолчанию меню апплетаРисунок 15.3.Заданное no умолчанию меню апплетаRemove from panel Move appletChange>»f About..Remove from panel Move appletChange>»f About..Рисунок 15.4.Меню апплета с двумя добавленными вариантами выбора для пользователяРисунок 15.4.Меню апплета с двумя добавленными вариантами выбора для пользователя♦label);♦label);
Выбор апплета с помощью правой кнопки мыши вызывает меню, показанное на рис. 15.3.
• Заданное по умолчанию меню предоставляет два выбора: апплет может быть удален с панели (первая строка) или церемещен в другое местоположение (вторая строка). Вы можете добавлять элементы в меню и назначать для них обратные вызовы. Следующий апплет добавляет два элемента в меню, приводя его к виду, показанному на рис. 15.4.
/** menu_applet.с **/
tinclude <gnome.h>
Iinclude <applet-widget.h>
4
Idefine APPLETNAME "menu-applet"
Idefine VERSION "1.0"
'
void changecallback(Appletwidget
♦applet,GtkLabel *label);
void aboutCallback(Appletwidget *applet,GtkLabel 10
int main(int argc,char *argv[])
{,
GtkWidget *applet;
Выбор апплета с помощью правой кнопки мыши вызывает меню, показанное на рис. 15.3.
• Заданное по умолчанию меню предоставляет два выбора: апплет может быть удален с панели (первая строка) или церемещен в другое местоположение (вторая строка). Вы можете добавлять элементы в меню и назначать для них обратные вызовы. Следующий апплет добавляет два элемента в меню, приводя его к виду, показанному на рис. 15.4.
/** menu_applet.с **/
tinclude <gnome.h>
Iinclude <applet-widget.h>
4
Idefine APPLETNAME "menu-applet"
Idefine VERSION "1.0"
'
void changecallback(Appletwidget
♦applet,GtkLabel *label);
void aboutCallback(Appletwidget *applet,GtkLabel 10
int main(int argc,char *argv[])
{,
GtkWidget *applet;
Remove from panel Move applet
Remove from panel Move applet
Рисунок 15.3.
Заданное no умолчанию меню апплета
Рисунок 15.3.
Заданное no умолчанию меню апплета
Remove from panel Move applet
Change
>»f About..
Remove from panel Move applet
Change
>»f About..
Рисунок 15.4.
Меню апплета с двумя добавленными вариантами выбора для пользователя
Рисунок 15.4.
Меню апплета с двумя добавленными вариантами выбора для пользователя
♦label);
♦label);
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
' 63
64
65
66
67
68
69
70
71
GtkWidget *label;
applet_widget_init(APPLETNAME,VERSION,
•argc,argv,
NULL,0,NULL);'
applet = applet_widget_new(APPLETNAME);
label = gtk_label_new("MenuXnApplet"); gtk_widget_set_usize(label,48,48);
applet_widget_add(APPLET_WIDGET(applet),label);
gtk_widget_show_all(applet);
applet_widget_register_callback( APPLETJWIDGET(applet),* "change","Change", (AppletCallbackFunc)changecallback,label);
applet_widget_register_stock_callback( APPLET_WIDGET(applet), "about",GNOME_STOCK_MENU_ABOUT, "About...", (AppletCallbackFunc)aboutCallback,label);
applet_widget_gtk_main();
exit(0);
}
void changecallback(Appletwidget *applet,GtkLabel *label) {
int i;
static GtkStyle *oldStyle = NULL;.
static GtkStyle *newStyle = NULL;
static int change = TRUE;
if(oldStyle == NULL) {
. oldStyle = gtkwidgetgetstyle(GTK_WIDGET(label)); newStyle = gtkstylecopy(oldStyle);
for(i=0; i<5; i++) { newStyle->fg[i] = oldStyle->light[i]; newStyle->fg_gc[i] = oldStyle->light_gc[i];
'}
}
if(change)
gtk_widget_set_style(GTK_WIDGET(label),newStyle); else
gtk_widget_set_style(GTK_WIDGET(label),oldStyle); change = 1 change; •**
}'
void aboutCallback(Appletwidget *applet,GtkLabel *label) {
GtkWidget *aboutBox;
const gchar *writtenBy[] = {
"Arthur Griffith", "George Spelvin", NULL
72
73
74
75
76
77
78
79
80
81
82
83 }
aboutBox = gnome_about_new("Menu Applet", "0.0",/
"(C) 1999 the Free Software Foundation", writtenBy,
"This applet demonstrates the code " "necessary to add items to the menu. " "The added menu items can be simple text "or it can be one of the stock items", NULL);x
gtk_widget_show(aboutBox);
В строках с 16 по 26 выполняется стандартный набор задач, необходимых для создания виджета, который отображает GtkLabel с текстом.
В строке 28 при помощи вызова applet_widget_register_callback() добавлен новый пункт меню. Из двух строк имен в строке 30 первое — это внутреннее имя виджета, а второе — текст, который появляется в меню. Последние два аргумента — это функция обратного вызова и данные, которые должны быть переданы ей (в этом случае адрес метки виджета).
Другой пункт меню добавлен с использованием одного из наборов определений меню при помощи вызова applet_widget_register_stock_callback() в строке 32. Строка в кавычках из строки 34 должна быть внутренним именем виджета. В строке 34 также определена константа, идентифицирующая набор пунктов меню. Строка в кавычках из программной строки 35 — это текст, который появляется в меню. Последние два аргумента в строке 36 определяют функцию обратного вызова и данные, которые нужно передать ей.
Функция обратного вызова changeCallback(), начинающаяся со строки 42, изменяет цвет текста в окне апплета. Она выполняет это, сохраняя копию GtkStyle и также делая и сохраняя копию GtkStyle с измененным основным цветом. Цикл, начинающийся в строке 52, изменяет копию GtkStyle так, что настройки переднего плана сохраняются такими же, как светлые установки. Изменение булева переключателя проверяется в строке 58; по тексту определяется, который объект GtkStyle используется. В строке 62 меняется (возвращается назад) переключатель для следующего вызова этой функции.
Функция обратного вызова aboutCallback(), начинающаяся со строки 64, отображает для апплета стандартное окно About.
Ориентация панели
Всякий раз, когда апплет отображается на панели, она подстраивает свой размер, чтобы удостовериться, что окно апплета отображается полностью. У этого метода имеется недостаток именно для больших апплетов, так как панель может расшириться, превышая выделенное место на рабочем столе. Одно из решений состоит в том, чтобы уменьшить ваше окно апплета или в вертикальном, или в горизонтальном направлении в зависимости от ориентации панели. В следующем апплете определяются ориентация и положение панели и выполняется соответствующая подстройка.
/** orient_applet.с **/
linclude <gnome.h>
linclude <applet-widget.h>
linclude <stdio.h>
5
Idefine APPLETNAME "orient-applet"
idefine VERSION "1.0"
'
void orientEvent(GtkWidget *widget,PanelOrientType orient,
GtkWidget ♦label);
11
int main(int argc,char *argv[])
{
GtkWidget *applet;
GtkWidget ♦label;
16
applet_widget_init(APPLETNAME,VERSION,
argc,argv,
NULL,0,NULL);
-
- applet * applet widget—new(APPLETNAME);
*
label = gtk_label_new(" ");
gtk_widget_set_usize(label,48,48);
25
gtk_signal_connect(GTK_OBJECT(applet),"change_orient",
GTK_SIGNAL_FUNC(orientEvent),label);
.
applet_widget_add(APPLET_WIDGET(applet),label);
gtk-Widget-ShoW-dll(applet);
applet-Widget_gtk_main();
exit(0);
}
void orientEvent(GtkWidget *widget,PanelOrientType orient,
■ GtkWidget *label)
{
gchar *text;
38
switch(orient) {
case ORIENT-UP:
gtk-Widget-8et-Usize(label,100,48);
text ="HorizontalBottom";
break;
case ORIENT—DOWN:
45gtk_widget-Set-Usize(label,90r48);
text ="HorizontalTop";
break;
case ORIENT—LEFT:.
49gtk-Widget-Set-Usize(label,48,48);
text * "VerticalXnRight";
break;
case ORIENT-RIGHT:.
53gtk-Widget-Set-Usize(label,48,48);(.
text « "VerticalXnLeft";
break;
>.
7gtk-label-Set-text (GTK_LABEL (label), text)‘;
}
В строках с 17 no 21 создается апплет, и для его отображаемого окна в строках 23 и 24 создается и устанавливается по размеру метка.
В строке 26 выполняется обращение к gtk_signal_connect(), которое связывает сигнал по имени "change_orient" с виджетом типа апплет. Это специальный сигнал, определенный внутри AppletWidget. Такое сделано для вызова функции orientEvent() всякий раз, когда панель изменяет свою ориентацию. В строках 29 и 30 в апплет вставляется метка, и он помещается на панель. Обратный вызов ”change_orient" делается, когда апплет впервые появляется на панели.
Функция обратного вызова orientEvent(), начинающаяся в строке 34, изменяет текст и размеры метки, чтобы отразить текущую организацию. Второй аргумент PanelOrientType используется в операторе switch из строки 40 для выбора ориентации. Названия ориентации относятся к направлению от апплета до корневого окна. То есть, ORIENT_UP означает, что апплет находится внизу окна с корневым окном выше него. ORIENT_LEFT означает, что апплет располагается справа с корневым окном слева от него.
Размер метки изменяется, чтобы соответствовать ориентации. Если апплет находится наверху панели или внизу экрана, метка расширяется, чтобы расположить одиночную текстовую строку. Если апплет находится на одной из сторон, метка сужается и текстовая строка разбивается на части.
Выводы
Апплет — программа с маленьким главным окном, и это окно появляется внутри панели GNOME. Апплет получает свои специальные возможности от AppletWidget, который действует как уровень представления для главного окна апплета. В этой главе обсуждались детали и опции при формировании апплета:
* Функции, которые определяют и управляют апплетом, очень похожи на те, которые определяют и управляют приложением. Функция applet_widget_init () используется вместо gnome_init(). Функция applet_widget_new() используется вместо gnome_app_new(). Функция applet_widget_gtk_main() используется вместо gtk_main ().
® Апплет может быть чувствительной к мыши кнопкой, которая служит входом в более объемную программу, но он также может использоваться для отображения коротких сообщений и простой информации.
е Апплет может добавить к своему меню любое число пунктов.
© Апплет может изменять свои размеры и переориентировать себя, чтобы соответствовать текущему окружению.
Следующая глава объясняет, как можно сделать доступными связи между процессами в интерфейсе GUI. Мышь может использоваться для перетаскивания объектов из одного местоположения в другое. Все уловки, требуемые для упаковки объекта и передачи его принадлежности от одного приложения к другому, встраиваются в GNkME API.
главаПеретащить, бросить,
4 жкопировать, вырезать и
■ О вставить
В этой главе
# Приспосабливание текста к перемещению из одного окна в другое
в Приспосабливание графики к перемещению из одного окна в другое
Ш Использование в GNkME средств drag-and-drop для осуществления операций cut-and-paste
Linux предоставляет ряд способов, с помощью которых один процесс может связываться с другим: через совместно используемую память, конвейеры, Х-со- бытия и сигналы низкого уровня. Существуют два других метода, которые особенно полезны для интерфейса GLM, так как они работают с действиями мыши и клавиатуры. Операция drag-and-drop (перетащить и бросить) имеет место, когда с помощью мыши выбирается элемент, нажимается и удерживается кнопка и элемент перемещается в новое местоположение. Операция cut-and-paste или copy-and-paste (вырезать и вставить или копировать и вставить) имеет место, когда выбранный текст записывается в di pboard (буфер обмена) и из буфера обмена он вставляется в текстовое окно.
Операция drag-and-drop над простым текстом
Left Source Tixt| Destination Window^ Right Source T«djLeft Source Tixt| Destination Window^ Right Source T«djДалее следует простая программа типа drag-and-drop, которая демонстрирует фундаментальные разделы алгоритма. Окно, которое она отображает, показано на рис. 16.1. Эта программа использует две кнопки с каждой стороны как источники для перетаскивания и кнопку в центре как пункт назначения. Текст ^упик ю. ■.
Left Source Tixt| Destination Window^ Right Source T«dj
Left Source Tixt| Destination Window^ Right Source T«dj
Операция drag-and-drop с кнопки на на кнопках с обеих сторон можно переме- г п ь г _кнопку 1
щать, и, если бросить его на кнопке в центре,,
копируется метка кнопки..
ПРИМЕЧАНИЕ
Эта программа — только скелет. У нее нет никаких типов данных, которые обычно требуются. Она демонстрирует лишь минимально необходимые вещи.
/♦♦ simplednd.c **7
#include <gnome.h>
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
gint eventDelete(GtkWidget *widget, GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget, GdkEvent ♦event,gpointer data);
void sendCallback(GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection,guint info,guint time);
void receiveCallback(GtkWidget *widget,4
. GdkDragContext *context, gint x,gint y,GtkSelectionData ♦selection, guint info,guint time);
void packSendingButton(GtkWidget *box,gchar *text);
void packReceivingButton(GtkWidget *box,gchar *tdxt);
int main(int argc,char *argv[]) { GtkWidget *app; GtkWidget *box;
gnome_init("simplednd","1.0",argc,argv);
app = gnome_app_new( "simplednd", "Simple DND"); gtk_signal_connect (GTK_OBJECT(app), "delete_event", GTK_SIGNAL_FUNC(eventDelete),NULL);
gtk_signal_connect (GTK_OBJECT(app), "destroy", GTK_SIGNAL_FUNC(eventDestroy), NULL);
box = gtk_hbox_new(TRUE,0);
gnome_app_set_contents(GNOME_APP(app),box);
packSendingButton(box,"Left Source Text"); packReceivingButton(box,"Destination Window"); packSendingButton(box,"Right Source Text");
gtkcontainersetborderwidth(GTKCONTAINER(app),25); gtk_widget_show_all(app);
gtk_main();
exit(0);
}.
void packSendingButton(GtkWidget *box,gchar *text) { GtkWidget *button; static GtkTargetEntry target = { "text/plain",0,0 };
button = gtk_button_new_with_label(text);
gtkboxpackstart(GTKBOX(box),button,TRUE,FALSE,0);
gtksignalconnect(GTK_OBJECT(button),"dragdataget", GTK_SIGNAL_FUNC(sendCallback),NULL);
gtkdrag_source_set(button,GDKBUTTON1MASK,&target, 1,GDKACTIONCOPY);
}-
void packReceivingButton(GtkWidget *box,gchar *text) { GtkWidget *button; static GtkTargetEntry target = { "text/plain",0,0 };
6060button = gtk_button_new_with_label(text);
60
60
61gtkboxpack start(GTKBOX(box),button,TRUE,FALSE, 0);
62~
63gtk_signal_connect(GTK_OBJECT(button),
64"dragdatareceived",
65GTKSIGNALFUNC(receiveCallback),NULL);
66gtkdrag^destset(button,„
GTKDESTDEFAULTMOTION|
GTK DESTDEFAULTHIGHLIGHT |
GTK DESTDEFAULTDROP,
&target,l,
71GDK ACTION COPY);
72 }
73 void sendCallback(GtkWidget *widget,
74GdkDragContext ♦context,-
75GtkSelectionData *selection,guint info,guint time)
76 {
gchar *ascii;
GtkWidget *label;
79
label = GTK_BUTTON(widget)->chiId;
gtklabelget(GTK_LABEL(label),&ascii);•
2gtkselectiondataset(selection,selection->target,
8,ascii,strlen(ascii));
}
void receiveCallback(GtkWidget *widget, .
GdkDragContext *context,
gint x,gint y,GtkSelectionData *selection,
guint info,guint time)
X .
90GtkWidget *label;
91-
92 ‘ label = GTKBUTTON(widget)->chiId;
93gtklabelsettext(GTK_LABEL(label),selection->data);
94 }
95 gint eventDelete(GtkWidget ^widget,1
96GdkEvent *event,gpointer data) {
97 return(FALSE);
98 }
99 gint eventDestroy(GtkWidget *widget,
100GdkEvent *event,gpointer data) {
101gtk_main_quit();.
102return(0);
103 }
В строках с 23 по 31 инициализируется приложение, создается горизонтальный ящик и вставляется в окно приложения. Вызовы функций в строках с 33 по 35 создают кнопки и упаковывают их в ящик. Две из кнопок могут выступать как источники, а одна — как пункт назначения для перетаскиваемого ASCII-текста.
• Функция packSendingButton() в строке 42 создает кнопку, устанавливает обратный вызов, необходимый для того, чтобы она была источником для перетаскивания, и упаковывает кнопку в ящик. Вызов gtk_signal_connect() в строке 50 определяет, что функция обратного вызова sendCallback( ) должна выполняться всякий раз, когда операция перетаскивания начинается внутри кнопки. Обращение к gtk_drag_source_set () в строке 52 определяет информацию по операции перетаскивания: тип данных, используемая кнопка мыши и какое действие должно произойти, чтобы завершить операцию drag-and-drop.
Функция packReceivingButton() в строке 55 создает кнопку, устанавливает обратный вызов, необходимый для становления места предназначения, и упаковывает кнопку в ящик. Обращение к gtk_signal_connect() в строке 63 определяет, что функция обратного Вызова выполняется всякий раз, когда операция drop (бросание) происходит внутри окна. Вызов gtk_drag_dest_set() в строке 66 определяет действие для выполнения, когда эта кнопка обнаруживает операцию drag (перетаскивание).
В строке 73 вызывается функция sendCallback() для создания данных, которые будут перемещены из источника перетаскивания. В строках 80 и 81 из метки кнопки извлекается текст и вызов gtk_selection_data_set() вставляет данные в структуру GtkSelectionData. Эта структура посылается принимающему виджету.
Функция receiveCallback() из строки 85 выполняется всякий раз, когда операция бросания происходит в пределах принимающей кнопки. Структура GtkSelectionData содержит указатель на строку формата ASCII, которая становится новой меткой.
Обратные вызовы выполняются только тогда, когда данные передаются фактически. Если, например, вы используете мышь, чтобы начать операцию перетаскивания, но данные сбрасываются в окно, которое не может принять их, никакие функции обратного вызова не вызываются. То есть функция обратного вызова отправителя выполняется только тогда, когда выбрано принимающее окно. До операции drag-and-drop источник вызывает функцию gtk_drag_source_set (), а адресат вызывает gtk_drag_dest_set(), и параметры настройки, установленные этими вызовами, используются для определения, допустимо ли перетаскивание. Если операция drag-and-drop допустима, выполняется обратный вызов источника, а затем обратный вызов места назначения. Таким образом, функция обратного вызова отправителя не должна ’’беспокоиться” относительно того, получил ли адресат данные — это особенно важно в операции GTK_ACTION_MOVE, в которой данные удаляются из источника.
Графические данные, перемещаемые между приложениями
Операция drag-and-drop может использоваться с разными типами данных. Спецификация MIME {Multipurpose Internet Mail Extensions — многоцелевые расширения электронной почты в сети Internet) определяет тип данных. Первоначально изобретенное как метод для идентификации и кодировки вложений электронной почты, MIME-кодирование нашло много других применений. Каждый тип данных определяется двумя именами: категория и специфический тип данных в пределах категории. Далее следуют примеры наименований данных типа MIME:
text/plain ' " text/html
image/jpeg
video/mpeg
Чтобы увидеть список типов MIME, поддерживаемых в Linux, выберите Mime Types в окне центра управления (Control Center) GNOME. Первый столбец содержит тип MIME, состоящий из двух слов, а второй столбец — обычный суффикс файла (также называемый расширение файла), который содержит этот тип данных. Вы можете использовать любой из этих типов MIME в операции drag-and-drop, если посылающее и принимающее приложения понимают тот же самый тип. А если пожелаете, то можете выдумать ваш соб-
ственный тип, который следует использовать только среди ваших собственных приложений.■
Вы можете перетащить из одного места два и более типов MIME, получатель данных определяет фактически выбранный тип. Следующий пример демонстрирует источник операции перетаскивания как виджет цветного растрового изображения, но получатель может выбрать, принимать ли цветное растровое изображение или обычный текст. На рис. 16.2 показан вид окна, когда несколько кнопок с рисунком перемещены и брошены на канве и, по крайней мере, одна кнопка с текстом внизу окна (в отличие от картинки она показывает время операции бросания). Поскольку используются стандартные наименования типов MIME, вы можете перетаскивать эти элементы в любое приложение. Например, перетащите кнопку с логотипом из этого приложения на терминал GNOME, и вы получите дату в виде обычного текста: текущая дата и время.
/♦* typednd.c **/
Iinclude <gnome.h> 3
Iinclude "minilogo.xpm"
5
Idefine HEIGHT 300
Idefine WIDTH 200
8
Idefine TARGETTYPETEXT 80
Idefine TARGETTYPEJPIXMAP 81
11
typedef struct {
GtkWidget *app;
GnomeCanvasGroup «rootGroup;
} tdContext;
,
static GtkTargetEntry fromlmage[] = {
{ "text/plain", 0, TARGET_TYPE_TEXT },
{ "image/x-xpixmap", 0, TARGETTYPEPIXMAP }
};
static GtkTargetEntry toButton =
{ "text/plain", 0, TARGET_TYPE_TEXT };
static GtkTargetEntry toCanvas =
{ "image/x-xpixmap", 0, TARGETTYPEPIXMAP };
25
gint eventDelete(GtkWidget «widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent ♦event,gpointer data);
GtkWidget «makeLayout(tdContext *tdcontext);
void addimage(tdcontext *tdcontext,char **xpm,
gint x,gint y);
void sendCallback(GtkWidget *widget,
GdkDragContext ♦context,
GtkSelectionData *selection,guintinfo,guint
void receiveCallback(GtkWidget «widget,
Рисунок 16.2.Перемещенные и брошенные картинки и текстРисунок 16.2.Перемещенные и брошенные картинки и текстtime);time);GdkDragContext «context,
Рисунок 16.2.
Перемещенные и брошенные картинки и текст
Рисунок 16.2.
Перемещенные и брошенные картинки и текст
time);
time);
38393839gint x,gint у,GtkSelectionData *seiection, guint info,guint time,tdContext *tdcontext);
38
39
38
39
40
41 int main(int argc,char *argv[))
{
GtkWidget *layout;
tdContext *tdcontext = g_malloc0(sizeof(tdContext));
45
gnome_init(*typednd",* 1.0",argc,argv);
tdcontext->app = gnome_app_new("typednd","Type DND");
gtk_signal_connect(GTK_OBJECT(tdcontext->app),
"deleteevent",
GTK_SIGNAL_FUNC(eventDelete),NULL);
gtk_signal_connect(GTK_OBJECT(tdcontext->app),
"destroy",
GTK_SIGNAL_FUNC(eventDestroy), NULL);
gtk_widget_show_all(tdcontext->app);
55
56layout = makeLayout(tdcontext);
57gnome_app_set_contents(GNOME_APP(tdcontext->app),
58layout);
59
60 gtk_widget_show_all(tdcontext->app);
61gtk_main();
62exit(0);
63 }
64 GtkWidget *makeLayout(tdcontext *tdcontext)
65 {
GtkWidget*box;
GtkWidget*canvas;
GtkWidget*button;
69
box = gtk_vbox_new(FALSE,0);
gtk_widget_show(box);
72
73canvas = gnome_canvas_new();
74gtkwidgetsetusize(canvas,WIDTH,HEIGHT);
75gnome_canvas_set_scroll_region(GNOME CANVAS(canvas),
760.0,0.0,WIDTH,HEIGHT);
77tdcontext->rootGroup =
798081828384858687887980818283848586878878gnome_canvas^root(GNOME_CANVAS(canvas));
79
80
81
82
83
84
85
86
87
88
79
80
81
82
83
84
85
86
87
88
gtk_signal_connect(GTK_OBJECT(canvas),
"drag_data_received",
GTKSIGNALFUNC(receiveCallback),tdcontext);
gtk_drag_dest_set(canvas,
GTK_DEST_DEFAULT_MOTION | GTKDESTDEFAULTHIGHLIGHT | GTKDESTDEFAULTDROP, &toCanvas,1, GDKACTIONCOPY);
89
90gtkboxpackstart(GTKBOX(box),canvas,TRUE,FALSE,0);
91
92addlmage(tdcontext,minilogo,WIDTH/2,HEIGHT/2);
93
94button = gtk_button_new_with_label("Text Target");
9 5gtk_signal_connect(GTK_OBJECT(button),
96
"dragdatareceived",
97
GTK_SIGNAL_FUNC(receiveCallback),tdcontext);
98
gtk_dragdestset(button,
99
GTK DEST—DEFAULT—MOTION |
100
GTK~DEST_DEFAULT highlight 1
101
GTK_DEST—DEFAULT—DROP,
102
6toButton,l,
103
GDK—ACTION—COPY);
104
gtkboX-pack-Start(GTK—BOX(box),button,TRUE,FALSE, 0);
105
106
return(box);
107 }
108 void addimage(tdContext *tdcontext,char **xpm,
109
gint x,gint y)
110 {
111
int width;
112
int height;
113
GtkStyle ♦style;
114
GdkBitmap *mask;
115
GdkPixmap *pixmap;
116
GtkWidget *button;
117
GtkWidget *pixmapWidget;,
118
GnomeCanvasItern *item;
119
120
style = gtk-Widget-get-Style(
121
GTKWIDGET(tdcontext->app));
122
pixmap * gdk-pixmap-Create-froni-Xpiii-d(
123
GTK-WIDGET(tdcontext->app)->window,
124
&mask,&style->bg[GTK—STATE—NORMAL],xpm);
125
pixmapWidget * gtk_pixmap_new(pixmap,mask);
126
button • gtk-button-new();
127
gtk-Container_add(GTK—CONTAINER(button),pixmapWidget)
128‘
129
sscanf(xpm[0),"%d %dn,&width,&height);
130
item = gnomecanvasitemnew(tdcontext~>rootGroup,
131
gnome-CanvaS-Widget-get-type(),
132
"widget",button,
133
"x",(double)x,
134
"y",(double)y,
135
"width",(double)width + 10,
136
"height*,(double)height 4- 10,
137
■anchor",GTK—ANCHOR—CENTER,
138
NULL);
139
gtk-Signal-Connect(GTK—OBJECT(button),"drag-data get"
140
GTK—SIGNAL—FUNC(sendCallback),NULL);*
141
gtk-drag-Bource-Set(GTK-WIDGET(button),
142
GDKBUTTON1MASK,
143
fromlmage,2,
144
GDKACTIONCOPY);
145
gtk-Vidget_show_all(button);
146 }
147 void sendCallback(GtkWidget *widget,
148
GdkDragContext ♦context,
149
GtkSelectionData ♦selection,guint targetType,
150
guint eventTime)
151 {
152
char str[80);
153
time t now;
154
155switch(targetType) {
156case TARGETTYFETEXT:
157time(&now);
158strcpy(str,ctime(6now));
159str[24] = '\0';
160gtk_selection_data_set(selection,.
161" selection->target,8,
162(guchar *)str,strlen(str));•
163break;
164 case TARGET_TYPE_PIXMAP:-
165gtk_selection_data_set(selection,
166selection->target,8,•
167(guchar *)minilogo,sizeof(minilogo));
168break;,
169default:
170break;
171}<
172 }
173 void receiveCallback(GtkWidget *widget,
174GdkDragContext ♦context,
175gint x,gint у,GtkSelectionData *selection,
176guint targetType,guint time,tdContext *tdcontext)
177 {■
GtkWidget *label;
-
switch(targetType) {
dase TARGETTYPETEXT:
label « GTKBUTTON(widget)->child;
gtk_label_set_text(GTK_LABEL(label),
selection->data);
break;
.case TARGETTYPEPIXMAP:
addimage(tdcontext,(gchar **)selection->data,x,y);
break;
default:
break;
}
}
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data) {
return(FALSE);
}'
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data) {
gtk_main_quit();
200return(0);
201 }'
Функция main() программы начинается в строке 41. Обращение к makeLayout() в строке 56 создает экран дисплея и присоединяет функции обратного вызова. Вызов gnome_app_set_contents () в строке 57 назначает новое размещение как главное окно приложения.
Функция makeLayout (), начинающаяся со строки 64, создает все виджеты и устанавливает обратные вызовы операций drag-and-drop. В строках 70 и 71 создается вертикальный ящик для поддержки двух частей окна: канва наверху и кнопка внизу. В строках с 73 по 76 создается GnomeCailvas, устанавливается его размер и его зона прокрутки
таким образом, чтобы он всегда был отображен. Когда элементы добавляются к канве, они сами фактически добавляют класс GnomeCanvasGroup уже внутри канвы, так что в строках 77 и 78 восстанавливается значение по умолчанию. Адрес GnomeCanvasGroup сохранен в контекстной структуре, определенной в строке 12, которая передается обратным вызовам в качестве данных.
Вызов gtk_signal_connect() в строке 80 устанавливает канву как виджет, который может принимать брошенные объекты. Всякий раз, когда внутри канвы с помощью мыши реализуется операция перетаскивания из приложения (этого или другого) и MIME- тип отправителя соответствует MIME-типу получателя, функция обратного вызова receiveCallback() вызывается с данными по операции перетаскивания. Если MIME- типы не согласуются, функция не вызывается.
Обращение к функции gtk_drag_dest_set() в строке 83 определяет принимаемый MIME-тип и некоторые другие характеристики канвы как адресата для сбрасывания объекта. Первый аргумент, канва, является виджетом, который принимает сбрасываемый объект. Второй аргумент, GtkDestDefault, является набором флагов, обозначающих действие, которое будет выполнено. Установка GTK_DEST_DEFAULT_MOTION влечет за собой посылку к приложению сигналов "dragjmotion”, так что ваш виджет может изменять свой вид или выполнять некоторое другое действие в течение операции перетаскивания. Установка GTK_DEST_DEFAULT__HIGHLIGHT подсвечивает виджет. Флаг GTK__DEST_DEFAULT_DROP влечет за собой посылку вашему приложению сигналов ”drag_drop". Чтобы определить сразу все три установки, просто укажите GTK_DEST_DEFAULT__ALL. Следующие два аргумента задают типы MIME в виде одной или нескольких структур GtkTargetEntry, которые этот виджет способен принимать. Канва принимает только один тип MIME; ом определен с помощью toCanvas в строке 23. Один обратный вызов может принять более чем один тип MIME, перечисляя их в массиве. Число после адресного указателя GtkTargetEntry — это количество членов в массиве. Последний аргумент — GdkActionType, определяющий действие, которое будет выполнено. В этом примере мы хотим копировать данные.
Обращение к addimage () в строке 92 использует информацию цветного растрового изображения для создания кнопки. Данные в формате ХРМ для растрового изображения названы minilogo и находятся в файле, включенном в строке 4. Этот вызов передает контекстную структуру, которая теперь содержит всю информацию, необходимую для добавления цветного растрового изображения к канве, данные в формате ХРМ и координаты центра канвы. ,
Код в строках с 94 по 104 создает кнопку, определяет ее как цель для ’’бросания" и упаковывает в ящик для отображения. Обращение к gtk_signal_connect () в стро-? ке 95 такое же, что и сделанное ранее для канвы: они даже совместно используют ту же самую функцию обратного вызова receiveCallback(). Обращение к- gtk_drag_dest_set() почти такое же, как и используемое для канвы, единственное< различие, что определен другой тип MIME. Тип обычного текста, определенный как toButton в строке 21, используется, чтобы разрешить кнопке принимать простой текст формата ASCII.
В строке 108 функция addimage () принимает данные в формате ХРМ, используя их для создания кнопки с цветным растровым изображением, размещает все это на канве в указанном месте и устанавливает кнопку как источник для операции drag-and-drop. Используя данные в формате ХРМ и стиль окна приложения GNOME, в строках
со 120 по 127 создается кнопка. Она добавляется к канве путем вызова функции gnome_canvas_item_new() в строке 130* Высота и ширина кнопки, полученные от данных в формате ХРМ в строке 129, используются для установки размера кнопки, причем она слегка больше, чем цветное растровое изображение, которое она содержит.
Обращение к gtk_signal_connect( ) в строке 139 определяет функцию sendCallback() как такую, которая будет вызываться всякий раз, когда операция перетаскивания начинается внутри кнопки. Вызов gtk_drag_source_set() в строке 141 определяет условия и действия операции перетаскивания. Первый аргумент — виджет, который должен быть источником перетаскивания. Второй — набор флагов, определяющих, какая кнопка мыши используется для перетаскивания: в этом примере используется GTK_BUTTON1_MASK, но это также может быть GTK_BUTTON2__MASK и GTK_BUTTON3_MASK или любая комбинация этих трех. Существует возможность исполь- зоватьразличные кнопки для слегка отличающихся действий. Например, используйте левую кнопку для создания копии и среднюю кнопку для перемещения объекта (удаления его из исходного места). -
Массив f romlmage, определенный в строке 17 и используемый как аргумент в строке 143, содержит два типа MIME, которые могут использоваться как типы исходных данных при перемещении объекта. Получатель выбирает фактически используемый тип. Когда в процессе перетаскивания выполняется ’’бросание”, первое, что происходит, — сравнение выходных MIME-типов с М1МЕ-1ипами получателя. Если они в общем совпадают, вызывается функция обратного вызова источника для упаковки и отправки данных. Затем вызывается функция обратного вызова адресата вместе данными. Если MIME-тип не совпадает, никакая функция не вызывается. Преимущество состоит в том, что всякий раз, когда выполняется один из этих обратных вызовов, вы знаете, что операция drag-and-drop подтверждена и должна завершиться успешно.
Функция sendCallback() в строке 147 вызывается всякий раз, когда мышь завершает определение связи, включая тип MIME, между виджетами источника и адресата. Оператор switch в строке 155 определяет, какой из типов MIME выбран. Эти значения — произвольные константы только для локального использования; в этом примере они определены в строках 9 и 10 и используются в массивах GtkTargetEntry в строках с 17 по 24. Фактические значения могут изменяться от одной программы до другой, потому что они — строки типа MIME, которые используются для сравнений внутри процесса.
В этом примере должен быть послан один из двух форматов данных. Оператор case в строке 156 указывает, что существует пункт приема, способный получать обычный ASCII-текст. Как образец текста в строках с 157 по 159 создается строка, содержащая текущую дату и время (будьте осторожны, завершая строку символом newline). Вызов gtk_selection_data_set () в строке 160 сохраняет данные в структуре GtkSelectionData, которая прилагается как аргумент. Содержимое этой структуры посылается в место опускания (бросания). Последние два аргумента — указатель на данные и полный размер отправляемых данных. Тип данных уже выбран. В строке 164 выполняется оператор case, если получатель ожидает данные цветного растрового изображения в формате ХРМ. Обращение к gtk_selection_data_set () в строке 165 — это все, что необходимо для вставки адреса и размера данных в формате ХРМ в структуру с целью задублировать их и отправить получателю.
Функция receiveCallback() в строке 173 вызывается всякий раз, когда выполнена операция drop (бросание). Первый аргумент — виджет, который принимает ’’брошен-
ные” данные. Всякий раз, когда вызывается эта функция, обратный вызов отправителя уже выполнен, так что данные размещаются в структуре GtkSelectionData. Оператор switch в строке 180 определяет, какой тип MIME получен. В строке 181 оператор case выполняется для обычного типа текста, предполагается, что виджет будет кнопкой и текст включается в нее как новая метка. Оператор case в строке 186 выполняется всякий раз, когда данные — цветное растровое изображение. Обращение к addimage () с координатами бросания х и у добавляет новую кнопку на канву.
Вырезать и вставить
J File £dlt _ГJ File £dlt _ГnSskTasmSTec^^ entered by positioning the cursor and typing. Also, a section of text can be and then either cut or copied to the clipboard. The clipboard text can then be restored to the cursor position or to overwrite me highlighted section.nSskTasmSTec^^ entered by positioning the cursor and typing. Also, a section of text can be and then either cut or copied to the clipboard. The clipboard text can then be restored to the cursor position or to overwrite me highlighted section.Рисунок 16.3.Доступное для редактирования текстовое окно, которое позволяет вамРисунок 16.3.Доступное для редактирования текстовое окно, которое позволяет вамВ следующей программе отображается текстовое окно, дающее вам возможность редактировать текст, который также может быть скопирован в глобальный clipboard (буфер обмена) и сделан доступным для любого приложения. Дополнительно, текст может быть считан из буфера обмена и вставлен в редактируемый текст. С помощью мыши определяется порция текста, записываемого в буфер обмена. Как показано на рис. 16.3, выделенная порция записывается в буфер обмена. Операция cut (вырезать) или сору (копировать) выполняет запись в буфер обмена в то время, как операция paste (вставить) читает и вставляет предварительно сохраненные в буфере обмена данные.
J File £dlt _Г
J File £dlt _Г
nSskTasmSTec^^ entered by positioning the cursor and typing. Also, a section of text can be and then either cut or copied to the clipboard. The clipboard text can then be restored to the cursor position or to overwrite me highlighted section.
nSskTasmSTec^^ entered by positioning the cursor and typing. Also, a section of text can be and then either cut or copied to the clipboard. The clipboard text can then be restored to the cursor position or to overwrite me highlighted section.
Рисунок 16.3.
Доступное для редактирования текстовое окно, которое позволяет вам
Рисунок 16.3.
Доступное для редактирования текстовое окно, которое позволяет вам
/♦♦ cutnpaste.c ♦*/вырезать и вставить
Iinclude <gnome.h> 3
static void fileExit(GtkObject *,gpointer);
static void editCut(GtkObject *,gpointer);
static void editPaste(GtkObject *,gpointer);
static void editCopy(GtkObject *,gpointer); 8
static GtkWidget *text;
10
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data); *.
gint eventDestroy(GtkWidget *widget,
GdkEvent *evbnt,gpointer data);‘
.
GnomeUIInfo fileMenu[] ■ {’
{ GNOMEAPPJJI_ITEM,"E_xit",
"Close the window and cease",
fileExit,NULL,NULL,
.GNOME_APP_PIXMAP_NONE,•
21*NULL,0,0,NULL },
22
GNOMEUIINFO END‘
};'
25
GnomeUIInfo editMenu[] • {
{ GNOME_APP_UI_ITEM,"_Cut",
"Delete and copy selection to clipboard",.
2 9editCut,NULL,NULL,
30GNONE_APP_PIXNAP_NONE,
31HULL,0,0,HULL },'
32{ GNONE_APP_UI_ITEN,"Cop_y",
33"Copy selection to clipboard",
34editCopy,NULL,NULL,
35 "GNOMEAPPPIXMAPNONE,-
36NULL,0,0,NULL },
37{ GNONE_APP_UI_ITEN,"_Paste",
38 "Paste selection fron clipboard",
39editPaste,NULL,NULL,
40GNONE_APP_PIXMAP_NONB,
41NULL,0,0,NULL },
42GNONEUIINFO END
43 }?■
44
45 GnoneUIInfo nainNenu[] " { 46■GNONEUIINFO SUBTREE(“_File",fileMenu),
47GNOMEUIINFO~SUBTREE("_Edit".editMenu),
48GNONEUIINFO END
49 }}
50
51 int main(int argc,char *argv[])
52 {
53GtkWidget *app;
54.
55gnome^init("cutnpaste","1.0",argc,argv);
56app 8 gnome_app_new("cutnpaste",
57"Cut, Copy, and Paste");
58gtk_signal_connect (GTK_OBJECT(app), "delete event",
59GTK_SIGNAL_FUNC(eventDelete),NULL);-
60gtk_signal_connect(GTK__OB JECT(app),"destroy",
61GTK SIGNAL_FUNC(eventDestroy),NULL);
62
6 3gnomeappcreatemenus (GNOMEAPP (app), mainMenu);
64.
65 text 8 gtk_text_new(NULL,NULL);*
66gtk_widget_set_usize(text,300,200);
67gtkjtextseteditable(GTKTEXT(text),TRUE);
68gnomeappsetcontents(GNOMEAPP(app),text);
69 70gtk_widget_show_all(app);
71 gtk_main();,,
72exit(0);■
73 }'
74 static void fileExit(GtkObject *object,gpointer data) {
gtk_main_quit();
>
static void editCut(GtkObject *object,gpointer data) {
gtk_editable_cut_clipboard(GTK_EDITABLE(text));
}
static void editCopy(GtkObject *object,gpointer data) {
gtkeditablecopyclipboard(GTKEDITABLE(text));
}
static void editPaste(GtkObject ,*object,gpointer data) {
gtk_editable_paste_clipboard(GTK_EDITABLE(text));
}.
gint eventDelete(GtkWidget *widget, 87GdkEvent *event,gpointer data) {
88return(FALSE);
89 }
90 gint eventDestroy(GtkWidget *widgetf
91GdkEvent *event,gpointer data) {
92gtk_main_quit();
93return(O);.
94 }
Операции вырезать, копировать и вставить — части каждого виджета, у которого в родословной есть GtkEditable. Особенно важно, что при этом включаются GtkEntry (возможность ввести одиночную строку текста) и GtkText (возможность ввести несколько строк, виджет редактирования текста). В этом примере используется виджет GtkText. Вы можете применять его для вырезания и вставки в пределах текстового окна или можете запустить много его версий и вырезать и вставлять среди них всех. Вы можете даже вырезать или скопировать текст Из окна редактирования и вставить его в окно Другого приложения, которое принимает текст, такого, как окно текстового редактора или терминала GNOME.
В строке 63 вызывается gnome^app_create_menus () для создания строки меню сверху поперек главного окна. Меню определены в массивах в строках с 16 по 48 и состоят только из двух основных заголовков. В меню File имеется только пункт Exit, а в меню Edit содержатся Cut, Сору и Paste. У каждого из этих четырех пунктов есть своя собственная функция обратного вызова.
Текстовый виджет создается и конфигурируется в строках с 65 по 68. Обращение к gtk_text_new() в строке 65 передает NULL для горизонтальных и вертикальных аргументов объекта GtkAd justment, поскольку в этом примере не используются полосы прокрутки. Обращение в строке 67 к gtk_text_set_editable() определяет, что текст должен быть доступен с клавиатуры и мыши. Объект GtkText, недоступный для редактирования, — это текстовое окно только для отображения.
Функции обратного вызова в строках с 77 до 85 взаимодействуют со всеми операциями вырезания и вставки. Виджет GtkEdit принимает ответственность за реакцию на мышь, с помощью которой выбирается текст для вырезания или копирования. Затем виджет выделяет текст, извлекает его из подсвеченной области, записывает извлеченный текст в буфер обмена, считывает текст из буфера обмена и вставляет его в текстовое окно. Обращение к функции gtk_editable_cut_clipboard( ) записывает выбранный текст в буфер обмена и удаляет его из текстового окна. Обращение к gtk_editable_copy_clipboard() делает то же самое, но не удаляет текст из окна. Вызов gtk_editable__pas te_cl ipboard () считывает текст из буфера обмена и вставляет его в текущее местоположение курсора.-
Выводы.
Данные могут быть перемещены из одного приложения в другое при помощи мыши. Графические объекты можно перетаскивать из одного положения в другое, а текст может быть скопирован в общедоступный буфер обмена для включения в другое текстовое окно или в другую позицию в том же самом текстовом окне. В этой главе были исследованы следующие методы:
^ Вы можете использовать операцию drag-and-drop для перемещения любого типа данных любого размера, но отправитель и получатель должны согласовать типы данных. Это выполняется путем использования наименований типов данных MIME.
S Операция drag-and-drop предварительно уточняет соответствие между посылающими и принимающими виджетами, сравнивая их список известных MIME-типов.
© Операция drag-and-drop весьма проста, но чем большее количество типов данных и опций добавляется, тем больше она усложняется.
& Любой доступный для редактирования виджет — GtkText или GtkEntry — может использоваться для вырезания и вставки текста, так как внутри класса GtkEditable включена полная процедура.
Следующая глава посвящена очень своеобразному окну верхнего уровня, которое является контейнером виджетов. В ней все о MKI (Multiple Kocument Interface — интерфейс для работы с несколькими документами), который не только действует как контейнер дочерних виджетов, но также разрешает пользователю выбирать среди них и позволяет каждому из дочерних виджетов изменять меню и панели инструментов родительского окна MKI. .
412
главаИнтерфейс Для работы
4 чс несколькими
■ /документами (MDI)
В этой главе
# Создание и отображение простого окна MKI
! Как заставить окно MKI отображать его дочерние окна в различных режимах ^ Изменение опций меню родительского окна MKI путем выбора дочернего окна ?v Использование панели инструментов с окном MKI
Интерфейс для работы с несколькими документами (MKI — Multiple Kocument Interface) — это специальный оконный объект, у которого есть возможность отобразить одно, два или больше дочерних окон. Он может показывать их по одному, как будто они были помещены в стек один за другим (вернее, один поверх другого). Он также может добавлять клавиши переключения сбоку этого стека, чтобы позволить мыши переключаться от одного дочернего окна к другому. Наконец, окно MKI может разделить себя на множественные окна верхнего уровня и отображать каждое из дочерних окон в его собственном окне верхнего уровня.
Структура и управление отображением (экраном) MKI отличаются от обычных окон потому, что окно MKI — не виджет. Объект MKI действует как посредник между одним или большим количеством окон верхнего уровня и одним или большим количеством дочерних окон. И потому, что число окон верхнего уровня может варьироваться, объект MKI также принимает на себя ответственность за создание и поддержку меню и панелей инструментов.'
Простое окно MDI
Следующая программа — простое приложение MDI, создающее и отображающее четыре окна и позволяющее мыши выбирать, какое из них является видимым в любое заданное время. Набор окон содержится в специальном контейнере, объекте MDI, который позволяет быть видимым только одному окну за раз. В этом примере каждый из документов — виджет метки. Окно для работы со многими документами показано на рис. 17.1.
ПРИМЕЧАНИЕ
Отображаемый объект, управляемый программным обеспечением MKI, может иметь несколько имен. Он может быть вызван как document (документ), который соответствует описанию существующей части интерфейса для работы с несколькими документами. Он также упоминается как view (вид), в котором имеются различные представления таких же
Рисунок 17.1.Окно MDI, отображаемое в режиме записной книжкиРисунок 17.1.Окно MDI, отображаемое в режиме записной книжкисамых или родственных (аналогичных) данных. Внутри он часто упоминается как child (ребенок) из-за его родственной связи с контейнером MKI. Вы также можете найти ссылки на раде (страница) из-за способа, каким программное обеспечение перебрасывается от одного на другой объект. Независимо от того, как вы вызываете его, он — просто виджет со своим отображением, управляемым программным обеспечением MKI.
Рисунок 17.1.
Окно MDI, отображаемое в режиме записной книжки
Рисунок 17.1.
Окно MDI, отображаемое в режиме записной книжки
/** simplemdi.c *♦/
#include <gnome.h>
3
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent ♦event,gpointer data);
'
static void addChiId(GtkObject *mdi,gchar *name);
static GtkWidget *setLabel(GnomeMDIChild *child,
GtkWidget *currentLabel,gpointer data);
static GtkWidget *createView(GnomeMDIChild *child,
gpointer data);
14
int mainfint argc,char *argv[])
{
17GtkObject *mdi;
18
19gnome_init("simplemdi","1.0",argc,argv);
20 mdi = gnome_mdi_new( "simplemdi", "Simple MDI"); .
21gtk signal_connect(mdi,"destroy",
22“ GTKSIGNALFUNC(eventDestroy),NULL);
23
24addChild(mdi,"First");
25addChild(mdi,"Second");
26addChiId(mdi,"Third");
27addChild(mdi,"Last");
28
29gnome_mdi_set_mode(GNOME_MDI(mdi),GNOME_MD ^NOTEBOOK);
30gnomemdiopentoplevel(GNOMEMDI(mdi));
31
32gtk_main();"
33exit(0);
34 }-
35 static void addChild(GtkObject *mdi,gchar *name)
36 {
GnomeMDIGenericChild *child;
38
child « gnome_mdi_generic_child_new(name);
gnome_mdi_add_chiId(GNOME_MDI(mdi),
GNOME_MDI_CHILD(child));
42
gnome_mdi_generic_child_set_view_creator(child,
createView,name);
gnome_mdi_generic_child set_label_func(child,setLabel,
NULL);~.
7gnome_mdi_add_view (GNOME_MDI (mdi),
48GNOME_MDI_CUlLD(Child));
49 }
50 static GtkWidget *createView(GnomeMDIChild *child, 51gpointer data)•
52 { 53 char str[80];
54
55' sprintf(str,"View of the\n%s widget",(gchar *)data);
56return(gtk_label_new(str));
57 }’
58 static GtkWidget *setLabel(GnomeMDIChild *child,
59GtkWidget *currentLabel,gpointer data)
60 {
61 if(currentLabel == NULL)
62return(gtk_label_new(child->name));
63
64gtk_label_set_text(GTK_LABEL(currentLabel),
.65child->name);
66teturn(currentLabel);
67 }
68 gint eventDestroy(GtkWidget *widget,
69GdkEvent *event,gpointer data) {
70gtk_main_quit();
71return(O);
72 }
В строке 19 при помощи вызова gnome_init() инициализируются GNOME и GTK+. Затем вместо того, чтобы создать окно приложения, обращение к gnome_mdi_new() в строке 20 создает объект GnomeMDI. Причем объект GnomeMDI — не виджет, а специальный тип контейнера, который способен содержать ряд дочерних виджетов (или документов, или видов) и позволяет им быть отображенными по одному. Когда объект GnomeMDI создан, у него нет нйчего для отображения, потому что он пустой. Прикладная программа должна вызвать функции для определения воспроизводимого содержимого и выполнить модификацию опций настройки.•
Обращение к gtk_signal_connect() в строке 21 влечет за собой обратный вызов eventDestroy (), предназначенный для немедленного закрытия приложения. Обратный вызов ”delete_event” (удалить событие) отсутствует так же, как в случае с другими окнами верхнего уровня GNOME и GTK+, потому что этот специфический сигнал не определен для GnomeMDI.
В стрдках с 24 по 27 добавляются виджеты документов к объекту отображения MDI. Вызов gnome_mdi_set_mode () в строке 29 устанавливает режим визуального отображения так, что клавиши переключения доступны слева, как показано на рис. 17.1. Вызов gnome_mdi_open_toplevel () в строке 30 создает окно верхнего уровня и использует его как контейнер для объекта GnomeMDI, отображающего виджеты документов.
Функция addChild(), начинающаяся со строки 35, создает новое окно документа и добавляет его к MDI для отображения в качестве дочернего. Каждый воспроизводимый объект — это объект GnomeMDIGenericChild, созданный при обращении к gnome_mdi_generic_child_new() в строке 39. Этот объект добавлен к объекту GnomeMDI вызовом gnome_mdi_add_child () в строке 40. Теперь потомок добавлен к GnomeMDI, но он невидим, пока не определен виджет, который его отображает. В строке 43 в обращении к gnome_mdi_generic_child_set_view_creator () указано, что функция createView( ) должна вызываться для возврата виджета, который является формой отображения объекта. В строке 45 в обращении к gnome_mdi_generic_child_set_label_func ( ) определено, что функция
setLabel () должна вызываться, чтобы создать метку для клавиш переключения на странице, содержащей вид объекта. Наконец, в строке 47 вызов gnome_mdi_add_view() создает видимую часть документа, вызывая функции, которые определены для создания изображения и метки.
Функция createView( ) в строке 50 создает виджет, который применяется, чтобы отобразить вид объекта. В этом примере используется строка имени, которая была передана как данные пользователя (в обращении ык gnome_mdi_generic_child_set_yiew_creator() в строке 43) для создания строки, содержащей название. Затем строка используется для создания и возврата GtkLabel как документа, который будет отображен.
Функция setLabel () в строке 58 вызывается для определения виджета, который служит в качестве метки на клавише, используемой для перебрасывания с помощью мыши от одной страницы к другой. Второй аргумент функции — виджет метки клавиши переключения (если существует), который был создан ранее. Всякий раз, когда окно MDI
Рисунок 17. 2.Доступ к клавишам, используя кнопки в виде ”стрелка вверх” и ”стрелка вниз”Рисунок 17. 2.Доступ к клавишам, используя кнопки в виде ”стрелка вверх” и ”стрелка вниз”впервые отображается в режиме записной книжки, эта функция вызывается для создания метки. Однако она может существовать даже с предыдущего раза, когда окно MDI показывалось в режиме записной книжки.
Рисунок 17. 2.
Доступ к клавишам, используя кнопки в виде ”стрелка вверх” и ”стрелка вниз”
Рисунок 17. 2.
Доступ к клавишам, используя кнопки в виде ”стрелка вверх” и ”стрелка вниз”
В режиме записной книжки всегда слева прилагаются клавиши с метками для переключения от одного представления (вида) к другому. Если имеется больше клавиш переключения, чем может быть отображено в окне, пара стрелок ’’вверх” и "вниз” вставляется внизу, так что пользователь может листать по клавишам вперед и назад. На рис. 17.2 показано окно, полученное в результате уменьшения размера окна из предшествующего примера.
Меню MDI и режимы отображения
Поскольку окно MDI отображается как собственное окно верхнего уровня, существуют некоторые специальные функции MD1, которые необходимы при управлении меню для окна. Все структуры меню и опции, описанные в главе 8, допустимы, но их структура и функционирование находятся под управлением функций MDI. В следующей программе создается строка меню, которая дает возможность пользователю изменять режим отображения MD1 и выполнять'переключения среди доступных изображений. Эта программа очень похожа на предыдущий пример кроме строки меню и добавленных для нее обратных вызовов.
/** menumdi.c **/
#include <gnome.h>
3
static GtkObject *mdi;
static GtkWidget *firstView;
static GtkWidget *secondView;
static GtkWidget *thirdView;
static GtkWidget *lastview;
9
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
.
static void addChild(gchar ‘name);
static GtkWidget *setLabel(GnomeMDIChild ‘child,
GtkWidget *currentLabel,gpointer data);
static GtkWidget *createView(GnomeMDIChild *child,
gpointer data);
20
static void fileExit(GtkObject ‘object,gpointer data);
static void modeNotebook(GtkObject ‘object,gpointer data);
static void modeToplevel(GtkObject ‘object,gpointer data);
static void modeModal(GtkObject ‘object,gpointer data);
static void modeDefault(GtkObject ‘object,gpointer data);
static void setFirstView(GtkObject ‘object,gpointer data);
static void setSecondView(GtkObject ‘object,gpointer data);
static void setThirdView(GtkObject ‘object,gpointer data);
static void setLastView(GtkObject ‘object,gpointer data); .
30
GnomeUIInfo fileMenu[] = {
GNOMEUIINFOSEPARATOR,
{ GNOME_APP_UI_ITEM,"E_xit",
"Close the window and cease",
fileExit,NULL,NULL,
GNOME_APP_PIXMAP_NONE,
NULL,0,0,NULL },
GNOMEUIINFOEND
};
40
GnomeUIInfo modeMenu[] = {
{ GNOMEAPPUIITEM,"Notebook",'
"Change to notebook display mode",
modeNotebook,NULL,NULL,
GNOMEAPPPIXMAPNONE,
NULL,0,0,NULL },
{GNOMEAPPUIITEM,"Toplevel",.
"Change to top-level display mode",
modeToplevel,NULL,NULL,
GNOMEAPPPIXMAPNONE,
NULL,0,0,NULL },
{GNOMEAPPUIITEM,"Modal",
"Change to modal displaymode"^
modeModal,NULL,NULL,
GNOME_APP_PIXMAP_NONE,
NULL,0,0,NULL },
{GNOMEAPPUIITEM,"Default",
"Change to the defaultdisplay mode",
modeDefault,NULL,NULL,
GNOMEAPPPIXMAPNONE,,
NULL,0,0,NULL },
2GNOMEUIINFO_END
};
64
GnomeUIInfo selectMenu[] = {
{ GNOME_APP_UI_ITEM,"First",
* "Switch to the first document",
setFirstView,NULL,NULL,.
GNOMEAPPPIXMAPNONE,
NULL,0,0,NULL },
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
{ GNOME_APP_UI_ITEM,"Second", "Switch to the second document", setSecondView,NULL,NULL, GNOMEAPPPIXMAPNONE, NULL,0,0,NULL },
{ GNOMEAPPUIITEM,"Third", "Switch to the third document", setThirdView,NULL,NULL, GNOME_APP_PIXMAP_NONE, NULL,0,0,NULL },
{ GNOME_APP_UI_IТЕМ,"Last", "Switch to the last document", setLastView,NULL,NULL, GNOME_APP_PIXMAP_NONE, NULL,0,0,NULL },
GNOMEUIINFO_END };
GnomeUIInfo mainMenu[] = {
GNOMEUIINFO_SUBTREE("File",fileMenu), GNOMEUIINFO_SUBTREE(" Mode",modeMenu), GNOMEUIINFO_SUBTREE("Select",selectMenu), GNOMEUIINFO_END
};
int main(int argc,char *argv[]) {
gnome_init("menumdi","1.0",argc,argv);
mdi = gnome_mdi_new("menumdi","Menu MDI");
gnome_mdi_set_menubar_template(GNOME_MDI (mdi), mainMenu);
gtksignalconnect(mdi,"destroy", GTK_SIGNAL_FUNC(eventDestroy),NULL);
addChild("First");
addChiId("Second");
addChild("Third");
addChild("Last");
gnomemdiopentoplevel(GNOMEMDI(mdi));
gtk_main();
exit(0);
}
static void addChild(gchar *name) {
GnomeMDIGenericChild *child;
child = gnome_mdi_generic_child_new(name); gnomemdiaddchild(GNOMEMDI(mdi),
GNOME_MDI_CHILD(child));
123124125126127128123124125126127128gnome_mdi_generic_child_set_view_creator(child, createView,name);
123
124
125
126
127
128
123
124
125
126
127
128
gnome_mdi_generic_child_set_label_f unc (child r setLabel NULL);
gnome_mdi_add_view(GNOME_MDI(mdi), GNOME_MDI_CHILD(child));
129 }
130 static GtkWidget *createView(GnomeMDIChild *child,
131gpointer data)
132 {
133gchar *name;
134char str(80];
135GtkWidget *view;
136
137name = (gchar *)data;
138sprintf(str,"View of the\n%s widget",name);
139view = gtk_label_new(str);
140gtk_widget_set_usize(view,250,100);
141if(!strcmp(name,"First"))
142firstView = view;
143else if(1strcmp(name,"Second"))
144secondView = view;
145else if(!strcmp(name,"Third"))
146thirdView= view;
147else
148lastview = view;
149return(view);•
150 }
151 static GtkWidget *setLabel(GnomeMDIChild *child,
152GtkWidget *currentLabel,gpointer data)
153 {
154 if(currentLabel == NULL)
155return(gtk_label_new(child->name));
156
157gtk_label_set_text(GTK_LABEL(currentLabel),
158child->name);
159return(currentLabel);
160 }
161 static void fileExit(GtkObject *object,gpointer data)
162 {
163 gtk_main_quit();
164 }
165 static void modeNotebook(GtkObject *object,gpointer data)
166 {
167gnomemdisetmode(GNOME_MDI(mdi),GNOME_MDI_NOTEBOOK);
168 }
169 static void modeToplevel(GtkObject *object,gpointer data)
170 {
171gnome_mdi_set_mode(GNOME_MDI(mdi),GNOME_MDI_TOPLEVEL);
172 }
173 static void modeModal(GtkObject *object,gpointer data)
174 {
175 gnome_mdi_set_mode(GNOME_MDI(mdi),GNOME_MDI_MODAL);
176 }
177 static void modeDefault(GtkObject *object,gpointer data)
178 {
179.gnome_mdi_set_mode(GNOME_MDI(mdi),
180GNOME_MDI_DEFAULT_MODE);
181 }
182 static void setFirstView(GtkObject *object,gpointer data)
183 {
184 gnome_mdi_set_active_view(GNOME_MDI(mdi),firstView);
185 }
186 static void setSecondView(GtkObject *object,gpointer data)
187 {
188gnome_mdi_set_active_view(GNOME_MDI(mdi), second View);
189 }
190 static void setThirdView(GtkObject *object,gpointer data)
191 {
192 gnome_mdi_set_active_view(GNOME_MDI(mdi),thirdView);
193 }
194 static void setLastView(GtkObject *object,gpointer data)
195 {
196 gnome_mdi_set_active_view(GNOME_MDI(mdi),lastview);
197 }
198 gint eventDestroy(GtkWidget *widget,
199GdkEvent *event,gpointer data) {
200gtk_main_quit();
201return(O);
202 }
Строки c 21 no 29 — прототипы функций обратного вызова для меню, а само меню объявлено в строках с 31 по 94. В главе 8 много подробной информации относительно размещения массивов меню. Когда программное обеспечение MD1 создает меню из массивов, перед тем как вызывается функция создания меню gnome_app_create_menus_with_data (), массивы копируются. Это означает, что определение меню в вашей программе не изменено.
Функция main() начинается вызовом gnome_init() в строке 98. Обращение к gnome_mdi_new() в строке 99 создает новый, но пустой объект GnomeMDI. Обращение к функции gnome_mdi_set_menubar_template() в строке 100 присоединяет меню к объекту GnomeMDI. Каждый из четырех вызовов функции addChild() в строках со 105 по 108 добавляет новую страницу документа к MD1. Наконец, в строке ПО при обращении к gnome_mdi_open_toplevel () открывается окно MDI.
Функция addChild (), начинающаяся в строке 115, добавляет один дочерний документ к окну MDI. Вызов gnome_mdi_generic_child_new() создает пустого потомка MDI, а вызов gnome_mdi_^add_child () в строке 120 включает его в качестве компонента списка дочерних объектов, который вы можете использовать для создания представлений (видов). В строках со 123 по 128 используется потомок для создания представления (вида) и добавления его к документам, которые отображаются в окне MDI.
Функции createView() в строке 130 и setLabel() в строке 151 являются функциями обратного вызова, которые, в свою очередь, зарегистрированы с вызовами MDI- функций в строках 123 и 125. Функция createView() вызывается для создания представления объекта. В строках со 127 по 140 создается метка и устанавливается по размеру текста названия, переданного как аргумент. Поскольку этой программе позже нужен доступ к каждому из представлений, адрес каждого из них сохраняется в глобальных переменных в строках со 141 по 148. В строке 149 возвращается созданное представление. Функция setLabel() в строке 151 создает метку, которая отображается на клавише переключения, когда окно MDI находится в режиме записной книжки.
В строке 165 функция обратного вызова modeNotebook () для меню обращается к gnome_mdi_set_mode (), которая изменяет отображение MDI в режим записной книжки. В этом режиме документы помещены в стек в окне лишь с одним видимым документом, но у каждого слева есть клавиша, так что можно использовать мышь для переключения между документами. Результирующее окно приведено на рис. 17.3. На рисунке также показано, что название текущего выбранного потомка появляется в заголовке окна MDI.
В строке 173 функция обратного вызова modeModal() для меню изменяет режим дисплея, как это показано на рис. 17.4. Документы помещены в стек один за другим, и с помощью мыши невозможно переключаться с одного документа на другой. Чтобы все-таки выполнить такое переключение, прикладная программа должна вызвать gnome_mdi_set_active_view(). Функция обратного вызова modeDefault() устанавливает экран дисплея MDI в заданный по умолчанию режим, в данном случае в модальный.
Рисунок 17.3.Строка меню с окном MDI в режиме записной книжкиРисунок 17.3.Строка меню с окном MDI в режиме записной книжкиРисунок 17.4.Строка меню окна MDI в модальном режимеРисунок 17.4.Строка меню окна MDI в модальном режиме
Рисунок 17.3.
Строка меню с окном MDI в режиме записной книжки
Рисунок 17.3.
Строка меню с окном MDI в режиме записной книжки
Рисунок 17.4.
Строка меню окна MDI в модальном режиме
Рисунок 17.4.
Строка меню окна MDI в модальном режиме
В строке 169 функция обратного вызова modeToplevel() изменяет экран дисплея таким образом, что позволяет одновременно размещать на нем более чем одну страницу. Каждому документу назначено его собственное окно верхнего уровня, и результат выглядит, как на рис. 17.5. Заметьте, что вся строка меню целиком дублируется для каждого окна: можно выбрать изменение режима на любом из меню и заставить экран дисплея свернуться назад в одно окно.
./О<хг./О<хгК Second - Menu MD I | £He —°de -e cК Second - Menu MD I | £He —°de -e ci*Ji*JView of the Last widgetView of the Last widgetJI First - Menu MDl" I File Mode SelectJI First - Menu MDl" I File Mode SelectView of theSecond widgetView of theSecond widgetenu MDI* Selectenu MDI* Select'—/О х'—/О хРисунок 17.5.Каждый документ MDI может иметь свое собственное окно верхнего уровня.Рисунок 17.5.Каждый документ MDI может иметь свое собственное окно верхнего уровня.
./О<хг
./О<хг
К Second - Menu MD I | £He —°de -e c
К Second - Menu MD I | £He —°de -e c
i*J
i*J
View of the Last widget
View of the Last widget
JI First - Menu MDl" I File Mode Select
JI First - Menu MDl" I File Mode Select
View of theSecond widget
View of theSecond widget
enu MDI
* Select
enu MDI
* Select
'—/О х
'—/О х
Рисунок 17.5.
Каждый документ MDI может иметь свое собственное окно верхнего уровня.
Рисунок 17.5.
Каждый документ MDI может иметь свое собственное окно верхнего уровня.
View of theThird widget
Окно MDI с панелью инструментов
В следующей программе демонстрируется метод создания панели инструментов для окна MD1. Процесс немного отличается от того, как была создана строка меню в предыдущем разделе. Панель инструментов создается в специальной функции обратного вызова, которая выполняется, когда создается родительское окно GnomeApp. У этой программы есть пара стандартных кнопок панели и набор радиокнопок, но панель инструментов MDI может содержать любой из компонентов, описанных в главе 8.
1
2 3
4
5 б
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
/** toolbarmdi.c **/
♦include <gnome.h>■
♦include "toolbarxpm.h"
static GtkObject *mdi;
gint eventDestroy(GtkWidget ‘widget, GdkEvent ‘event,gpointer data);
static void addChild(GtkObject *mdi,gchar ‘name);
static GtkWidget ‘setLabel(GnomeMDIChild *child, GtkWidget *currentLabel,gpointer data);
static GtkWidget *createView(GnomeMDIChild ‘child, gpointer data);
static void notebookcallback(GtkObject *object, gpointer data);
static void modalCallback(GtkObject ‘object, gpointer data);
static void toplevelCallback(GtkObject ‘object, gpointer data);
static void dummyCallback(GtkObject ‘object, gpointer data);
static void appCreated(GnomeMDI *mdi,GnomeApp *app, gpointer data);
GnomeUIInfo modeList[] = {
GNOMEUIINFO_RADIOITEM("Modal",
"Change to the Modal display mode", modalCallback,modalXPM), GNOMEUI INFO__RADIOITEM("Notebook",
"Change to the Notebook display mode", notebookcallback,notebookXPM), GNOMEUIINFO_RADIOITEM("Toplevel",
"Change to the Toplevel display mode",
•toplevelCallback,toplevelXPM),
GNOMEUIINFO_END
};
static GnomeUIInfo modeToolbar[] = {
{ GNOME_APP_UI_ITEM,"New", "Create a new file",dummyCallback,NULL,NULL, GNOME APP PIXMAP STOCK,GNOME STOCK PIXMAP NEW, '0,0,NULL },~
GNOMEUIINFO_SEPARATOR, GNOMEUIINFO_RADIOLIST(modeList), GNOMEUIINFO_SEPARATOR, { GNOMEAPPUIIТЕМ,"Save as",
"Save to a new file",dummycallback,NULL,NULL, GNOME_APP_PIXMAP_STOCK,GNOMESTOCKPIXMAPSAVEAS, 0,0,NULL },
GNOMEUIINFO_END };
56575657int {int {main(int argc,char *argv(l)main(int argc,char *argv(l)
56
57
56
57
int {
int {
main(int argc,char *argv(l)
main(int argc,char *argv(l)
58gnome_init(*toolbarmdi","1.0",argc,argv);
59mdi = gnome_mdi_new("toolbarmdi","Toolbar MDI");
gtk_signal_connect(mdi,"destroy",
GTK_SIGNAL_FUNC(eventDestroy),NULL);
gtk_signal_connect(mdi,"app_created",
GTK_SIGNAL_FUNC(appCreated),NULL);
64
addChild(mdi,"First");
addChild(mdi,"Second");
addChild(mdi,"Third");
addChild(mdi,"Last");
69
gnome_mdi_open_toplevel(GNOME_MDI(mdi));
71
gtk_main();
exit(0);
}
static void addChiId(GtkObject *mdi,gchar *name)
{
GnomeMDIGenericChild *child;
78
child = gnome_mdi_generic_child_new(name);
gnome_mdi_add_child(GNOME_MDI(mdi),
GNOME_MDI_CHILD(child));
82
gnome_mdi_generic_child_set viewcreator(child,
createView,name);
gnome_mdi_generic_child_set_label_func(child,setLabel,
NULL);
gnome_mdi_add_view(GNOME_MDI(mdi),
GNOME_MDI_CHILD(child));
}
static GtkWidget *createView(GnomeMDIChild *child,
gpointer data)
{
char str[80];
GtkWidget *label;
95
sprintf(str,"Viewof the\n%s widget",(gchar *)data);
label = gtk_label_new(str);
gtk_widget_set_usize(label,200,200);
return(label);
}
static GtkWidget *setLabel(GnomeMDIChild *child,
GtkWidget *currentLabel,gpointer data)
{
if(currentLabel == NULL)
return(gtk_label_new(child->name));
106
gtk_label_set_text(GTK_LABEL(currentLabel),
child->name);
return(currentLabel);
}
static void appCreated(GnomeMDI *mdi,GnomeApp *app,
gpointer data)
{
114gnome_app_create_toolbar(app,modeToolbar);
115 }
116 static void toplevelCallback(GtkObject *object,
117gpointer data)
118 {
119 GtkToggleButton *button = GTK_TOGGLE_BUTTON(object);
120 if(gtk_toggle_button_get_active(button))
121gnome_mdi_set_mode(GNOME_MDI(mdi),
122GNOME_MDI_TOPLEVEL);
123 }
124 static void modalCallback(GtkObject *object,
125gpointer data)
126 {
127 GtkToggleButton *button = GTK_TOGGLE_BUTTON(object);
128 if(gtk togglebutton getactive(button))
129gnome_mdi set_mode(GNOMEMDI(mdi),
130GNOMEMDIMODAL);
131 }
132 static void notebookcallback(GtkObject *object,
133gpointer data)
134 {
135GtkToggleButton *button = GTKTOGGLEBUTTON(object);
136if(gtk_toggle_button_get_active(button))
137gnome_mdi_set_mode(GNOME_MDI(mdi),
138GNOME_MDI_NOTEBOOK);
139 }
140 static void dummyCallback(GtkObject *object,gpointer data)
141 {
142 gnome_ok_dialog("The dummy callback.");
143 }
144 gint eventDestroy(GtkWidget *widget,
145GdkEvent *event,gpointer data) {
146gtk_main_quit();
147return(O);
148 }
Функция main(), начинающаяся с обращений к gnome_init () и gnomejmdi_new() в строках 58 и 59, инициализирует GNOME и создает объект GnomeMDI. Обращение к gtk_signal_connect( ) в строке 62 назначает функцию обратного вызова appCreated() сигналу под названием ”app_created”, который немедленно выполняется после создания окна GnomeApp. В строках с 65 по 68 к MDI добавляются четыре документа, а в строке 70 для их содержания создается окно верхнего уровня.
Строки с 75 по 109 — те же самые, как и в примере меню из предыдущего раздела. Функция addChild() создает дочерний документ и вставляет его в окно MDI, а функция createView() создает виджет, который действует как показ (вид) дочернего объекта. Функция setLabel() вызывается, чтобы создать метки кнопок переключения для каждого вида в режиме записной книжки MDI.
Функция обратного вызова appCreated() из строки 111 вызывается всякий раз, когда создается окно GnomeApp, так что панель инструментов может быть добавлена к нему. Меню создается таким же самым образом, как и для обычного окна приложения GNOME, описанного в главе 8. Обращение к gnome_app_create_toolbar () в строке 114 создает панель инструментов и прикрепляет ее к окну. Вид панели инструментов определен в массивах в строках с 28 по 54; для ее пиктограмм используются данные в формате ХРМ из файла toolbarxpm.h, включенного в строке 4. Панель инструментов и окно MDI показаны на рис. 17.6.
Рисунок 17.6.Окно MDI с панелью инструментовРисунок 17.6.Окно MDI с панелью инструментовбрана.брана.Функция dummyCallback() в строке 140 вызывается всякий раз, когда выбрана однаФункция dummyCallback() в строке 140 вызывается всякий раз, когда выбрана однаКаждая из функций обратного вызова — toplevelCallback(), modalCallback() и notebookcallback() — присоединена к радиокнопке панели инструментов. Это дает возможность переключаться на панели инструментов экрана дисплея между тремя различными режимами. В каждой из этих функций перед тем, как установить режим, проверяется, не является ли кнопка активной. Если кнопка не активна, это означает, что она скорее не выбрана, чем вы-
Рисунок 17.6.
Окно MDI с панелью инструментов
Рисунок 17.6.
Окно MDI с панелью инструментов
брана.
брана.
Функция dummyCallback() в строке 140 вызывается всякий раз, когда выбрана одна
Функция dummyCallback() в строке 140 вызывается всякий раз, когда выбрана одна
из кнопок панели.
Выводы
Преимущество экрана дисплея MDI состоит в том, что в маленькой области он может содержать множество окон. Это достигается путем расположения отображаемых виджетов в стеке один за другим (один поверх другого), а пользователи имеют доступ к тому из них, к которому пожелают. Эта глава охватила главные элементы MDI, а именно:
Окно MDI отображает свое дочернее окно в одном из трех режимов.
Модальный режим отображения дочерних окон предусматривает их расположение в стеке одно за другим (вернее, одно поверх другого). Можно переключаться от одного окна к другому, используя меню или панель инструментов или другую внутреннюю методику приложения.
Режим записной книжки — такой же, как и модальный, за исключением того, что слева от окна имеются клавиши, которые можно использовать для переключения с помощью мыши между представлениями (видами) окон.
В режиме верхнего уровня каждое из дочерних окон отображается в его собственном окне верхнего уровня.
О Окно верхнего уровня объекта MDI — это не обычное окно верхнего уровня GNOME, но у него есть возможности управления меню и панелями инструментов.
Следующая глава содержит примеры основного шага настройки вашего приложения: конструирование ваших собственных пользовательских виджетов. Есть ряд ситуаций, где это может быть выгодно, но особенно удобно, когда тот же самый интерфейс должен использоваться во множественных приложениях. Это также инкапсулирует части вашего приложения таким образом, что уменьшает трудности сопровождения.
главаСоздание вашего
18собственного виджета
В' этой главе
Исследование внутренней организации виджета в GNkME
Разработка и создание виджета, отображающего граф
> Создание заголовочного файла виджета, который может использоваться другими приложениями
© Модификация виджета, который уже используется
В этой главе рассматривается методика написания виджета. Может быть, искусство создания виджетов и представляет некоторые трудности, но надо учесть, что существует несколько путей их создания. Метод, приведенный в настоящей главе, должен вполне подходить для всех случаев создания виджетов в ваших приложениях.
Виджеты являются объектно-ориентированными, что обусловлено не самим языком С, а достигается за счет использования набора кодированных договоренностей и требования, чтобы все следовали этим договоренностям. В то время как объектно-ориентированные языки, как, например, C++ и Java, имеют встроенные средства, позволяющие упростить программирование объектов, сам код может быть организован в виде объектов в любом языке программирования. В настоящей главе приведено описание внутренних особенностей виджетов, что в то же время является и описанием метода объектно-ориентированного программирования на языке С.
Виджет-граф в виде полос
Виджет, описанный в этой главе, очень специфичен. Он обладает большинством основных структурных элементов, скажем, таких, как GtkButton или виджет GtkText. Однако он не учитывает выдаваемые сигналы, подсчитывая количество ссылок или устанавливая набор значений, который может быть задан по имени, состоящему из символов ASCII.
Этот виджет называется AgBargraph. Согласно договоренности об именах виджетов в GTK+ они начинаются с Gtk, а виджеты GNOME начинаются с Gnome. Виджет AgBargraph входит в состав гипотетической коллекции, известной, как виджеты Ад. Он отображает многоцветный полосатый граф с переменным количеством членов. AgBargraph реагирует на события мыши двумя способами: меняет цвет фона всякий раз при вхождении указателя мыши в его окно и отвечает на нажатие кнопок мыши, ото-
Рисунок 18.1.Виджет AgBargraph отображает наименование полосыРисунок 18.1.Виджет AgBargraph отображает наименование полосыбражая наименование выбранного полосатого графа. На рис. 18.1 приведен образец его вывода.
Рисунок 18.1.
Виджет AgBargraph отображает наименование полосы
Рисунок 18.1.
Виджет AgBargraph отображает наименование полосы
Виджет AgBargraph обладает следующими свойствами:
Он объектно-ориентирован и обладает специальными функциями, которые вызываются для создания виджета и в конце "его жизни" для удаления. В этом случае выделенные под виджет ресурсы системы автоматически возвращаются при удалении виджета. Доступ к значениям, контролируемым виджетом, осуществляется через вызовы функций
Как и все виджеты, AgBargraph как часть вашего приложения очень прост в использовании. Необходимо всего лишь создать виджет и присоединить его к родительскому окну, которое будет отображать этот виджет.
Ваше приложение может содержать любое количество экземпляров этого виджета. Каждый образец действует независимо, но использует один и тот же набор функций для конфигурирования и управления.
AgBargraph наследует все свойства GtkWidget, что позволяет выбирать события, которые могут быть просто получены путем их запрашивания. Поскольку GtkWidget сам заботится о внутренней структуре виджета AgBargraph, то большая часть программного кода имеет дело с установленными значениями и рисованием изображения на экране.
AgBargraph автоматически изменяет свои размеры до размеров области, предназначенной для его размещения. Он перерисовывает сам себя при выходе на передний план (экспозиция). Кроме того, виджет AgBargraph изменяет цвет своего фона при вхождении указателя мыши в область его окна. Щелчок на одной из полос графа приводит к выводу ее наименования.
В любое время, как до реализации виджета, так и во время его отображения, вы можете добавить в граф новые данные.
Использование виджета AgBargraph
Приведенная ниже программа создает и отображает виджет AgBargraph.
/** showbargraph.с **/
#include <gnome.h>
3
tinclude "agbargraph.h"
5
GtkWidget *makeBox();
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widgetr
GdkEvent *event,gpointer data);
11
int main(int argc,char *argv[])
{
GtkWidget *window;
GtkWidget *agbargraph;
•
gnome_init("AgBargraph","1.0",argс,argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_container_set_border_width(GTK_CONTAINER(window),
25);
gtk_signal_connect(GTK_OВJECT(window),"delete_event",
GTK_SIGNAL_FUNC(eventDelete),NULL);
gtk_signal_connect(GTK_OBJECT(window),"destroy",
GTK_SIGNAL_FUNC(eventDestroy),NULL);
25
26agbargraph = ag_bargraph_new();
27ag_bargraph_add(AG_BARGRAPH(agbargraph),"Pickle",82);
28ag_bargraph_add(AGBARGRAPH(agbargraph),"Onion",39);
29ag_bargraph_add(AGBARGRAPH(agbargraph),"Herring",5 4);
30ag_bargraph_add(AG_BARGRAPH(agbargraph),"Sardine",12);
31ag_bargraph_add(AGBARGRAPH(agbargraph),"Other",90);
32
gtk_container_add(GTK_CONTAINER(window),agbargraph);
gtk_widget_show_all(window);
gtk_main();
exit(0);
}
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data) {
return(FALSE);
}
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data) {
gtk_main_quit();
return(O);
}
Это очень простая прикладная программа GNOME. В строках с 17 по 24 система деинициализируется, создается окно, и для закрытия приложения устанавливаются обратные вызовы.'
В строках с 26 по 31 создается виджет AgBargraph, и в него тотчас же вставляются пять полос графа. Обращение к ag_bargraph_new() создает новый и пустой виджет. Каждый вызов функции ag_bargraph_add () определяет новую полосу, которая будет отображаться путем задания имени и значения от 0 до 100.
В строке 33 вызывается функция gtk_container_add(), которая вставляет виджет в оконный контейнер. Обращение к gtk_widget_show_all () реализует все виджеты дерева, включая виджет AgBargraph.
Заголовочный файл виджета AgBargraph
Каждый виджет имеет свой заголовочный файл для определения всех структур, констант и функций, включенных в виджет. Один и тот же заголовочный файл включается прикладной программой, использующей виджет, и исходным кодом самого виджета, написанного на языке С. Ниже приведен заголовочный файл виджета AgBargraph.
/* agbargraph.h */
2
fifndef AG_BARGRAPH_H
#define AGBARGRAPHH
5
Iinclude <gtk/gtk.h>
finclude <gtk/gtkwidget.h> 8
lifdef cplusplus
extern "C" {
lendif
12
Idefine AG_BARGRAPH(obj) \
GTKCHECKCAST(ob j,ag_bargraphgettype(),AgBargraph)
Idefine AG_BARGRAPH_CLASS(klass) GTK_CHECK_CLASS_CAST( \
klass,agbargraph_gettype(),AgBargraphClass)
Idefine AG_IS_BARGRAPH(obj) \
GTKCHECKTYPE(ob j,ag_bargraph_get_type()) 19
typedef struct _AgBargraph AgBargraph;
typedef struct _AgBargraphClass AgBargraphClass;
typedef struct ^AgBargraphBar AgBargraphBar;
23
struct _AgBargraph {
GtkWidget widget;
GdkColor *outside_color;
GdkColor *inside_color;
gint maximum_value;
gint bar_count;
gboolean contains_pointer;
AgBargraphBar *bars;
gchar *show_text;
GdkFont *text font;
};.
35
struct AgBargraphclass {
GtkWidgetClass parent_class;
};
.
struct _AgBargraphBar {
gchar *name;
gint value;
GdkGC *gc;
gint x_right;
gint xleft;
};
47
48 Idefine AGBARGRAPH MAXIMUM 100
49
GtkWidget *ag_bargraph_new(void);
guint ag_bargraph_get_type(void);
void agbargraphadd(AgBargraph *agbargraph,
gchar *name,gint value);
54
55
lifdef cplusplus
}
lendif
59
lendif /* AGBARGRAPHH ♦/
Условия прекомпилятора в строках 3, 4 и 60 запрещают включать заголовочный файл в код программы более одного раза. Этот виджет использует GtkWidget в качестве сво-
его родительского типа, поэтому в программу необходимо включить файлы gtk.h и gtkwidget.h, как это сделано в строках 6 и 7. Поскольку компилятору сообщается, что все, что находится между скобками, расположенными в строках 10 и 57, должно компилироваться как написанное на языке С, а не на C++, то этот виджет можно использовать и в программе, написанной на C++. Компилятор языка C++ всегда определяет _cplusplus.
Макрос AG_BARGRAPH, определенный в строке 13, пытается привести указатель к типу указателя на виджет AgBargraph. Если указатель имеет ошибочный тип, приведение типов аварийно завершается и выдается сообщение об ошибке. Аналогично макрос AG_BARGRAPH_CLASS, определенный в строке 15, приводит указатель к типу указателя на виджет AgBargraphClass. Макрос AG_IS_BARGRAPH, определенный в строке 17, возвращает TRUE или FALSE в зависимости от того, является ли переданный ему объект виджетом AgBargraph.
Договоренности по наименованию хорошо прослеживаются именно в операторах typedef из строк с 20 по 22. Определяемые.структуры начинаются со знака подчеркивания, а затем с помощью оператора typedef им присваиваются имена. Благодаря использованию оператора typedef для определения имен структур, разрешается выполнять объявления в такой форме:
AgBargraph *bargraph;
Структура для AgBargraph определена в строках с 24 по 34. Первое, с чего начинается структура AgBargraph в строке 25, — структура GtkWidget. Это означает, что указатель на структуру AgBargraph можно трактовать как указатель на структуру GtkWidget: обе структуры располагаются по одному адресу. Вот почему указатель на AgBargraph может быть приведен к тому же типу, что и указатель на GtkWidget. Начало структуры GtkWidget объявлено следующим образом:
struct _GtkWidget {
GtkObject object; guintl6 private_flags;
Поскольку первое, с чего начинается структура GtkWidget, — это GtkObject, все эти три типа имеют один и тот же стартовый адрес. Это означает, что указатель на AgBargraph может быть приведен к указателю на GtkWidget или указателю на GtkObject и любой указатель на GtkWidget может быть приведен к указателю на GtkObject. Такой метод используется для всех объектов GTK+ и GNOME; родительским объектом всех их является GtkObject. Поэтому GtkObject либо родитель, либо дедушка всех других объектов; сам GtkObject не имеет родительских объектов.
Поля, определенные в строках с 26 по 33, являются индивидуальными для каждого экземпляра виджета AgBargraph. Например, значение поля bar^count увеличивается всякий раз при добавлении новой полосы к виджету, то есть значение этого поля может отличаться для разных экземпляров виджета AgBargraph. Хранение всей изменяющейся от образца к образцу информации в одной структуре — это одна из хитростей, которая позволяет создавать многие экземпляры одного виджета и одновременно управлять ими. Структура класса AgBargraphClass из строки 36 содержит любые поля, определенные для всего класса объектов, а не только для отдельного экземпляра. Например, поле text^f ont, определенное в строке 33, может быть использовано для задания шрифта для каждого отдельного образца виджета AgBargraph. Если бы это поле
было включено в структуру класса, то изменение его значения сразу бы отразилось во всех экземплярах виджета. В приведенном примере структура AgBargraphclass содержит только структуру ее родительского класса.
Структура AgBargraphBar в строке 40 содержит данные, которые необходимы для задания единственной полосы графа. Всякий раз, когда новая полоса-столбец добавляется к виджету, структура этого типа добавляется в массив, названный bars, в строке 31.
Прототипы функций определены в строках с 50 по 53. Функции, которые вызываются прикладной программой, являются нестатическими. Всегда существует, по крайней мере, одна функция ’’new”, с помощью которой создается объект, и функция ’’type”, которая идентифицирует объект с помощью уникального номера. Как правило, существует еще несколько других функций, которые используются для управления виджетом. В приведенном примере единственной дополнительной функцией является функция ag_bargraph_add (), которая вставляет в виджет новую полосу-столбец. Некоторые функции могут быть определены для всего класса, а некоторые — только для отдельных экземпляров. Функция, которая определена для отдельного экземпляра, в качестве первого аргумента принимает указатель на виджет (таким образом, функция знает, для какого образца она объявлена), а функция, определенная для класса, не нуждается в указателе, поскольку она объявлена для всех экземпляров класса.
Виджет AgBargraph
Ниже приведено описание исходного кода виджета AgBargraph на языке С.
Как правило, хотя и не обязательно, все виджеты записываются в виде одного файла исходного кода. Поскольку этот файл используется для общих и личных функций, то последние следует объявлять как static во избежание вызова их приложением напрямую. Так как на функции, объявленные как static, можно ссылаться только внутри одного исходного файла, лучше всего включить весь код в один файл, чтобы статические функции могли быть вызваны всеми другими функциями.
Следующий листинг немного длиннее и сложнее приведенных ранее, поэтому он разбит на части и каждая часть описана отдельно.
/* agbargraph.c */ 2
finclude "agbargraph.h"
4
finclude <stdio.h>
finclude <stdlib.h> 7
static void ag_bargraph_class_init(AgBargraphClass *klass);
static void ag_bargraph_init(AgBargraph *bargraph);
static void ag_bargraph_realize(GtkWidget *widget);
11 static void ag_bargraph_size_allocate(GtkWidget *widget,
GtkAllocation *allocation);
static void ag_bargraph_send_configure(
AgBargraph *bargraph);
static void ag_bargraph_draw(GtkWidget *widget,
GdkRectangle *area);
static gint ag_bargraph_event(GtkWidget *widget,
GdkEvent *event);.
static void ag_bargraph_size_request(GtkWidget *widget,
GtkRequisition *requisition);
static void ag_bargraph_destroy(GtkObject *object);
static void ag_bargraph_paint(GtkWidget *widget);
static void ag_bargraph_add_gc(GtkWidget *widget,
AgBargraphBar *bar);
static void ag_bargraph_set_text(GtkWidget *widget,
GdkEventButton *event);
static void ag_bargraph_paint_text(GtkWidget *widget);
28
В строке 3 в программу включается заголовочный файл, который определяет виджет. В действительности в виджете существуют два типа статических функций. Это личные служебные функции, такие, как ag_bargraph_paint (), которые вызываются из других функций, находящихся в этом же файле, и функции обратного вызова, такие, как ag_bargraph_de stroy (), которые вызываются виджетами-родителями и виджетами- дедушками. '
Функция ag_bargraph_get_type () из строки 29 — это одна из двух требуемых нестатических функций. Эта функция необходима, потому что каждый виджет должен зарегистрироваться в системе и получить уникальный идентификационный номер. Номера идентификаторов назначаются динамически, таким образом, вы не должны сами придумывать какой-то уникальный номер. Это также означает, что единственный способ определения идентификационного номера — это обращение к этой функции.
2930313233J4*35363738394041424344454647482930313233J4*3536373839404142434445464748guint ag_bargraph_get_type(void) {
29
30
31
32
33
J4
*35
36
37
38
39
40
41
42
43
44
45
46
47
48
29
30
31
32
33
J4
*35
36
37
38
39
40
41
42
43
44
45
46
47
48
static guint ag_bargraph_type = 0;
if(1ag_bargraph_type) {
static const GtkTypelnfo ag_bargraph_info = { "AgBargraph", sizeof(AgBargraph), sizeof(AgBargraphClass),
(GtkClassInitFunc)ag_bargraph_class_init, (GtkObjectInitFunc)ag_bargraph_init, NULL, NULL, (GtkClassInitFunc)NULL
};
ag_bargraph_type = gtk_type_unique( gtk_widget_get_type(),&ag_bargraph_info);
}
return(ag_bargraph_type);
Идентификационный номер хранится в статической переменной ag_bargraph_type, объявленной в строке 31, что узаконивает ее только внутри этой функции. При первом же вызове этой функции выполняется обращение к функции gtk_type_unique () в строке 44, чтобы зарегистрировать класс и получить для него уникальный идентификационный номер. Регистрация происходит только однажды, последующие вызовы просто возвращают в строке 47 идентификационный номер. Если вы пишете ваш собственный виджет, просто вставьте функцию, как она есть, и поменяйте имена виджетов.
Вторая из двух требуемых нестатических функций — это функция ag__bargraph_new() из строки 49. Она используется для создания и возврата нового виджета. И хотя этого нет в данном примере, функция создания может требовать аргу-
менты, которые будут использоваться в процессе создания. Большинство виджетов имеют только одну функцию создания, но бывают и исключения. Например, чтобы создать виджет-кнопку, можно вызвать функцию gtk_button_create( ) или функцию gtk_button_create_with_label (). Единственным различием между этими двумя функциями являются передаваемые аргументы.
49 GtkWidget *ag_bargraph_new()'
50 { 51GtkWidget *widget =
5 2GTK_WIDGET(gtk_type_new(agbargraphgettype()));
53return(widget);
54 }
55
В строке 52 прикладной программы с помощью функции gtk_type_new() создается виджет AgBargraph. Единственный аргумент функции — идентификационный номер виджета, полученный при обращении к функции ag_bargraph_get_type (). Таким способом можно создать весь виджет, поскольку в строках с 34 по 42 прилагается вся необходимая для регистрации информация.
Функция ag_bargraph_class_init(), определенная в строке 56, в строке 38 задана как функция инициализации класса. Она вызывается однажды в начале создания каждого виджета, чтобы инициализировать класс. Ее основное предназначение — установка функций обратного вызова. Какие из этих функций будут актуальны зависит от требований вашего виджета. В данном виджете замещены пять функций родительского класса GtkWidget и одна функция прародительского класса GtkOb ject.
56 static void ag_bargraph—class—init(AgBargraphClass *klass)
57 {
GtkWidgetClass*widgetclass;
GtkObjectClass*object_class;
60
widget_class =(GtkWidgetClass*)klass;
object-dass =(GtkObjectClass*)klass;
63
widget-dass->realize = ag-bargraph-realize;
widget-dass->draw = ag-bargraph-draw;
widget—class->event = ag_bargraph—event;
widget-Class->size-request = ag_bargraph-Size-request;
widget-Class->size—allocate *
ag-bargraph_size_allocate;
70
object_class->destroy * ag_bargraph_destroy;
}
Функции обратного вызова, которые отвечают на обратные вызовы GtkWidget, указаны в строках с 64 по 69. Адрес каждого обратного вызова хранится в указателе на функцию уровня класса. Функция ag_bargraph_realize() может вызываться только один раз: немедленно после того, как впервые реализуется виджет. Всякий раз, когда необходимо перерисовать окно виджета, вызывается функция ag-bargraph_draw (). Функция ag_bargraph_event () вызывается при возникновении каждого события. Функции ag_bargraph_size_request() и ag_bargraph_size_allocate() вызываются виджетом-контейнером для определения размеров окна виджета. Присваивание в строке 71 вынуждает вызвать для удаления виджета функцию ag_bargraphidestroy().
Функция ag_bargraph_init (), которая начинается со строки 73, в строке 39 назначена как функция инициализации виджета. Она устанавливает все начальные значения структуры виджета.
static void ag_bargraph_init(AgBargraph *bargraph)
{
GdkColor *color;
76
color * g_malloc(sizeof(GdkColor));
78color->red = 45000;
79color->blue = 15000;
80color->green = 15000;
81bargraph->outside_color = color;
82
83color = gmalloc(sizeof(GdkColor));
84color->red = 45000;
85color->blue * 45000;
86color->green * 45000;
bargraph->inside_color = color;
88
bargraph->bar_count * 0;
bargraph->bars = NULL;
bargraph->maximum_value = AGBARGRAPHMAXIMUM;
bargraph->containsjointer = FALSE;
}
При вызове функции ag^bargraph^init () виджет еще не был реализован, поэтому единственное, что можно сделать — это инициализировать то, что не требует информации об окне виджета. В приведенном примере в строках с 77 по 97 создается и инициализируется пара структур GdkColor. Хотя цвета красный, зеленый и синий определены, тем не менее, сам цвет не распределен, поскольку карта цветности пока еще не доступна. В строках с 89 по 92 устанавливаются другие значения пю умолчанию, да и указатели устанавливаются равными NULL.
Функция ag_bargraph_realize(), которая начинается со строки 94, вызывается после реализации виджета, поскольку в строке 64 ей присвоена именно эта роль. Определяются размеры и положение окна виджета, сам он создается и конфигурируется.
static void agJargraphjealize(GtkWidget *widget)
{
AgBargraph *bargraph;
GdkWindowAttr attributes;
guint attributesjask;
•
g_return_if Jail (widget 1= NULL);
g_return JfJail (AGJSJARGRAPH(widget));
102
bar graph = AG JARGRAPH (widget);
104
GTKJIDGETJETJLAGS (widget, GTKREALIZED);
106
attributes.window type = GDK WINDOW CHILD;
attributes.x = widget->allocation.x;
attributes.у = widget->allocation.y;
attributes.width * widget->allocation.width;
attributes.height = widget->allocation.height;
attributes.wclass = GDK_INPUT_OUTPUT;
attributes.visual = gtk_widget_get_visual(widget);
attributes.colormap = gtk_widget_get_colormap(widget);
attributes.event_mask = gtk_widget_get_events(widget);
116 attributes.event_mask |= (GDKEXPOSURE MASK |
117GDK_BUTTON_PRESS_MASK |
113GDK_BUTTON_RELEASE_MASK |
119GDK_ENTER_NOTIFY_MASK |
120GDKLEAVENOTIFYMASK);
121
122attributes_mask = GDKWA X | GDKWAY
123| GDKWAVISUAL f GDKWACOLORMAP;
124widget->window = gdk_window_new(
125gtk_widget_get_parent_window(widget),
126&attributes,attributes_mask);-
127
128gdk_window_set_user_data(widget->window,widget);
129
130widget->style = gtk_styleattach(widget->style,
131widget->window);
132gtk_style_set_background(widget->style,
133widget->window,GTK_STATE_NORMAL);
134
135ag_bargraph_send_configure(AG_BARGRAPH(widget));
136
137gdk_color_alloc(gtk_widget_get_colormap(widget),
138bargraph->outside_color);
139gdk_color_alloc(gtk_widget_get_colormap(widget),
140bargraph->inside_color);
141 }
В строке 105 используется макрос GTK_WIDGET_SET_F1AGS для установки флагов, сигнализирующих о том, что виджет был реализован. Существует множество опций, которые могут быть установлены при создании нового окна, поэтому аргументы хранятся в структуре GdkWindowAttr, которая определена в строке 97. Эта структура используется в качестве аргумента при обращении к функции gdk_window_new() в строке 124. Некоторые значения в структуре GdkWindowAttr обязательны, а другие — нет. Необязательные значения игнорируются, если только не указан соответствующий флаг, подобный тем, что устанавливаются в маске attributes^mask в строке 122.
В табл. 18.1 перечислены все поля структуры GdkWindowAttr и значения флагов, связанных с каждым из них. Флаги используются для вас, чтобы определить, какие поля содержат корректные данные оконной спецификации. Если с полем связан флаг, то в маске флага, передаваемой gdk__window__new(), необходимо установить бит флага равным 1, что заставляет функцию использовать прилагаемое значение. Если бит флага равен 0, то будет использоваться значение по умолчанию вместо аналогичного из структуры GdkWindowAttr. Некоторые поля не имеют определенных для них флагов, поскольку всегда используется значение, хранящееся в структуре GdkWindowAttr. Примером обязательного аргумента является тип создаваемого окна. Тип окна должен принимать одно из значений, приведенных в табл. 18.2.
Таблица 18.1. Поля и установки флагов структуры GdkWindowAttr
Попе
ФлагОписание
gchar ‘title
GKK_WA_TITLEНаименование, которое появляется в
строке заголовка окна. По умолчанию выводите^ имя программы.
gint event_ma$k
Флаги, определяющие события, получаемые окном.
guint16 x
GKK_WA_XПоложение по горизонтали относи
тельно родительского окна, выраженное в пикселах. По умолчанию равно нулю.
guint16 у
GKK_WA_YПоложение повертикали относитель
но родительского окна, выраженное в пикселах. По умолчанию равно
guint16 width
guint16 height
GdkWindowClass wclass
»нулю.
Ширина окна в пикселах.
Высота окна в пикселах.
Окно GKKJNPUT_kNLY воспринимает события, но не отображается на экране. Окно GKK_INPUT_kUTPUT воспринимает события и отображается на экране.
GdkVisual ‘visual
GKK_WA_VISUALС этим окном используется поле
visual. Если оно не определено, т<Э берется стандартное по умолчанию из используемой структуры GdkVisual.
GdkColorMap ‘colormap
GKK_WA_CkLkRMАР Карта цветности, используемая с этим окном. По умолчанию берется системная карта, которая совпадает с заданным по умолчанию visual.
GdkWindowType window_type GdkCursor ‘cursor
Один из типов, описанных в .табл. 18.2.
GKK_^WA_CURSkRКурсор мыши для этого окна. По
умолчанию принимается курсор родительского окна.
gchar *wmclass_name gchar *wmclass_class
GKK_WA_WMCLASS Наименование и класс, которые используются для отображения всплывающих подсказок. По умолчанию подсказки отсутствуют.
gboolea n override__redirect
GKK_WA_NkREKIRЕсли принимает значение TRUE,
менеджер окон не управляет размерами и положением окна. По умолчанию устанавливается FALSE, если только тип окна не GKK_WINKkW_TEMP.
436
Часть II. Шаг за шагом
Таблица 18.2. Типы окон, определяемые структурой GdkWindowType
Тип
Описание
GKK
.WINKkW
_ RkkT
Корневое окно, закрывающее весь экран.
GKK.
.WINKkW.
JkPLEVEL
Окно, созданное приложением как главное окно. Обычно оно имеет строку заголовка и управляющие меню. Может выступать в качестве родительского ряда дочерних окон.
GKK_
WINKkW.
CHILK
Окно, которое содержится внутри другого окна и является
дочерним окном окна верхнего уровня.
GKK.
.WINKkW.
.KIALkG
То же, что и окно верхнего уровня, за исключением того, что менеджеру окон сообщается, что это диалоговое окно (и может рассматриваться по-другому).
GKK.
WINKkW.
TEMP
Окно, которое существует короткий период времени, как, например, опускающееся меню. Это окно верхнего уровня без строки заголовка и управления. Такое окно всегда
перекрывает переназначение ввода-вывода, что ограничивает менеджера окон в части управления окном. Например, опускающееся меню может выходить за границы окна, кото
рое в противном случае было бы его родительским окном.
GKK.
WINKkW_
PIXMAP
Окно хранится в памяти и не появляется на экране. Как цветное растровое изображение, так и окно считаются объектами GdkKrawable, поскольку для записи и в то, ив другое используется один и тот же набор функций.
GKK.
.WINKkW.
.FkREIGN
Любое окно, не созданное GKK+.
В строках со 116 по 120 определены события, которые посылаются этому виджету, включая события, которые передаются родительскому окну. Кроме того, имеется пять событий, которые необходимы именно для этого приложения, поэтому они определяются независимо от того, установлены ли таковые в родительском виджете или нет.
В обращении к функции gdk_window_set_user_data () в строке 128 указывается, что в качестве первого аргумента будет передаваться сам виджет. При вызове функции gtk_style_attach() в строке 130 анализируется стиль окна, оно инициализируется и, если необходимо, обновляется и изменяется. Затем функция возвращает указатель на (возможно новый) стиль. Обращение к функции gtk__style_set_background () в строке 132 инициализирует цвет фона в соответствии с цветом, описанным в стиле: чистый цвет, растровый рисунок, "гравировка" или что- нибудь еще. Поскольку этот виджет может иметь только одно состояние, то нет необходимости инициализировать какие-либо другие состояния.
Родительский виджет необходимо уведомить о размерах и положении изображения, поэтому в строке 135 вызывается функция ag_bargraph_send_conf igure(), чтобы создать событие GdkEventConf igure и отослать его родительскому виджету.
Последний шаг инициализации — это распределение цветов из карты цветности. Обращения к функции gdk__color_alloc () в строках со 137 по 140 используют данные в формате RGB, хранящиеся в структурах в строках с 77 по 87, чтобы выделить цвета с соответствующим значением для карты цветности.
В строке 142 функция ag_bargraphidestrоу () вызывается всякий раз при удалении виджета, поскольку в строке 71 именно она определена как функция обратного вы-
зова "destroy" (для удаления). Назначение этой функции — высвобождение выделенной памяти и других ресурсов системы.
142 static void agbargraph destroy(GtkObject *object)
143 {~
144int i;
145AgBargraph *bargraph;
146AgBargraphclass *klass;
147
148greturniffail(object1=NULL);
149greturniffail(AG_ISJ8ARGRAPH(object));
150
151bargraph = AGBARGRAPH(object);
152gfree(bargraph->outside_color);
153g_free(bargraph->inside_color);
154for(i=0; i<bargraph->bar_count; i++) {
155g_free(bargraph->bars[i].name);
156if(bargraph->bars[i].gc 1= NULL)
157gdk_gc_destroy(bargraph->bars[i].gc);
158}
159g_free(bargraph->bars);
160
161if(bargraph->text_font !=NULL)
162gdkfontunref(bargraph->textfont);
163
164klass = gtktypeclass(gtk_widget_get_type());
165if(GTKOBJECTCLASS(klass)->destroy)
166(* GTK_OBJECT_CLASS(klass)->destroy)(object);
167 }
В строках co 151 no 159 освобождаются любые блоки памяти, которые были выделены для виджета. В строке 157 удаляются все существующие графические контексты. В строке 162, если создается объект шрифта, его счетчик ссылок уменьшается на 1. Если значение счетчика уменьшилось до нуля, шрифт удаляет сам себя. Если значение счетчика не достигло нуля, то такой же шрифт используется где-нибудь в другом месте программы.
В строках со 164 по 166 вызывается функция удаления объекта. К этому моменту все, что было выделено под виджет, уже освободилось, и поэтому необходимо только вызвать функцию удаления родительского виджета, которая может выполнить аналогичную операцию для ресурсов. Вызов функции destroy () в строке 166 возвращает системе всю память, и виджет прекращает свое существование.
Функция ag_bargraph_draw() из строки 168 вызывается всякий раз при необходимости перерисовки в окне виджета, поскольку в строке 65 она назначена функцией обратного вызова. Это случается при первоначальном запуске программы (сразу же после реализации ее окна) и также при изменении размеров окна.
168 static void ag_bargraph_draw(GtkWidget ♦widget,
169GdkRectangle *area)
170 {
171g_return_if_fail(widget 1= NULL);
172g_return_if_fail(AG_IS_BARGRAPH(widget));
173
174ag_bargraph_paint(widget);
175 }
Функция ag_bargraph_draw() сама не выполняет рисования. Фактически рисование производится при обращении к ag_bargraph_paint () в строке 174. В более сложном виджете, в котором выполняется рендеринг, вы, возможно, захотите ограничить вывод прямоугольной областью, указанной в строке 169 посредством объекта GdkRectangle. Этот прямоугольник задает единственную область внутри окна, которую необходимо перерисовывать.
Функция ag_bargraph_event () из строки 176 вызывается при возникновении любого из событий. Все события, выбранные посредством флагов в строках со 115 по 120, устанавливают вызов этой функции.
176 static gint ag_bargraph_event(GtkWidget *widget,
177GdkEvent ♦event)
178 {
179AgBargraph *bargraph;
180
181g_return_val_if_fail(widget != NULL,FALSE);
182g_return_val_if_fail(AG_IS_BARGRAPH(widget),FALSE);
183
184bargraph = AGJBARGRAPH (widget);
185
186switch(event->type) {
187caseGDK_ENTER_NOTIFY:
188bargraph->contains_pointer=TRUE;
189break;
190caseGDK_LEAVE_NOTIFY:
191bargraph->contains_pointer=FALSE;
192break;
193caseGDK_BUTTON_PRESS:.
194agbargraph_set_text(widget,
195(GdkEventButton ♦)event);
196break;
197case GDKJBUTTONRELEASE:
198bargraph->show_text=NULL;
199break;
200case GDK_EXPOSE:
201break;
202default:
203return(FALSE);
204}
205ag_bargraph_paint(widget);
206return(TRUE);
207 }
В зависимости от типа события оператор switch в строке 186 выбирает выполняемое действие. Булева переменная contains_pointer включается и выключается соответственно при вхождении указателя мыши в окно и при выходе из него. Всякий раз, когда нажимается кнопка, текст, который должен выдаваться на экран, определяется путем обращения к ag_bargraph_set_text (). Если событие не должно оказывать никакого влияния на изображение, в строке 203 выполняется действие, заданное по умолчанию, и функция выполняет возврат, не производя никаких действий. Но если одно из событий меняет изображение, то в строке 205 вызывается функция ag_bargraph_paint (), которая обновляет экран дисплея.
Функция ag_bargraph_set_text() из строки 208 определяет, какая полоса (столбец) находится под указателем мыши в данный момент, и сохраняет указатель на найме-
нование полосы в месте, используемом функцией прорисовки для отображения наименования.
208 static void ag_bargraph_set_text(GtkWidget *widget,
209GdkEventButton *event)
210 {
211int i;
212
213AgBargraph *bargraph = AG_BARGRAPH(widget);
214
215bargraph->show_text = NULL;
216for(i=0; i<bargraph->bar_count; i++) {
217if((event->x > bargraph->bars[i].x_left) &&
218(event->x <= bargraph->bars(i].xright)) {
219bargraph->show_text = bargraph->bars[i].name;
220return;
221}
222}
223 }
Функция ag_bargraph_paint() из строки 224 рисует полное окно виджета. Одной из ее задач является вычисление горизонтального и вертикального положений полос графа. Для вычислений применяются числа с плавающей запятой, поскольку целочисленная арифметика ведет к накоплению небольших ошибок, приводящих к возникновению пустых пространств между полосами или перекрытий. Это также может произойти, когда число с плавающей запятой конвертируется в целочисленный пиксел, но ошибка, если даже и возникает, в этом случае несравненно меньше.
224 static void ag_bargraph_paint(GtkWidget *widget)
225 {
int i;
AgBargraph *bargraph = AG_BARGRAPH(widget);
float barpercent;
floatbarwidth;
floatbar_height;
floatbarx;
floatbary;
233
234if(bargraph->contains_pointer){
235gdk_window_set_background(widget->window,
bargraph->inside_color);
} else {
gdk_window_set_background(widget->window,
bargraph->outside_color);
}
gdk_window_clear(widget->window);
.
bar_x = 0;
bar_width = (float)widget->allocation.width/
(float)bargraph->bar_count;
for(i=0; i<bargraph->bar_count; i++) {
if(bargraph->bars[i].gc == NULL)
agbargraph_add_gc(widget,&bargraph->bars[i]);
bar_percent = (float)bargraph->bars[i].value /
(float)bargraph->maximum_value;
bar_height = bar_percent*
* (float)widget->allocation.height;
253254255256257258259260261262263264 }253254255256257258259260261262263264 }Ьагу = (float)widget->allocation.height
253
254
255
256
257
258
259
260
261
262
263
264 }
253
254
255
256
257
258
259
260
261
262
263
264 }
* (1.0 - bar_percent);
gdk_draw_rectangle(widget->window, bargraph->bars[i].gc,TRUE,
•(gint)bar__xr (gint)bar_y,
(gint)bar_width + 1,(gint)bar_height + 1);
bargraph->bars[i].x_left = (gint)bar_x;
barx += bar_width;
bargraph->bars[i].x_right = (gint)barx;
}
ag_bargraph_paint_text(widget);
Оператор if в строке 234 для выбора цвета фона проверяет, находится ли курсор в окне виджета, при этом используется булева переменная, объявленная в строках со 188 по 191. Далее в строке 241 с помощью вызова функции gdk_window_clear() окно заполняется фоновым цветом.
Размеры и положение каждой вертикальной полосы вычисляются в цикле, который начинается в строке 246. При первом отображении полосы для нее с помощью вызова ag_bargraph_add_gc () создается графический контекст. Он создается в самый последний момент, упрощая в любое время добавление новой полосы к виджету. Как только размеры и положение полосы определены, она рисуется в окне с помощью вызова функции gdk_draw_rectangle() в строке 255. В конце цикла в строках с 259 по 261 сохраняются два значения х как часть информации о полосе, отмечая ее края, и значение переменной Ьаг_х увеличивается до координаты начала следующей полосы. И, наконец, в строке 263 вызывается функция ag_bargraph_paint_text(), выбирающая текст полосы, который может быть выведен.
Если для виджета значение указателя show^text не равно NULL, то указатель содержит адрес строки символов, которые должны выводиться на экран. Равен указатель значению NULL или нет, определяется при обработке событий в строках со 193 по 199. Текст только присутствует на экране, если удерживается кнопка мыши.
265 static void agbargraph_paint_text(GtkWidget «widget)
266 {
267 AgBargraph «bargraph = AGBARGRAPH(widget);
268gintIbearing;
269gintrbearing;
270gintwidth;.
271gintascent;
272gintdescent;
273gintx;
274ginty;
275
276 if(bargraph->show_text ** NULL)
277return;
278
279if(bargraph->text_font == NULL) {
280bargraph->text_font * gdk_font_load(
281"-«-bookman-light-r-normal—18-*-*-*-p-*-iso8859-l");
282}•
283gdk_text_extents(bargraph->text_font,
284bargraph->show_text,
285strlen(bargraph->show_text),
286&lbearing.
287trbearing,
288&width,
289Sascent,
290^descent);
291 у * ascent;
292 x = (widget->allocation.width / 2) - (width / 2);
293
294gdk_draw_string (widge t->window,
295bargraph->text_font,
296widget->style->black_gc,
297x,y,
298bargraph->show_text);
299 }
Если текст будет отображаться впервые, то в строках с 279 по 282 определяется шрифт с помощью обращения к функции gdk_font_load(). Далее в строке 283 вызывается функция gdk_text_extents(). В строках 291 и 292 из нее устанавливаются значения переменных X и у, которые используются для размещения текста вверху по центру окна. Строка текста выводится на экран в строке 294 путем вызова функции gdk_draw_string().
Каждая вертикальная полоса графа имеет свой цвет, а цвета устанавливаются в строке 300 функцией ag_bargraph_add_gc (). В приведенном примере цвет, назначенный каждой полосе, выбирается случайным образом. (В действительности, псевдослучайным образом, поскольку при каждом запуске программы последовательность цветов будет одна и та же).
300 static void ag_bargraph_add_gc(GtkWidget *widget,
301AgBargraphBar *bar)
302 {
303GdkColor color;
304GdkColormap *colormap;
305
306bar->gc = gdk_gc_new(widget->window);*
307color.red +» (((double)rand()*0xFFFF)/RAND MAX);
308color.green += (((double)rand()*0xFFFF)/RAND MAX);
309color.blue += (((double)rand()*0xFFFF)/RAND_MAX);
310
311colormap = gtkwidgetgetcolormap(widget);
312
313gdk^coloralloc(colormap,Scolor);
314gdk_gc_set_foreground(bar->gc,&color);
315 }
Функции ag_bargraph_size_request ( ) в строке 316 и ag_bargraph_size_allocate() в строке 325 вместе определяют размеры и положение виджета. В строках 67 и 68 эти две функции установлены как функции обратного вызова для получения размеров. Они вызываются любым виджетом-контейнером, содержащим виджет AgBargraph.
316 static void agbargraphsizerequest(GtkWidget *widget,
317GtkRequisition *requisition)
318 {
319g_return_if_fail(widget != NULL);
320g_returniffail(AG_ISBARGRAPH(widget));
321
322requisition->width = 200;
323 requisition->height = 100;
324 }
325 static void ag_bargraph_size_allocate(GtkWidget *widget,
326GtkAllocation *allocation)
327 {
328g_return_if_fail(widget 1= NULL);
329g_return_if_fail(AG_IS_BARGRAPH(widget));
330g_return_if_fail(allocation 1= NULL);.
331
332widget->allocation.x = allocation->x;
333widget->allocation.y = allocation->y;
334widget->allocation.width = allocation~>width;
335widget->allocation.height = allocation->height;
336
337if(GTK_WIDGET_REALIZED(widget)) {
338gdk_window_move_resize(widget->window,
339allocation->x,allocation->y,
340allocation->width,allocation->height);
341ag_bargraph_send_configure(AGBARGRAPH(widget));
342}
343 }
Процесс определения размеров виджета называется согласованием (negotiating) размеров. Но последнее слово все равно остается за контейнером. Во-первых, для определения предпочтительных размеров виджета контейнер вызывает функцию ag_bargraph_size__request (). Далее контейнер использует возвращаемые значения, оценивает их в свете других требований и ограничений для вычисления актуальных размеров и вызывает функцию ag_bargraph_size__allocate (), которая и принимает окончательное решение по размерам и размещению. В строках с 332 по 335 значения размеров и размещение сохраняются в виджете. Если виджет реализован, тогда уже существует окно. Поэтому в строке 338 изменяются размеры существующего окна, и оно перемещается в новое положение. Кроме того, обращение к функции ag_bargraph_send_conf igure () в строке 341 генерирует событие реконфигурирования, которое вынуждает виджет перерисовать себя в соответствии с новыми размерами и положением.
Процесс согласования размеров может быть довольно сложным. Например, виджет AgBargraph содержится в рамке, которая находится в вертикальном ящике, который, в свою очередь, удерживается главным окном приложения. В процессе согласования размеров должны участвовать все эти виджеты. Процесс начинается с самого верхнего уровня (с единственного виджета-контейнера окна верхнего уровня). Запрашивается вертикальный ящик, насколько велик он будет. Далее вертикальный ящик запрашивает то же самое у всех содержащихся в нем виджетов, один из которых — рамка. И, наконец, рамка запрашивает AgBargraph. Рамка берет все возвращаемые ей числа, добавляет к ним свои собственные требуемые размеры и передает результат вертикальному ящику. Далее ящик складывает размеры всех своих дочерних виджетов, по ходу решая изменить размеры некоторых из них, если в этом есть необходимость, и передает результат контейнеру в главном окне. Затем контейнер главного окна решает, какой должен быть общий размер, и вызывает функцию, сообщающую вертикальному ящику его ширину и высоту. В свою очередь, вертикальный ящик делит на части эти размеры и вызывает функции для каждого из содержащихся в нем виджетов, сообщая им их размеры. Этот процесс продолжается до тех пор, пока AgBargraph не выяснит, каковы должны быть его размеры, и не отобразит себя.
Функция ag_bargraph_send_conf igure() из строки 344 не обязательна для данного виджета, но бывают случаи, когда она необходима. Например, если бы данный виджет был расширением не GtkWidget, a GtkButton, тогда необходимо было бы уведомить виджет-кнопку об изменении размеров, чтобы кнопка, в свою очередь, могла бы поменять размеры содержащегося в ней виджета метки (надписи).
344 static void ag_bargraph_send__configure(
345AgBargraph *bargraph)
346 {
347GtkWidget *widget;
348GdkEventConfigure event;
349
350widget = GTK_WIDGET(bargraph);
351
352event.type = GDK_CONFIGURE;^
353event.window = widget->window;
354event.x = widget->allocation.x;
355event.у = widget~>allocation.y;
356event.width = widget->allocation.width;
357event.height = widget->allocation.height;
358.
359gtk_widget_event(widget,(GdkEvent *)&event);
360 }
В строках с 352 по 357 в структуре GdkEventConfigure сохраняются текущие размеры и размещение. Обращение к функции gtk_widget_event() в строке 359 генерирует событие для нее, вынуждающее любую функцию, которая конфигурируется, получать этот сигнал для отработки.
Для добавления новой полосы к графу из строки 361 приложения вызывается функция ag_bargraph_add().
361 void ag_bargraph_add(AgBargraph *bargraph,gchar *name,
362gint value)
363 {
364AgBargraphBar *newbars;
365gint newcount;
366
367g_return_if_fail(bargraph 1= NULL);
368g_return_if_fail(AG_IS_BARGRAPH(bargraph));•
369
370newcount = bargraph->bar_count + 1;
371 newbars = g_malloc(sizeof(AgBargraphBar) ♦ newcount);
372memcpy(newbars,bargraph->bars,"
373sizeof(AgBargraphBar) * bargraph->bar_count);
374newbars[bargraph->bar_count].name = g_strdup(name);
375newbars[bargraph->bar_countJ.value = value;
376newbars[bargraph->bar_count].gc « NULL;
377
378g_free(bargraph->bars);
379bargraph->bars = newbars;
380bargraph->bar_count = newcount;
381 }
Новая вертикальная полоса создается в строке 371. Полосы содержатся в массиве bars в структуре AgBargraph, которая расширяется при добавлении новой полосы. Расширение достигается за счет создания нового массива, копирования указателей из ста-
рого массива в новый и последующего удаления старого массива. Наименование и значение полосы сохраняются, но графический контекст установлен в значение NULL. Здесь не может быть создан графический контекст, поскольку эта функция может быть вызвана до реализации какого-нибудь из окон. Поэтому в строке 248 функция ag_bargraph_paint () берет на себя установку графического контекста. .
Изменения и обновления виджета
Поскольку виджет является объектом и поскольку объект является замкнутой системой, возможно вносить в него дополнения и изменения, не вызывая никаких проблем ни в одной из прикладных программ, которые используют данный объект. Если существующие функции API, общие из которых вместе с их прототипами описаны в файле agbargraph • h, остаются и выполняют те же самые действия, то любое количество изменений может быть проведено в виджете и даже добавлены новые функции. Вы можете вносить любые изменения, но необходимо следить за тем, чтобы внешний вид, который устанавливается по умолчанию, и действие не отличались от их оригинальных вариантов. В этом случае любое существующее программное обеспечение будет продолжать работать, в то же время будут доступны и новые возможности. Это, наверное, наиболее весомое преимущество объектно-ориентированного программирования или, по крайней мере, второе по важности после возможности быстрого внедрения функции, выполняющей определенное задание.
Если в виджете необходимо произвести большие изменения, которые могут повлиять на работу существующих приложений, то лучше в таком случае написать новый виджет и использовать в качестве родительского виджет AgBargraph, а не GtkWidget. Таким образом, ваш новый виджет может сохранить те возможности, которые вас устраивают, и изменить некоторые другие. Вовсе не обязательно иметь виджет-наследник четвертого или пятого поколения.
Виджет AgBargraph был намеренно сделан упрощенным для демонстрации структуры виджета. Вы можете наделить виджет рядом дополнительных возможностей. Так, например, можно добавить следующую функцию, позволяющую приложению устанавливать максимальное значение.
ag_bargraph_set_maximum(AgBargraph *bargraph,gint value)
{.
bargraph->maximum_value = value;
}
Можно проделать аналогичное действие для установки минимального значения, но при этом придется внести изменения в методику вычисления размеров и положения. Это вызвано тем, что в существующем коде принято минимальное значение, равное нулю.
Кроме того, можно сделать, чтобы максимальное значение могло меняться динамически. Как вариант по умолчанию можно принять уже существующий (с фиксированным максимумом), но иметь опцию, позволяющую самому вйджету определять максимальное значение по данным добавленной полосы. Такую опцию можно установить путем добавления функции создания, которая включит ее:
GtkWidget *ag_bargraph_new_autoadjust();
Эта функция делает то же, что и функция ag_bargraph_new(), но она, кроме того, устанавливает флаг, который вынуждает переопределять максимальное значение каждый
раз при добавлении новой полосы. Все первоначальные возможности сохранены, и добавлена новая возможность.
Существует ряд способов сделать виджет более полезным и привлекательным. Например, можно добавить пару функций, которые устанавливают цвета фона при входе указателя мыши в окно виджета и при выходе из него. Или можно добавить опции установки цвета к списку аргументов функции ag_bargraph_new(). Рисование полос также можно сделать более привлекательным. Вы можете сделать их подобными трехмерным блокам. Также могут быть опции для прорисовки горизонтальных полос, отображающие сначала более длинные полосы или, наоборот, более короткие, аннотирующие каждую полосу по ее имени или числовому значению и т.д.•
Выводы
При написании виджетов необходимо учитывать множество вещей, но структура основного наследования GTK+ все упрощает и дает четко определенную структуру виджета. Если в ваших приложениях часто повторяется один и тот же компонент (и особенно, если он встречается в различных приложениях), то, может быть, имеет смысл преобразовать этот компонент в виджет, что позволит стандартизировать управление и упростить интерфейс прикладной программы. В настоящей главе рассмотрены фундаментальные основы создания виджетов:
8 Виджет - это объект в иерархии объектов. Предком каждого виджета является GtkWidget, a GtkObject — предок виджета GtkWidget. GtkObject не имеет предков.
# Ваш виджет может входить в состав других виджетов, управляться и отображаться так же, как и любой виджет GTK+.
8 Виджет определяется в двух файлах: в исходном, написанном на языке С и содержащем все функции виджета, и в заголовочном файле, также написанном на С, который содержит определения данных и прототипы доступных и вне виджета функций.
8 В виджете содержится целый ряд статических функций. Перед многими из них стоит задача отвечать на обратные вызовы, чтобы менять конфигурационные установки, реагировать на пользовательские события или отображать окно.
# Вы можете расширить любой виджет, чтобы создать новый. Если уже существует какой-либо виджет, очень похожий на тот, который хотите сделать вы, можно унаследовать возможности существующего виджета или добавить к нему интересующие вас возможности.
В следующей главе — последней главе части "Шаг за шагом" — описывается, каким образом ваша программа может реагировать на свое окружение и модифицировать свое действие. Во-первых, ваша программа может хранить и получать установки окружения, что позволяет ей адаптироваться к предпочтениям пользователя. Во-вторых, можно разработать приложение, которое будет автоматически транслироваться на язык пользователя.
446
главаКонфигурация и
19интернационализация
В этой главе
Считывание настроек окружения, которые могут быть использованы для конфигурирования приложения
Запись настроек пользовательского окружения для использования их при следующем запуске приложения•
Формирование кода программы, который при ее запуске может быть оттранслирован на другой язык
В этой главе рассматриваются два взаимосвязанных вопроса. Первый вопрос — это настройки конфигурации, которые могут быть сохранены и восстановлены приложением, а второй — метод, позволяющий вашей программе автоматически себя оттранслировать для использования в разных локалях.
По умолчанию настройки, или установки, конфигурации хранятся в домашнем (исходном) каталоге пользователя. Это означает, что каждый пользователь может иметь свои установки. И, кроме того, настройки хранятся в обычном формате ASCII, поэтому каждый, кто имеет к ним доступ, может при необходимости их редактировать.
Интернационализация (internationalization — также называется И8п, потому что в этом слове между i и п находится 18 букв) как процесс достаточно хорошо автоматизирована. При написании кода те строки, которые необходимо будет перевести на другой язык, маркируются. Используя эти маркированные строки, человек переводит их на другой язык и устанавливает на диск. Когда пользователи запускают программу и локаль указывает, что текст должен быть переведен, программное обеспечение замещает маркированные строки программы на их перевод.
Управление окружением
Программа может иметь пользовательские файлы конфигурации, которые содержат настройки и значения, сохраняющиеся между вызовами программы. Например, если при работе приложения пользователь изменяет шрифт, размер окна и отдельные цвета, их значения должны быть сохранены так, чтобы при следующем запуске программы они могли быть получены и использованы.
ПРИМЕЧАНИЕ НАУЧНОГО РЕДАКТОРА
API — application program interface — интерфейс прикладных программ.
GNOME API включает набор функций, используемых для сохранения значений таким образом, что позже эти значения могут быть восстановлены и использованы. При запуске программа может считывать установки конфигурации и применять найденные значения для настройки ее операций. Программа также может считывать установки конфигурации и, хотя и необязательно, изменять их и записывать обратно. Поскольку установки конфигурации хранятся в файле на диске, они сохраняются между вызовами программы.
Формат файла конфигурации•
Настройки конфигурации хранятся в файле формата ASCII. Формат файла включает категории с ключами внутри каждой из них. Каждому ключу присвоено значение. Ниже приведен образец файла, содержащего два заголовка и пять ключей:
[winsize]
width=120
height=80
[colornames]
background=white
edges=blue
lettering=gray42
Категория winsize содержит ключи width и height. Значение каждого ключа — целое число. Категория colornames содержит ключи background, edges и lettering. Все эти три ключа строковые величины. Обратите внимание, что в файл не включается информация о типе данных, программа, которая считывает и записывает значения, сама определяет фактический тип данных.
Расположение файла конфигурации
По умолчанию файл располагается либо в подкаталоге . gnome, либо в подкаталоге .gnome_private домашнего (исходного) каталога пользователя. Обычно используется каталог .gnome, но вы можете предпочесть хранить некоторые настройки в каталоге .gnome_private. Разница в том, что каталог .gnome доступен всем, а каталог . gnome_private — только одному пользователю. Если вы планируете хранить такие компоненты, как пароли, то желательно использовать каталог .gnome_private.
За один раз функции обращаются только к одному значению ключа, поэтому при каждом вызове функций необходимо указывать полный путь (маршрут) к ключу. Путь состоит из трех частей следующего формата:
/filename/category/keyname
Здесь filename — это имя файла, содержащего данные по конфигурации. Хотя маршрут начинается с наклонной черты, это наименование не абсолютного маршрута. Фактический маршрут к файлу создается путем включения имени домашнего каталога пользователя и выглядит подобно этому:
/home/fred/.gnome/filename
А если вы вызываете функцию, имеющую дело с личными настройками пользователя, то путь может выглядеть следующим образом:
/home/fred/.gnomejprivate/filename
Адрес всегда состоит из трех частей: файл (filename), категория (category) и имя ключа (keyname), то есть, каждый адрес — это имя полного маршрута к ключу. Чтобы запол-
нить два предыдущих адреса, необходимо включить в них категорию и имена ключей следующим образом:
/home/fred/.gnome/filename/wins ize/width /home/fred/.gnome_private/filename/winsize/width
Есть и другой вариант. Окружив имя файла знаками равенства, вы можете задать абсолютный маршрут и расположить файл конфигурации, где угодно. Это, пожалуй, наилучший и пригодный для всех пользователей способ поддержать конфигурационные установки. Например:
=/var/maxique/config®/colornames/background указывает файл с именем абсолютного маршрута /var/maxique/conf ig.
Считывание и запись в файл конфигурации
Файл конфигурации создается, когда приложение впервые записывает в него. Чтение из отсутствующего файла конфигурации или попытка прочесть несуществующий ключ не является ошибкой — просто в этом случае возвращаемое значение указывает, что функция имеет значение NULL, или нулевое значение. Ниже приведен файл конфигурации, который используется следующими далее образцами программ для чтения и записи:
[geometry] width=8-
height®3 margin®15 [id] name=Homer nickname® show_menu=true time=931815930
Файл содержит две категории: geometry и id. Категория geometry определяет численные значения для width, height и margin. Категория id определяет name, но не имеет установки для nickname. Булево значение ключа show_menu установлено равным true, a time — время последнего обновления файла конфигурации. Этот файл был создан следующей программой:
1 /** maxiquel.с *♦/ 2 Iinclude <gnome.h> 3
4
5 int main(int argc,char *argv[J)
6 {
7gnome_init("maxique!","1.0",argc,argv);
8gnome_config_set_int("/maxique/geometry/width",8);
9gnomeconfig_set_int("/maxique/geometry/height",3);
10gnomeconfig_set_int("/maxique/geometry/margin", 15);
11gnome_configset_string("/maxique/id/name","Homer");
12gnome_configsetstring("/maxique/id/nickname",NULL)
13gnomeconfig_set_bool("/maxique/id/showmenu",TRUE);
14gnomeconfig_setint("/maxique/id/time",time(NULL));
15gnome_config_sync();
16exit(0);
17 }
По именам маршрутов видно, что имя этого файла — maxique и что хранится он в пользовательском каталоге . gnome. Для сохранения в памяти (не на диске) ключей и связанных с ними значений используются функции типа "set”. В каждой из строк 8,9 и 10 целочисленному значению в категории geometry назначается ключ. Категория id устанавливается с помощью вызова функций в строках с 11 по 14. В каждом случае первый аргумент — это полный маршрут к ключу, а второй — назначенное ключу значение. Данные остаются в памяти до тёх пор, пока не будет вызвана функция gnome_conf ig_sync(), выполняющая запись в файл конфигурации на диске. Если эта функция не вызывается, то файл не обновляется.
В процессе записи в файл с помощью функции gnome_config_sync() не перезаписываются данные, которые уже там имеются, то есть, если указан файл, который уже содержит какие-то ключи, а вы перед вызовом функции gnome^conf ig_sync() создаете один новый ключ (и больше не делаете ничего), то новый ключ просто добавляется в список, все другие ключи и значения не меняются. .
Приведенная ниже программа считывает и выдает на экран все значения, хранящиеся в этом файле конфигурации: '
1234567891011121314151617181920212223242512345678910111213141516171819202122232425/*♦ maxique2.c **/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
♦include <gnome.h>
int main(int argc,char *argv[J)
{,
time_t timeval;
gnome_init("maxique2","1.0",argc,argv);
g_print("geometry width=%d\n", gnome_conf ig_get_int ( "/maxique/geometry/width"));
g_print("geometry height=%d\n",
gnome_config_get_int("/maxique/geometry/height")); g_print("geometry margin=%d\n",
gnome_config_get_int("/maxique/geometry/margin"));
g_print("id name=%s\n",
x gnome_config_get_string("/maxique/id/name")); g_print("id nickname=%s\n",
gnome_config_get_string("/maxique/id/nickname")); g_print("id show_menu=%s\n", gnome_config_get_bool("/maxique/id/show_menu") ? "true" : "false");
timeval = gnome_config_get_int("/maxique/id/time");
g_print("id time=%s",ctime(&timeval));
exit(0);
Функции с именами, начинающимися на gnome^conf ig_get_, используются для получения данных из файла конфигурации. Все данные в файле хранятся в виде строк символов, поэтому сама программа должна знать тип значений и производить требуемое преобразование, которое выполняется с помощью вызова соответствующей функции. Вывод программы выглядит следующим образом:
geometry width=8
geometry height=3
geometry marginal5•
id name=Homer1
id nickname= 1
id show_menu=true■
id time=Mon Jul 12 14:20:.44 1999
Сохранение и выборка вектора
Ключу можно присвоить не одно значение. Набор значений можно называть списком, массивом^ или вектором. В GNOME обычно используется термин вектор. Чтобы присвоить ключу список значений, необходимо создать массив строковых указателей. Массив строковых указателей и строки, на которые они указывают, размещаются в процессе чтения массива из файла конфигурации.
В приведенном ниже примере содержатся две функции. Одна создает массив и записывает его в файл конфигурации, а другая считывает данные из файла конфигурации и выводит, их на экран.-.
/** configvec.c ♦♦/"
#include <gnome.h> .
3
static void retrievevector();
static void storevector();
6
int main(int argc,char *argv[])
{
gnome_init("conf igvec","1.0",argc,argv);
storevector();
retrievevector();
exit(0);
>.
static void storevector()
{
gint user_count = 5;
const gchar *user_name[] = {
"fred",
"wilfprd",
"ship worth",.
-21"norton",
"maglin"
};
24
gnome_config_set_vector("convec/user/names",
user_count,user__name);
gnomeconfig_sync(); ,
}
static void retrievevector()
{
gint i;
gint user_count;
gchar **user_name;
34
gnome_config_get_vector("convec/user/list",’
&user_count,&user_name);
for(i=0; i<user_count; i++)
printf("%d: %s\n",i,user_name[i]);
g_strfreev(user_name);
}
Функция storeVector () из строки 14 сохраняет список имен в файле конфигурации с именем convec в категории user и с ключом list. Одно из пяти имен списка содержит пробел. Содержимое файла выглядит следующим образом:
[user]'
names^fred wilford shipW Worth norton maglin
Двойная обратная наклонная черта используется как управляющая последовательность, указывающая, что следующий символ не пробел, а часть имени. Функция retrievevector() из строки 29 считывает список имен и выводит каждое на экран. Под возвращаемый массив и его строки была выделена память, следовательно, необходимо вернуть ее системе, что и делается вызовом функции g_strf reev() в строке 39. Эта функция создана для удобства, она удаляет каждую строку массива, а затем и сам массив.
Типы данных в файле конфигурации
В табл. 19.1 перечислены различные типы данных, доступные для использования в файле конфигурации. Поскольку существует много разных способов манипулирования установками конфигурации, то существует целый ряд функций, предназначенных для работы с каждым типом. "
Таблица 19.1. Типы данных, хранимые и выбираемые из файлов конфигурации
ТипОписание
boolЦелое число с нулем, представляющим FALSE, и целое число, не равное
нулю, соответствующее TRUE. В файле хранится как "true" или "false".
float64-битное число с плавающей запятой (gdouble). Хранится в файле в виде
числа с десятичной запятой или, при необходимости, с экспонентой.
int32-битное целое число (gint). Хранится в файле в виде десятичных разрядов.3.
stringСтрока символов в формате ASCH. Может быть пустой (строка нулевой
длины) и также может содержать пробелы.
tra nslated_string Строка символов, которая может меняться в зависимости от текущих ..., языковых установок.
vectorСписок строковых значений в формате ASCII. Вектор может быть пустым;
каждое значение может содержать пробелы.
Ниже приведён список функций, работающих с файлами конфигурации. Все эти функции включают тип данных как часть своего имени.
Функции для типа bool
Эти функции записывают булевы значения (типа bool) в файл конфигурации:
void gnome_config_set^bool(char *path,gboolean val);
void gnome^config_private_set_bool(char *path,gboolean val);
Значение val определяет, будет ли строка, сохраняемая в файле конфигурации, ’’true” или ’’false”. Вы можете использовать следующие функции для выборки значений типа bool из файла конфигурации:
gboolean gnome_config_get_bool(char *path);•
gboolean gnome_config_get_bool_with_default(char *path, gboolean *def);.
gboolean gnomeconfigprivate_get_bool(char *path);
gboolean gnome_config_private_get_bool_with_default(char *path, gboolean *def);
Если указанное значение не обнаружено в файле конфигурации, то возвращается значение по умолчанию, равное FALSE. Если задан аргумент def, то значение типа gboolean, на которое он указывает, устанавливается равным TRUE при условии, что это значение найдено в файле. Если возвращается значение по умолчанию, то оно равно FALSE.
Функции для типа float
Эти функции записывают в файл конфигурации значения типа float:
void gnomeconfigsetfloat(char *path,gdouble val);
void gnomeconfigprivatesetfloat(char *path,gdouble val);
Значение val преобразуется в строку символов и записывается в файл конфигурации. Для выборки из файла конфигурации значений типа float используются следующие функции:-'
gdouble gnome_config_get_float(char *path);
gdouble gnome_config_get_float_with_default(char *path, ' gboolean *def);
gdouble gnome_config_private_get_float(char *path);
gdouble*gnome_config_private_get_float_with_default(chdr *path, gboolean *def);
Если указанное значение не обнаружено в файле конфигурации, то возвращается принятое по умолчанию значение 0.0. Если задан аргумент def, то значение типа gboolean, на которое он указывает, устанавливается равным TRUE при условии, что в файле обнаружено это значение. Если возвращается значение по умолчанию, то оно равно FALSE.
Функции для типа int
Эти функции сохраняют в файле конфигурации значения типа int:
void gnome_config__set_int(char *path,gint val);.
void gnome_config_private_set_int(char *path,gint val);
Значение val преобразуется в строку символов и записывается в файл конфигурации. Для выборки значений типа int из файла конфигурации используются следующие функции:'
gint gnome_config_getint(char *path);.
gint gnome_config_get_int_with_default(char *pathr gboolean *def);
gint gnomeconfig_private_get_int(char *path);
gint gnome_configprivate_get_int_with_default(char *path, gboolean *def);
Если указанное значение не обнаружено в файле конфигурации, то возвращается принятое по умолчанию значение 0. Если задан аргумент def, то значение типа gboolean, на которое он указывает, устанавливается равным TRUE, если в файле обнаружено это значение. Если возвращается значение по умолчанию, то оно равно FALSE.
Функции для типа string
Эти функции сохраняют в файле конфигурации значения типа string:
void gnome_config_set_string(char *path,gchar *val);
void gnome_config^private_set_string(char *path,gchar *val);
• Строка, на которую указывает val, сохраняется в файле конфигурации. Для выборки значения типа string из файла конфигурации используются следующие функции:
gchar *gпотереonfig^get^string(char *path);
gchar *gnome2config_get_string_with_default(char *path, gboolean *def);
gchar *gnome_config_private_get_string(char *path);-
gchar *gnome_config_private_get_string_with_default(char *path, gboolean *def);
Если указанное значение не обнаружено в файле конфигурации, то возвращается NULL. Если задан аргумент def, то значение типа gboolean, на которое он указывает, устанавливается равным TRUE при условии, что в файле обнаружено это значение. Если возвращается принятое по умолчанию значение, то оно равно FALSE.
Функции для типа translated_string
Эти функции сохраняют значения типа translated_string для текущего выбранного языка:
void gnome_config_set_translated_string(char *path,gchar *val);
void gnome_config_private_set_translated_string(char *path,
■gchar *val);
Строка, на которую указывает val, сохраняется в файле конфигурации. Для выборки значения типа translated_string из файла конфигурации используются следующие функции:
gchar *gnome_config_get_translated_string(char *path);
gchar *gnome_config_get_translated_string_with_default(
char *path,gboolean *def);
gchar *gnome_config_private_get_tranglated_string(char *path);
gchar *gnome_config_private_get_translated_string_with_default(
-• char *path,gboolean *def);'
Если указанное значение не обнаружено в файле конфигурации, то возвращается NULL. Если задан аргумент def, то значение типа gboolean, на которое он указывает, устанавливается равным TRUE при условии, что это значение обнаружено в файле. Если возвращается принятое по умолчанию значение, то оно равно FALSE.
Функции для типа vector
Эти функции сохраняют в файле конфигурации значения типа vector:
void gnome_config_set_vector(const char *path,int argc, const char *const argv[])
void gnome_config_private_set_vector(const char *path, int argc,const char *const argv[])-
Значение argc — это количество элементов массива. Каждый элемент массива указателей по имени argv содержит адрес строки символов, которая записывается в файл конфигурации.
void gnomeconfiggetvector(const char *path, int *argcp, char ***argvp)
void gnome_config_get_vector_with_default(
const char *path,int *argcp,char ***argvp,•
gboolean *def)
void gnome_config_private_get_vector(const char *path, int *argcp,char ***argvp)■
void gnomeconfig_private_get_vector_with_default( const char *path,int *argcp,char ***argvp, gboolean *def)
Если указанное значение не обнаружено в файле конфигурации, то возвращается пустой массив. Если задан аргумент def, то значение типа gboolean, на которое он указывает, устанавливается равным TRUE при условии, что это значение обнаружено в файле. Если возвращается принятое по умолчанию значение, то оно равно FALSE.
Интернационализация
Если ваше приложение понадобится перевести на другой язык (а при существующей на сегодняшний день сети Internet это вполне реально), то вы можете предпринять некоторые шаги для облегчения перевода. Если внутри вашего исходного кода будут корректно маркированы строки, которые необходимо будет перевести, процесс перевода может быть автоматизирован. Хотя для перевода каждой строки вашего текста на другой язык и требуется вмешательство человека, ваше приложение проверяет свое окружение, чтобы установить, какой язык использовать.
Рассматриваемый процесс достаточно прост. Следующий пример демонстрирует, как можно маркировать строки, чтобы они были доступны для перевода.
/** translate.с *♦/
#include <gnome.h>
3
tdefine PACKAGE "translate"
fdefine GNOMELOCALDIR "/usr/share/locale"
6
GtkWidget *makeBox();
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
‘
static gchar *labelstring = N ("Static string");
14
15 int main(int argc,char *argv[])'
{.
GtkWidget *window;
GtkWidget *box;
19
20bindtextdomain(PACKAGE,GNOMELOCALDIR);
21textdomain(PACKAGE);
22
23gnome_init("translate","1.0",argc,argv);
24window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
25gtk_container_set_border_width(GTKCONTAINER(window),.
2625);
27gtksignalconnect(GTK_OBJECT(window),"deleteevent",
28GTKSIGNALFUNC(eventDelete), NULL);
29gtk_signal connect(GTK_OBJECT(window),"destroy",
30GTKSIGNALFUNC(eventDestroy),NULL);
31
32box = makeBox();
33gtkcontaineradd(GTK_CONTAINER(window),box);
34gtkwidgetshow(window);
35gtk_main();
exit(0);.
}
GtkWidget *makeBox() {
GtkWidget *box;
GtkWidget *button;
41
.42 box = gtkvboxnew(FALSE,0);
gtk_widget_show(box);
44
45button = gtk_button_new_with_label(_("Inline string"));
♦46gtkboxpackstart(GTK_BOX(box),button,FALSE,FALSE,0);
. gtk_widget_show(button);
48
button = gtk_button_new_with_label(_(labelstring));
gtk_box_pack_start(GTKBOX(box),button,FALSE,FALSE,0);
gtk_widget_s how(button);
•
return(box);
}
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data) {
return(FALSE);
}-
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data) {
gtk_main_quit();
return(0);•
'63 }*
В строке 4 определение PACKAGE присваивает программе имя пакета. В пакет может входить не одно приложение. Любые строки, которые совместно используются несколькими приложениями, необходимо переводить только один раз, поскольку приложения используют одни и те же таблицы перекодировки. Определение GNOMELOCALDIR в строке 5 задает каталог, в котором будут содержаться файлы перевода. Это каталог расположен в таком месте, которое будет просматриваться программным обеспечением при необходимости выполнить трансляцию.
ПРИМЕЧАНИЕ
Обычно определения PACKAGE и GNkMELkCALKIR определяются в заголовочном файле, предназначенном для этой цели. Этот файл обычно именуется config.h и часто содержит эти и другие установки конфигурации. Система разработки программного обеспечения в GTK+ и GNkME имеет свои make-файлы, автоматически создающие config.h. Кроме того, можно создать определения, используя опцию -Кв командной строке компилятора.
Обращение к bindtextdomain () в строке 20 связывает имя пакета с каталогом, в котором будет осуществляться поиск, так что в случае возникновения любых запросов на перевод, известно, где искать. Функция textdomain () в строке 21 назначает текущее приложение указанному пакету.
Программа создает две кнопки, каждая из которых имеет текстовую метку (надпись). Первая метка объявляется как строка в кавычках (цитата) в строке 45. Метка объявляется как обычно, за исключением того, что она содержится внутри скобок макроса по имени _(). Именем макроса является символ подчеркивания; этот макрос маркирует строку для перевода. Вторая кнопка, создаваемая в строке 49, также имеет транслируемую метку, но на этот раз используется переменное имя. Макрос _() все еще требуется, но поскольку*
строка определяется в другом месте, необходим еще один дополнительный шаг. Строка объявлена в строке 13, и, потому что она должна маркироваться как подлежащая переводу, заключена в скобках в другом макросе с коротким именем N_().
Вот и все. Убедитесь, что вы пометили все строки, которые необходимо перевести, пропуская те, которые не должны переводиться, как например в строках 23 и 27. Если все ваши строки маркированы и ваше приложение переводится на другой язык, то все они переводятся и вставляются в таблицы.
В написании программы, которая будет переводиться на другой язык, есть один недостаток. Ваша программа очень ограничена в вопросах динамического создания строк. Если в процессе компиляции содержание строки неизвестно, то ее нельзя перевести на другой язык. Невозможно считать строку из файла или набранную пользователем и перевести ее для вывода на экран. Однако, используя функции printf () и sprintf (), можно комбинировать непереведенные и переведенные строки. Например, переводчик находит, что следующая строка нуждается в переводе:
"The last device in the list is %s\n"
Эту строку можно перевести, и она будет работать, как ожидалось, так долго, пока где-либо в строке остается %s. Процесс несколько усложняется, если в строке присутствуют две переменные. Например:
"Device number %d has been set to %s mode\n"
И эту строку можно перевести, но при этом переводчик должен позаботиться о том, чтобы порядок следования %d и %s остался неизменным, потому что именно в этом порядке появляются артументы при вызове функции.•
Выводы.
Большой набор установок окружения может быть сохранен в файлах на диске и использован для конфигурирования вашей программы. Сюда могут быть включены настройки цвета, пунктов меню, панелей инструментов и даже языка. В этой главе рассмотрены следующие основные положения:
# Можно создать отдельные настройки (установки) для каждого пользователя и единые для всех пользователей. Также существуют специальные средства для обеспечения безопасности данных конфигурации.
# Для сохранения и восстановления данных конфигурации существует стандартный API. Данные хранятся в формате ASCII и могут быть преобразованы в любой тип (или из любого типа) языка С внутри приложения.
* Два предопределенных макроса используются для маркировки текста приложения, подлежащего автоматическому переводу на другой язык в зависимости от окружения, в котором запущена программа.
Эта глава завершает вторую часть книги. Третья часть содержит более общую информацию, такую, как полный перечень виджетов. В первой из глав третьей части, в главе 20, рассматривается использование automake и autoconfig для автоматизации компиляции и компоновки.
^ Ссыпки и III механизмы
■ww****^*- В этой части
Глава 20: Конфигурация и компиляция
~ Глава 21: Виджеты GTK+.
< > ,Гм№22: Виджеты GNkME,
Глава 2$: Некоторые механизмы Linux
' Глава 24: Сравнительная анатомия: Win32 и GNkME
главаКонфигурация
20и компиляция'
'-•- ' '— - ' ^В ЭТ^^^ЙГ
< Инсталляция вашей копии системного исходного кода GNkME
Создание сценариев autoconfig и autogen, которые могут использоваться для построения ваших make-файлов
? Связь между сценариями, вашим исходным кодом и make-файлами
В этой главе описывается последовательность шагов, которые необходимо предпринять для настройки среды разработки приложений в GNkME и GTK+.
Существуют сотни способов настройки среды, или окружения, а также разработки приложений. Причем make-файлы, описываемые в этой книге, достаточно просты и ими легко пользоваться. Именно из-за их простоты в больших проектах они становятся громоздкими. Ручное обновление make-файлов может стать сложным и при этом легко допустить ошибку. Имеется несколько способов автоматизации процесса компиляции и компоновки, но в GNkME используется пол у стандартная форма, поэтому имеет смысл скопировать эти методы и использовать их в ваших GNKME-приложениях.
Даже при использовании этой конфигурации все равно приходится поддерживать некоторые файлы вручную. Но после того как выполнены все настройки, изменять и дополнять приходится на удивление мало. Например, чтобы изменить номер версии компилируемой системы, вам необходимо ввести новый номер всего в одном месте, и он автоматически будет вставлен в код заголовочного файла. Если вы добавляете новый исходный модуль, то его имя необходимо ввести лишь в одном месте в одном файле. В результате определяются все его зависимости и модуль компилируется вместе с остальным кодом.
Инсталляция исходного кода GNOME
Для разработки приложений в среде GNOME необходимо иметь доступ к исходному коду GNOME. Он входит в комплект поставки, поэтому, если у вас уже установлен GNOME, вероятно, установлен и его исходный код.
Одним из самых важных преимуществ открытого исходного кода является возможность заглянуть вовнутрь функции и увидеть, что же на самом деле делается при ее вызове. Документация по открытому исходному коду отстает от программирования самого кода и иногда настолько, что ее просто нельзя найти. Даже если у вас есть документация, в ней как раз может отсутствовать именно то, что вас больше всего интересует. По этой самой причине необходимо всегда держать под рукой исходный код, который поможет вам выбраться из затруднительной ситуации.
ПРИМЕЧАНИЕ
Одна из важнейших причин использования исходного кода —- это предотвращение утечек памяти. Например, если функция возвращает указатель на строку, то необходимо знать, является1 ли возвращаемый указатель адресом статической строки или под строку выделялась память. В последнем случае, если не освобождать выделяемую под строку память, возникает memory leak (утечка памяти). Если вы попытаетесь освободить память, выделенную под статическую строку, возникает runtime error (ошибка периода выполнения).
В настоящей главе описана организация, соответствующая используемой в GNOME и GTK+. Просматривая каталоги исходного кода, вы можете найти примеры, описанные в настоящей главе. Это обогатит вас полезными идеями относительно структуры и возможностей.
Установка каталога для разработки
Создание каталога, в котором будет производиться разработка, является первоочередной задачей. Этот каталог будет содержать некоторые основные файлы конфигурации и сценарии, используемые для конфигурирования и управления компиляцией. Он также содержит подкаталоги, в которых находятся некоторые системные макросы и исходный код ваших приложений.
Кое-что необходимо сделать только один раз. После установки начального каталога легко добавлять новые проекты. Такая структура позволяет при необходимости добавлять исходный код для новых систем и подсистем. Конечно, вы не должны производить все ваши разработки в одном и том же дереве каталогов, но поскольку всегда необходимо сделать некоторые начальные настройки, то имеет смысл выполнять их единообразно. Добавление нового проекта разработки программного обеспечения к существующей конфигурации сводится к добавлению одного или двух подкаталогов, записи исходного кода в этот новый каталог и заданию настроек конфигурации таким образом, чтобы нужный каталог можно было отыскать и исходный код компилировался.
Минимальное содержимое корневого каталога разработки включает следующие файлы и каталоги:
AUTHORSMakefile.amacconfig.hhelloauto/
ChangeLogNEWSautogen.sh*macros/
IDGBIBLEREADMEconfigure.in
Все эти файлы и каталоги макросов рассмотрены в последующих разделах настоящей главы. Каталог helloauto содержит исходный код, который необходимо откомпилировать, и файл Makefile «ат.
Макросы
Существует целый ряд макросов, которые используются в сценариях конфигурации. Некоторые из них довольно простые и выполняют, например, проверку наличия компилятора или определяют одну или две переменных окружения, другие же — довольно сложные и осуществляют такие операции, как извлечение текста, подлежащего переводу, или создание заголовочного файла, который включается во все приложения. Для применения макросов существует сценарий autogen. sh, выполняющий большую часть работы, связанную с созданием make-файлов.
Макросы отыскиваются в подкаталоге macros исходного дерева GNOME. Попробуйте найти их либо в gnome/gnome-libs/macros, либо в gnome/gnome-core/macros. Вы можете обнаружить их в том и в другом каталоге, но в таком случае они идентичны. В будущих версиях макросы могут находиться в другом месте.
Скопируйте содержимое полного каталога macros в ваш каталог для разработки.
Файл configure.in
autoconf обрабатывает содержимое файла configure.in и создает сценарий configure. Макросы, которые находятся в файле configure.in, проверяют наличие и правильность некоторых обязательных элементов, устанавливают флаги компилятора, генерируют make-файлы и создают файл conf ig.h, а также выполняют некоторые другие действия для подготовки к компиляции.
Существует множество макросов. В табл. 20.1 перечислены наиболее часто используемые при настройке среды разработки GNOME. Для получения дополнительной информации по макросам воспользуйтесь одной или обеими следующими командами:
info autoconf
info automake
Макросы, начинающиеся на АС, предназначены для autoconf, а макросы, начинающиеся на АМ, — для automake.
Таблица 20.1. Макросы, которые могут использоваться в configure.in
Макрос
Описание
AC_ARG_PRkGRAM
Обеспечивает возможность изменения имени программы во время инсталляции.
AC_HEAKER_STC'
Проверяет наличие стандартных заголовочных файлов С. В действительности, он проверяет наличие нескольких файлов и предполагает, что все остальные присутствуют.
AC_INIT (имя файла)
Всегда является первым макросом в файле. Считывает командную строку и определяет некоторые имена, используемые в других макросах. Передаваемое макросу имя,может быть именем любого файла каталога, это всего лишь проверка, что он запущен в правильном каталоге.
AC_kUTPUT ac_prkG_c
Список всех файлов, которые будут произведены.
Определяет, какой компилятор С использовать. Если переменная окружения СС еще не установлена, ищет дсс, • затем сс и в соответствии с результатами поиска устанавливает переменную СС.
АС_ PRkG_CXX
Определяет, какой компилятор C++ использовать. Если переменная окружения СХХ не установлена, проверяется переменная ССС, а затем производится поиск компилятора на диске по следующим вероятным именам: с++, д++, дсс, СС, схх и с++. По умолчанию имя компилятора — ус.
АС—SUBST (имя)
Создает выходную переменную из переменной оболочки. Имя переменной и ее значение включаются во все создаваемые make-файлы.
Таблица 20.1. (продолжение)
Макрос
Описание
ALLJJNGUAS="/1 U /3 ..."
AM_ACLkCALJNCLUKE (каталог)
AM_CkNFIG_HEAKER (имя файла)
AM_GNU_GETTEXT
AMJNIT_AUTkMAKE (имя, версия)
AM_MAINTAINER_MkKE
AM_PRkG__LIBTkkL
GNkME_CkMPILE_W ARNINGS
GNkMEJNIT
GNkME_X_CHECKS•
Это не макрос, а переменная окружения, содержащая список аббревиатур для всех языков, на которые это приложение переводится.
Имя каталога, в котором содержатся файлы макросов ш4. Обычно этот подкаталог находится в подкаталоге macros корневого каталога вашего дерева разработки. Утилита ш4 — это стандартный макропроцессор Linux.
Имя создаваемого заголовочного файла. Обычно называется config. К.
Выполняет некоторые обязательные начальные действия для интернационализации.,
Используя указанное имя, определяет PACKAGE и, используя указанный номер версии, определяет VERSIkN. Имя и номер версии — просто строки, не имеющие специального формата.
Запрещает создание файлов, которые предназначены * только для сопровождения программного обеспечения.
Требуется только в случае, когда выводом является разделяемая (совместно используемая) библиотека, созданная libtool.
Устанавливает число полезных предупреждений периода компиляции для компилятора дсс.
Определяет набор флагов компилятора, специфичных для GNkME.
Проверяет наличие Х11 и устанавливает переменные маршрутов (путей). Этот макрос также может устанавливать и очищать флаги, которые используются при компиляции и компоновке исходных кодов.•
Ниже приведен пример содержимого файла configure «in.
AC_INIT(helloauto/helloauto.с)
AMCONFIGHEADER(config.h)
AM_INIT_AUTOMAKE(HelloAuto,1.0)-
AM_MAINTAINER_MODE .
AM_ACLOCAL_INCLUDE(macros)
GNOME_INIT
ACISCPOSIX
ACPROGCC
ACHEADERSTDC
ACARGPROGRAM
ACPROGCXX
AM_PROG_LIBTOOL 1GNOME COMPILE WARNINGS
GNOME X CHECKS
GNOME_GHTTP_CHECK
ALL_LINGUAS="de en_GB es" AM_GNU_GETTEXT
AC SUBST(CFLAGS)'
AC^SUBST(CPPFLAGS)
AC_SUBST(LDFLAGS)
AC_OUTPUT([
Makefile macros/Makefile helloauto/Makefile ])
Текстовые файлы
В табл. 20.2 перечислены хранящиеся в корневом каталоге текстовые файлы с документацией на систему. Вы также можете обнаружить файлы с такими именами в подкаталогах, в которых хранится исходный код.
Таблица 20.2. Некоторые общепринятые файлы с документацией .
Имя файла Содержимое
AUTHkRS
Список имен авторов программного обеспечения. Часто также содержит адреса электронной почты.
BUGS
Если существуют проблемы, связанные с кодом и способные создать сложности, имеет смысл создать специальный файл, описывающий проблему.
CkPYING
Информация по авторским правам. В деревьях с исходным кодом GNkME и GTK+ можно найти несколько таких файлов. В некоторых из них имеются небольшие отличия, таким образом, вы можете скопировать файл, который наиболее вам подходит, и, если желаете, сделать ваш собственный вариант. Однако если вы вносите такие изменения, что ваше приложение больше не является GNU (условия его распространения не соответствуют общедоступной лицензии GNU), вы не можете утверждать обратного.
KEPENKS
Если компиляция зависит от наличия чего-либо вне этого дерева исходного кода, например, от специальной библиотеки, вы можете перечислить это в данном файле.‘1
HACKING
Информация, содержащаяся в этом файле, предназначена для того, кто хочет внести какие-либо изменения в исходный код и откомпилировать его. В нем перечислены необходимые для этого специальные утилиты и процедуры. Часто в таком файле указаны инструкции по компиляции и предупреждения.
INSTALL
В этом файле содержатся процедуры, необходимые для инсталляции двоичных выполняемых файлов.
NEWS
Всякий раз при внесении изменений, добавлении новых возможностей, обнаружении ошибки тестируется программное обеспечение и объявляется новый номер версии; вся эта информация вносится в начало файла. При внесении в этот файл данных о новой версии он становится ее журналом регистрации.
REAKME
TkKk
Этот файл содержит описание программного обеспечения.
В системе любой сложности всегда есть, что делать. Этот файл содержит список того, что можно (или необходимо) сделать, чтобы улучшить программное обеспечение.,
Сценарии устанавливаются для проверки некоторых из указанных файлов. Они не считывают содержимого файлов, так что если на данный момент вам нечего сказать, можно просто создать пустые файлы AUTHORS, ChangeLog, NEWS и README.
Ограничиваться файлами, указанными в табл. 20.2, вовсе не обязательно. Например, можно использовать файл по имени DESIGN, или ALGORITHM, который объясняет теоретические основы перед функционированием наименее ясных для понимания частей программы. Текстовые файлы распознаются по заглавным буквам их имени. В приведенном примере представлен текстовый файл IDGBIBLE.
Также имеется файл ChangeLog, который вначале бывает пустым или вообще отсутствует. Он остается пустым, пока не будет выпущена первая версия программы (альфа- версия или какая либо другая). После этого регистрируется каждое изменение в соответствии с исходным файлом, датой и программистом, с кратким описанием внесенного изменения или изменений. Файл NEWS, как правило, описывает изменения с точки зрения пользователя, а файл ChangeLog — внутренние изменения, сделанные программистом.
Файл acconfig.h
В каталоге исходного кода создайте файл acconfig.h. Это шаблон (образец), применяемый для создания файла conf ig.h. В действительности программа autoheader считывает файл acconfig.h для создания файла config.h.in. Далее программа autoconf использует conf ig.h. in для получения файла conf ig.h. Именно этот файл conf ig.h должен быть включен в исходный код вашего приложения.
Несмотря на то что файл acconfig.h имеет расширение .h и его синтаксис соответствует синтаксису препроцессора С, тем не менее он не включается напрямую в файл исходного кода. Этот файл содержит только последовательность операторов tundef. Для каждой переменной, которую вы хотите определить в config.h, имеется свой оператор tundef.
Файл acconf ig. h, как минимум, должен содержать описания пакета и версии, а также и некоторые другие. Каждое описание именуется в операторе tundef. Для успешной генерации make-файла необходимы еще некоторые другие описания типа tundef. Далее приведено содержимое файла acconf ig. h в минимальном варианте:
/♦ acconfig.h */
lundef ENABLE_NLS lundef HAVE^CATGETS lundef HAVEGETTEXT lundef HAVE_LC_MESSAGES lundef HAVESTPCPX lundef HAVE_LIBSM
lundef PACKAGE lundef VERSION
Сценарий autogen.sh
Вам необходимо создать в вашем каталоге сценарий autogen.sh. Другой сценарий с таким же именем имеется в каталоге макросов, но это два разных сценария, autogen. sh из каталога макросов достаточно обширный и выполняет полностью всю работу по созданию make-файлов. А сценарий, который вы создаете в вашем каталоге, делает несколько более простую проверку и исполняет autogen. sh из каталога macros.
#i/bin/sh
I Run this to generate all the initial makefiles, etc.
srcdir*'dirname $0*.
test -z "$srcdir" 66 srcdir*.
PKG_NAME»"Hello Auto"
(test -f $srcdir/configure.in \
66 test -f $srcdir/IDGBIBLE \
66 test -d $srcdir/helloauto) || {z
echo -n "**Error**: Directory "\* $srcdir\'"" echo -n "does not look like the" echo " helloauto development directory" exit 1
}
. $srcdir/macros/autogen.sh
Переменная окружения srcdir установлена в значение текущего каталога. Переменная PKG^NAME используется для присвоения всему пакету имени, то есть имени программного обеспечения, которое получается в результате компиляции всех исходных кодов из всех подкаталогов. В примере присутствует два оператора test, которые служат лишь для проверки, запущен ли сценарий в текущем каталоге и содержит ли текущий каталог все необходимое. В частности, наличие файла по имени IDGBIBLE и каталога helloauto указывает, что сценарий расположен в требуемом месте.
Ваш autogen.sh завершается исполнением сценария autogen.sh из подкаталога макросов. Объем вывода при этом довольно большой. Текст выводится как в stdout, так и в stderr. Взгляните на этот вывод, это полезно для понимания происходящих процессов, но поскольку во время работы сценария создается довольно большой объем текста, для его сохранения можно сделать следующее:
autogen.sh > fred 2>61
Если все идет успешно (по крайней мере, если сценарий "полагает", что все прошло успешно), то последней напечатанной строкой будет: ’’Enter ’make’ to compile Hello Auto”.
Главный файл Makefile.am
Вам необходимо будет создать в главном каталоге разработки файл Makefile.ат. Этот файл используется программой autoconf при создании файла Makefile, in, содержащего описание полного make-файла. Создаваемый Makefile.in содержит информацию, необходимую для компиляции и компоновки всей системы с нуля. Он также содержит специальный набор инструкций, которые отменяют действие компиляции и компоновки (make clean), инсталлируют ранее откомпилированное программное обеспечение (make install) и создают дистрибутивный пакет (make dist). Кроме того, программа autoconf сканирует исходный код и определяет все зависимости (в какие другие файлы исходного кода какие заголовочные файлы включены), которые необходимы для создания конечного make-файла.'
Точное содержимое файла Makefile.ат зависит от количества включаемых подкаталогов. В приведенном далее примере включаются два подкаталога: исходного кода под названием helloauto, а также macros, содержащий локальные копии макросов:
SUBDIRS*macros helloauto
EXTRA DIST*IDGBIBLE
В файле Makefile «ат содержится список определении макросов, который используется в качестве входных данных для automake. Файл верхнего уровня Makefile.аж обычно совсем простой по сравнению с аналогичными файлами, расположенными в каталогах исходного кода. Имя SUBDIRS — это разделенный пробелами список имен подкаталогов, в которых находятся другие Makefile earn. Все эти файлы могут содержать имена других подкаталогов, в которых находятся файлы Makefile, аж Хотя возможно указать каталог более чем одного уровня глубиной, легче поддерживать систему, имеющую в каждом подкаталоге один Makefile .ат. Имя EXTRA^DIST определено как разделенный пробелами список файлов текущего каталога, которые необходимо включить вместе с двоичными файлами как часть дистрибутива программного обеспечения.
Каталог исходного кода
Создайте каталог для вашего исходного кода. Если в вашей среде разработки содержится исходный код нескольких программ или библиотек, то вы, возможно, захотите создать отдельные подкаталоги для исходных кодов каждой части: один для каждой выполняемой программы и один для исходного кода каждой библиотеки и т.д. Организация дерева каталогов должна отражать взаимосвязи между файлами. Этй подкаталоги могут, в свою очередь, содержать другие подкаталоги и каждый из них может быть включен как часть процедур автоматизации.
В каждом из этих подкаталогов имеется Makefile.ай, используемый для генерации make-файла.•
Подчиненный файл Makefile.am
В каждом каталоге исходного кода должен быть файл Makefile «ат, используемый для генерации make-файла. Далее приведен образец файла Makefile.am, который компилирует два файла исходного кода (helloauto.с и agbargraph.с) и компонует их вместе для создания выполняемой программы (helloauto).
INCLUDES = \.
-1$(top_srcdir) \
-1$(includedir) \.'.
-DGNOMELOCALDIR=\" " $ (datadir)/locale"\" \ -DG_LOG_DOMAIN=\"HelloAuto\" \
$(GNOME_INCLUDEDIR)
binPROGRAMS = \
helloauto
helloauto_SOURCES = \'
helloauto.c \ agbargraph.c \ agbargraph.h
helloauto LDADD = \
$(GNOMBUI_LIBS) \
$(GNOMB_LIBDIR) \ $(INTLLIBS)
Переменная INCLUDES используется для указания набора флагов, передаваемых компилятору. .•
Каталоги для Поиска включаемых файлов здесь появляются с опцией -I, но можно использовать и любые другие флаги командной строки компилятора. В приведенном примере для задания двух переменных окружения используется опция -D.
Переменная bin_PROGRAMS устанавливает имя выходного двоичного файла или файлов, создаваемых make-файлом.
Переменная helloauto_SOURCES указывает файлы исходного кода, используемые для создания двоичного выходного файла helloauto. Используя эту информацию, генерируется make-файл, который проверяет все указанные файлы на корректность зависимостей.
Переменная helloauto_LDADD задает список библиотек, которые отыскиваются для разрешения внешних ссылок в файлах, составляющих helloauto.
Вы можете добавить другие программы в этот же файл путем включения их имен в список переменной bin^PROG^AMS и добавления новых элементов SOURCE и LDADD. Кроме того, если вы желаете иметь подкаталоги исходных файлов, то можно использовать определение SUBDIRS для указания правильного каталога. Значит, чтобы добавить новый каталог к вашему исходному дереву, просто создайте файл Makefile «ат в но- - вом каталоге исходного кода и добавьте элемент SUBDIRS в файл Makefile.ат родительского каталога.'
* Запуск сценария autogen.sh
Процесс компиляции проводится в два этапа. Сначала запускается сценарий из корневого каталога разработки:
autogen.sh
Это добавляет ряд файлов в корневой каталог разработки. Какие именно файлы добавляются, зависит в первую очередь от установок и сделанного ранее выбора. Например, если вы используете ALL^LINGUAS для настройки перевода, то создаются подкаталоги ро и inti, в которых будут храниться переведенные строки.
После запуска сценария наберите:
паке
Эта команда компилирует и компонует файлы во всем дереве каталогов. Если вы находитесь в одном из исходных подкаталогов, то введенная команда make компилирует только то, что находится в текущем каталоге и ниже (во вложенных в него подкаталогах).'
Причем make-файлы сравнивают даты исходных и объектных файлов, поэтому, если вы компилируете вновь, включаются только измененные файлы. Тем не менее, удалив объектные файлы, можно выполнить и полную компиляцию. Для удаления всех объектных файлов и всех других файлов, создаваемых при компиляции, введите:
паке clean
При разработке приложения и добавлении новых исходных файлов приходится модифицировать соответствующий файл Makefile.ат и затем исполнять autogen.sh для включения нового исходного файла.
После успешной компиляции можно инсталлировать выполняемые файлы:
nake install
Выводы
Процесс настройки автоматической компиляции немного усложнен, но награда за это приходит позже, при разработке программного обеспечения. Все зависимости между вашими исходными файлами отслеживаются автоматически, а для компиляции и компоновки ваших программ будет использоваться правильный и полный набор команд. Как детально обсуждается в настоящей главе, следует выполнить следующие шаги:
Создайте каталог разработки, содержащий необходимый набор файлов и каталогов. Он также может содержать копии макросов, входящих в комплект программного обеспечения разработки GNOME.,
S Создайте файл configure. in, который содержит в случае использования макросов базовое описание вашего проекта. Кроме того, создайте файл acconfig.h, используемый в качестве шаблона при создании файла config ,h.
# Создайте простой сценарий autogen • Sh, используемый для нахождения зависимостей и генерации make-файлов.'
Создайте файл Makefile.am, в котором перечисляются имена исходных файлов, используемых в качестве входных, и имена создаваемых объектных файлов, один из которых появляется в каждом каталоге дерева разработки.
Две следующие гл^вы являются справочными (предназначены для ссылок). В главе 21 содержится список виджетов GTK-F, а в главе 22 — список виджетов GNkME. Многие из них ранее использовались в программах настоящего издания, а для тех, которые еще не использовались, приведены небольшие примеры.
468468
468
468
Виджеты GTK+
ф Перечень и описание виджетов и других объектов GTK+
ф Определение всех сигналов и функций, которые заданы для объекта 1
ф Определение всех унаследованных функций, доступных объекту, путем рассмотрения его места в иерархии
ф Задание перечислимых констант (энумераторов), используемых для передачи функциям установок конфигурации
ф Начинаем с включения простого примера каждого объекта
В этой главе приведен перечень объектов GTK+ в алфавитном порядке. Большинство объектов — это виджеты, но имеется несколько объектов, порожденных напрямую от класса GtkKbject. В описании каждого элемента приведены иерархия наследования и все функции, доступные вашему приложению.
Вы можете использовать любой виджет как базовый для создания другого виджета, но не все виджеты могут отображаться на экране, некоторые предназначены для применения лишь в качестве базовых классов. Если в классе нет функции, имя которой заканчивается на _new (или где-нибудь в имени присутствует _new_) и которая возвращает указатель на вновь созданный виджет, то этот класс можно использовать только как базовый. .
Образец кода, приведенный для каждого виджета, — это функция, которая создает отображаемый виджет и возвращает указатель на него. Основные части всех программ, отображающих виджеты, очень похожи. Следующий пример приведен для виджета GtkEntry:
/** xgtkentry.c **/
Iinclude <gnome.h>
gint eventDelete(GtkWidget *widget, GdkBvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget, GdkBvent *eveht,gpointer data);
static GtkWidget *makeWidget();
int main(int argc,char *argv[]) {
GtkWidget *app;
GtkWidget *widget;
gnome_init("xgtkentry","1.O",argc,argv);1
app = gnome_app_new("xgtkentry","GtkBntry");-
gtk_container_set_border_width (GTK_COWTAINER (app), 20);' k .
gtk_signal_connect(GTK OBJECT(app),"deleteevent*, GTK_SIGNAL_FUNC(eventDelete),WULt); gtk_signal_connect(GTK_OBJECT(app),"destroy",A
GTKSIGNALFUNC(eventDestroy),NULL);
widget * makeWidget();_
gnome_app_set_contents (GNOMEAPP (app),widget); gtk_widget_show_all(app); gtk_main();
exit(O); }•
gint eventDelete(GtkWidget *widget, GdkEvent *event,gpointer data) {"
return (FALSE);-
} gint eventDestroy(GtkWidget *widget, GdkEvent *event,gpointer data) { gtk_main_quit(); return(O);
}
static GtkWidget *makeWidget() {'
GtkWidget ♦widget; widget = gtk_entry_new_with_max_length(40); gtk_entry_set_text(GTK_ENTRY(widget),"Edit ae1"); return(widget);
}
В ряде мест могут наблюдаться некоторые отличия. Например, виджеты, которые заключают сами себя в свое собственное окно верхнего уровня и таким образом управляют своими действиями, не возвращают указатель. Если вы Просмотрите исходный код на CD-ROM (на компакт-Диске) или Скопированный с Web-сайта, то сможете найти полную программу для каждого примера, а не только короткие фрагменты, приведенные в настоящей главе.- -
GtkAccel Label■■
Этот виджет-метка считывает и отображает клавишу-акселератор (accelerator key) из другого виджета* В том случае, если он вообще что-то отображает, это будет текст, используемый при его создании, пока не назначен виджет с клавишей-акселератором.
ПРИМЕЧАНИЕ НАУЧНОГО РЕДАКТОРА.
Accelerator key — клавиша или комбинация клавиш, применяемая для ускорения доступа к предоставленным программой возможностям.
Иерархия • GtkAccelLabel->GtkLabel->GtkMi8c->GtkWidget->Gtk0bject.
Функции
guint gtk_accel_label_get_accel^width(GtkAccelLabel *accel_label) GtkType gtk_accel_label_get_type (void)
GtkWidget *gtклассеl_label_new(const gchar *string) gboolean gtk_accel_label_refetch(GtkAccelLabel *accel_label) void gtk_accel_label_set_accel_widget(
GtkAccelLabel *accel_label, GtkWidget *accel_widget)
Сигналы
■changed"void cb(GtkWidget *, gpointer)
"value_changed"void cb(GtkWidget *, gpointer)
Label StringLabel StringРисунок 21.1.Виджет GtkAccelLabel, отображающий строку текста, принятую по умолчаниюРисунок 21.1.Виджет GtkAccelLabel, отображающий строку текста, принятую по умолчаниюСледующий пример демонстрирует окно, показанное на рис. 21.1.
Label String
Label String
Рисунок 21.1.
Виджет GtkAccelLabel, отображающий строку текста, принятую по умолчанию
Рисунок 21.1.
Виджет GtkAccelLabel, отображающий строку текста, принятую по умолчанию
static GtkWidget *makeWidget()
{
GtkWidget *widget;
widget =gtk_accel_label_new("Label String"); return(widget);
}
GtkAdjustment
Этот объект хранит геометрические данные, например, верхнюю и нижнюю границы, шаг и размер страницы. Объект GtkAdjustment используется другими объектами для хранения их внутренних установок размерностей. Кроме того, он передается в качестве аргумента для задания геометрии объекта.
Обращение к функции gtk_adjustment_changed() генерирует сигнал ’’changed”, а к функции gtk_ad justment_value_changed() — сигнал ”value_changed”, если после выдачи последнего сигнала было отмечено изменение какого-либо значения.
Иерархия
GtkAdjustment->GtkData->GtkObj ect
Функции..
void gtk_adjustment_changed(GtkAdjustment *adjustment)
void gtk_adjustment_clamp_page(GtkAdjustment *adjustment, gfloat lower, gfloat upper)
GtkType gtk_adjustment_get_type (void)
GtkObject *gtk_adjustment_new(gfloat value, gfloat lower,
gfloat upper, gfloat step_increment, gfloat page_increment, gfloat page_size)
void gtk_adjustment_set_value(GtkAdjustment *adjustment, gfloat value)
void gtk_adjustment_value_changed(GtkAdjustment *adjustment)
Пример использования пары объектов GtkAdjustment для управления полосами прокрутки, вертикальной и горизонтальной, приведен в разделе ’’Слоистый контейнер” главы 5.
GtkAlignment . '
Виджет-контейнер, позволяющий управлять размерами одного дочернего виджета. Значения коэффициента масштабирования лежат между 0.0 и 1.0, указывая, насколько максимально может быть расширен дочерний виджет, чтобы заполнить пространство, выделяемое относительно виджета GtkAlignment. Установленные значения определяют ко-
ординаты х и у положения дочернего виджета относительно верхнего левого и нижнего правого углов прямоугольника GtkAlignment. Установленные значения лежат между 0.0 (для верхней или левой стороны) и 1.0 (для нижней или правой стороны).
Иерархия.
GtkAlignment->GtkBin->GtkContainer->GtkWidget->GtkObject -' -
Функции■
GtkType gtk_alignment_get_type(void)
GtkWidget *gtk_alignment_new(gfloat xalign, gfloat yalign, gfloat xscale, gfloat yscale)
void gtk-aUgnment—Set (GtkAlignment *alignment, gfloat xalign, gfloat yalign, gfloat xscale, gfloat yscale)
Я | GtkAlignment ^iW^bЯ | GtkAlignment ^iW^b[The Button Lat^[The Button Lat^The Button LabelThe Button LabelВ приведенном коде виджет GtkButton вставляется в виджет GtkAlignment. Значение х устанавливается равным 1.0, что смещает кнопку к правому краю, а значение у — 0.5, что центрирует кнопку по вертикали. Коэффициент масштабирования для обоих направлений установлен равным 0.15, что ограничивает размеры кнопки пятнадцатью процентами доступного ей пространства.
Я | GtkAlignment ^iW^b
Я | GtkAlignment ^iW^b
[The Button Lat^
[The Button Lat^
The Button Label
The Button Label
Рисунок 21.2.Виджет GtkAlignment управляет размерами и положением дочернего виджетаРисунок 21.2.Виджет GtkAlignment управляет размерами и положением дочернего виджетаНа рис. 21.2 слева показано окно принятого по умолчанию размера, когда виджет GtkAlignment приводит свои размеры в соответствие с требуемыми размерами кнопки. Справа показано то же окно после увеличения его размеров.
Рисунок 21.2.
Виджет GtkAlignment управляет размерами и положением дочернего виджета
Рисунок 21.2.
Виджет GtkAlignment управляет размерами и положением дочернего виджета
static GtkWidget *makeWidget() {
GtkWidget *alignment;
GtkWidget *button;
button = gtk_button_new_with_label("The Button Label");
alignment = gtk_alignment_new(1.0,0.5,0.15,0.15);:? r„
gtk_container_add(GTK_CONTAINER(alignment),button);
return(alignment);
GtkArrow
Простой стреловидный виджет, который может указывать вверх, налево, вниз или направо.1.
Иерархия
GtkArrow->GtkMisc->GtkWidget->GtkObject
Функции
GtkType gtkarгow_get_tyре(void) '
GtkWidget *gtk_arrow_new(GtkArrowType arrow_type,.
GtkShadowType shadow_type)
void gtk_arrow_set(GtkArrow *arrow, GtkArrowType arrow_type, GtkShadowType shadowtype)
Энумераторы
typedef enum {*"
GTKARROWUP,
GTK_ARROW_DOWN,
GTK ARROW LEFT,
GTKARROWRIGHT } GtkArrowType;
Рисунок 21.3.Виджет GtkArrow, указывающий налево и углубленный за счет затененияРисунок 21.3.Виджет GtkArrow, указывающий налево и углубленный за счет затененияtypedef enum { GTK_SHADOW_NONE, GTKSHADOWIH, GTKSHADOWOUT, GTK SHADOW_ETCHED_IN, GTK~SHADOW_ETCHED_OUT
Рисунок 21.3.
Виджет GtkArrow, указывающий налево и углубленный за счет затенения
Рисунок 21.3.
Виджет GtkArrow, указывающий налево и углубленный за счет затенения
} GtkShadowType;
Приведенная далее функция создает стрелку, указывающую налево, как показано на рис. 21.3, нарисованную так, что затенение создает эффект ее углубленности.
static GtkWidget *makeWidget()
GtkWidget ♦arrow;
arrow = gtk_arrow_new(GTK_ARROW_LEFT,GTK_SHADOW_IN); return(arrow);
GtkAspectFrame
Этот виджет-контейнер содержит один виджет в рамке с меткой (с надписью) и распространяет формат изображения (отношение ширины к длине) на дочерний виджет.
Иерархыия
GtkAspectFrame - >G tkFr ame - >GtkBin - >Gt kCon ta iner - >6 tkWidget - >GtkOb j ect
Функции
GtkType gtkaspectframegettype (void)
GtkWidget *gtk_aspect_frame_new(const gchar*label, gfloat xalign, gfloat уalign, gfloat ratio, gint obey_child)
void gtkaspect_frame_set(GtkAspectFrame *aspectframe, gfloat xalign, gfloat yalign," gfloat ratio, gint obeychild)
Приведенный пример заключает виджет GtkLabel внутри GtkAspectFrame. булева переменная obey_child установлена равной TROB, так что значение коэффициента (соотношение) игнорируется и определяется по размерам метки (надписи). Значения переменных xalign и yalign устанавливают предпочтительное положение как 60% расПриведенный пример заключает виджет GtkLabel внутри GtkAspectFrame. булева переменная obey_child установлена равной TROB, так что значение коэффициента (соотношение) игнорируется и определяется по размерам метки (надписи). Значения переменных xalign и yalign устанавливают предпочтительное положение как 60% рас
Приведенный пример заключает виджет GtkLabel внутри GtkAspectFrame. булева переменная obey_child установлена равной TROB, так что значение коэффициента (соотношение) игнорируется и определяется по размерам метки (надписи). Значения переменных xalign и yalign устанавливают предпочтительное положение как 60% рас
Приведенный пример заключает виджет GtkLabel внутри GtkAspectFrame. булева переменная obey_child установлена равной TROB, так что значение коэффициента (соотношение) игнорируется и определяется по размерам метки (надписи). Значения переменных xalign и yalign устанавливают предпочтительное положение как 60% рас
стояния от верхнего и от левого краев. На рис. 21.4 показано первое появление виджета и после изменения размеров. Окно растянуто по горизонтали больше, чем по вертикали. По сути, виджет изменяет свои размеры до максимально возможных при сохранении заданного соотношения сторон, оставляя 60% свободного пространства слева и 40% справа.
т**й#*РЙ* «Ь 'V Л»<45Й®
|tML6bBiTe»<|
у. jTheie«Tw -
Рисунок 21.4.
Рамка со всех сторон сохраняет формат изображения (соотношение сторон) дочерних виджетов
static GtkWidget «makeWidget() { GtkWidget *aspectframe;.
GtkWidget *label;
• label ■ gtk_label_new("The Label Text"); . aspectframe ■ gtk aspectframe new("Flable",.
0e6,0e6,170,TRUE);*
gtkcontaineradd(GTKCONTAINER(aspectframe),label);-
return(aspectframe);•
}
GtkBin
Это базовый класс для контейнера, содержащего только один дочерний виджет. Этому классу соответствует код, общий для всех виджетов, содержащих только один дочерний виджет.-
Иерархия
GtkBin->GtkContainer->GtkWidget->6tkObject
Функция.
GtkType gtk_bin_get_type(void)
GtkBox
Это базовый класс контейнеров GtkHBox и GtkVBox. Его код необходим для поддержания списка содержащихся виджетов, но не позиционирует их.
Иерархия *..
GtkBox->GtkContainer->GtkWidget->6tkObject
Функции,., .
GtkType gtk_box_get_type(void) . void gtk_box_pack_end(GtkBox «box, GtkWidget *chiId, gboolean expand, gboolean fill, guint padding) void gtk_box_pack_end_defaults(GtkBox *bo£, GtkWidget «child)- ■
void gtkboxpackstart(GtkBox *£ох, GtkWidget ♦child,.
gboolean expand, gboolean fill, guint padding) ' .
void gtk_box_pack_start_defaults(GtkBox «box, GtkWidget «child) void g^k_box_query_child_packing(GtkBox «box, GtkWidget «child, ,,
gboolean «expand, gboolean «fill, guint «padding,'
GtkPackType «packtype) ' '
void gtk_box_reorder_chiId(GtkBox.«box, GtkWidget «child, gint position)
. void gtk_box_set_child_packing(GtkBox «box, GtkWidget «child,•
gboolean expand, gboolean fill, guint padding, GtkPackType packtype)r
void gtk_box_set_homogeneous(GtkBox «box, gboolean homogeneous) . void gtk_boxset_spacing(GtkBox «box, gint spacing).
Энумератор-
typedef enum { GTK_PACK_START, GTKPACKEND } GtkPackType; ■1
GtkButton
Это окно с текстом или меткой в виде растрового изображения внутри рамки. Может реагировать на мышь.•
Иерархия .
GtkButton->GtkBin->GtkContainer->GtkWidget->GtkObject
Функции
void gtk_button_clicked(GtkButton *button) void gtk_button_enter(GtkButton *button) GtkReliefStyle gtk_button_get_relief(GtkButton *button) GtkType gtk_button_get_type(void) void gtk_button_leave(GtkButton *button) GtkWidget *gtk_button_new(void) GtkWidget *gtk_button_new_with_label(const gchar *label) void gtk_button_pressed(GtkButton *button) void gtk_button_released(GtkButton *button) void gtk_button_set_relief(GtkButton *button, GtkReliefStyle newrelief)
Эну мера top•
typedef enum {
GTK_RELIEF_NORMAL, GTK_RELIEF_HALF, GTK_RELIEF_NONEr } GtkReliefStyle;
Сигналы'
"clicked"void cb(GtkWidget *, gpointer)
"enter"void cb(GtkWidget *, gpointer)„
"leave"void cb(GtkWidget *, gpointer),
"pressed"void cb(GtkWidget *, gpointer)
"released"x void cb(GtkWidget *, gpointer)-
Объект GtkButton неоднократно использовался по всей книге, поэтому примеры его применения присутствуют почти в каждой главе. В частности, в главах 3 и 4.
GtkButtonBox
Базовый класс, содержащий общие функции для контейнеров GtkHButtonBox и GtkVButtonBox. Это виджеты-контейнеры, специально предназначенные для управления набором кнопок. GtkButtonBox имеет целый ряд функций управления, которые можно использовать для установки размеров и положения кнопок внутри контейнера.
Иерархия.
GtkButtonBox->GtkBox->GtkContainer->GtkWidget->GtkObject
Функции•
void gtk_button_box_child_requisition(GtkWidget *widgetr
int *nvis_children, int *width, int *height)'•
void gtk_button_box_get_child_ipadding(GtkButtonBox *widgetr'
gint *ipad_xr gint *ipad_y)
void gtk_button__box_get_child_ipadding_default(gint *ipad_x, gint *ipad_y)
void gtk_button_box_get_child_size(GtkButtonBox *widgetr•
gint *widthr gint *height)
void gtk_button_box_get_child_size default(gint *widthr gint *height)
GtkButtonBoxStyle gtk_button_box_get_layout ( GtkButtonBox *widget) gint gtk_button_box_get_spacing(GtkButtonBox *widget) GtkType gtk_button_box_get_type(void) void gtk_button_box_set_child_ipadding(GtkButtonBox *widget, * gint ipadx, gint ipad_y) void gtk_button_box_set_child_ipadding_default(gint ipad_x, gint ipad_y)•
void gtk_button_box_set_child_size(GtkButtonBox *widget,.
gint width, gint height) void gtk_button_box_set_child_size_default(gint width, gint height)•
void gtk_button_box_set_layout(GtkButtonBox *widget, GtkButtonBoxStyle layout_style) void gtk_button_box_set_spacing(GtkButtonBox *widget,.
gint spacing)
Энумератор typedef enum { GTK_BUTTONBOX_DEFAULT_STYLE, GTK_BUTTONBOX_SPREAD,.
GTKBUTTONBOXEDGE, GTK_BUTTONBOX_START, GTK_BUTTONBOX_END.
} GtkButtonBoxStyle;
GtkCalendar
Виджет GtkCalendar отображает один месяц (календарь). Пользователь может выбрать месяц, год, а затем и определенный день месяца.
Иерархия
GtkCalendar->GtkWidget->GtkObject
Функции■
void gtk_calendar_clear_marks(GtkCalendar *calendar) void gtk_calendar_display_options(GtkCalendar *calendar, GtkCalendarDisplayOptions flags) void gtk_calendar_freeze(GtkCalendar *calendar) void gtk_calendar_get_date(GtkCalendar *calendar, guint *year,'
guint *month, guint *day)
GtkType gtk_calendar_get_type(void) gint gtk_calendar_mark_day(GtkCalendar *calendar, guint day) GtkWidget *gtk_calendar_new(void)'
void gtk_calendar_select_day(GtkCalendar *calendar, guint day)-
gint gtk_calendar_select_month(GtkCalendar *calendar,,
guint month, guint year)''
void gtk_calendar_thaw(GtkCalendar ^calendar) gint gtk_calendar_unmark_day(GtkCalendar *calendar, guint day)
Энумератор typedef enum {.
GTK_CALENDAR_SHOW_HEADING, GTK_CALENDAR_SHOW_DAY_NAMES, GTK_CALENDAR_NO_MONTH_CHANGE, GTK_CALENDAR_SHOW_WEEK_NUMBERS, GTK_CALENDAR_WEEK_START_MONDAY } GtkCalendarDisplayOptions;
Рисунок 21.5.Отображаемый виджет GtkCalendarРисунок 21.5.Отображаемый виджет GtkCalendar, Всякий раз, когда создается новый виджет-календарь, в нем по умолчанию устанавливается текущая дата и время, как и показано на рис. 21.5.
Рисунок 21.5.
Отображаемый виджет GtkCalendar
Рисунок 21.5.
Отображаемый виджет GtkCalendar
static GtkWidget *makeWidget() {
GtkWidget *widget;
widget = gtk_calendar_new();
return(widget);
}
GtkCheckButton
Виджет GtkCheckButton отображает маленькую кнопку с расположенной рядом с ней меткой (надписью). С помощью мыши кнопка может быть включена или отключена и сохраняет свое состояние до следующего включения.
Иерархия
GtkCheckButton->GtkToggleButton->GtkButton->GtkBin->GtkContainer->
GtkWidget->GtkObj ect
Функции
GtkType gtk_check_button_get_type (void)
GtkWidget *gtk_check_button_new(void)
GtkWidget *gtk_check_button_new_with_label(const gchar *label)
Рисунок 21.6.Виджет GtkCheckButton с меткой (с надписью)Рисунок 21.6.Виджет GtkCheckButton с меткой (с надписью)В приведенном примере демонстрируется окно, представленное на рис. 21.6.
Рисунок 21.6.
Виджет GtkCheckButton с меткой (с надписью)
Рисунок 21.6.
Виджет GtkCheckButton с меткой (с надписью)
static GtkWidget *makeWidget()
. GtkWidget *widget;
widget = gtk_check_button_new_with_labeL( "Check Button Label");
return(widget);
GtkCheckMenultem'
Этот виджет отображает кнопку-переключатель и метку. Поскольку он является потомком GtkMenuItem, то предназначен для использования в меню в качестве кнопки- переключателя.
Иерархия
GtkCheckMenuItem->GtkMenuItem->GtkItem->GtkBin->GtkContainer-> GtkWidget->GtkObject
Функции-
GtkType gtk_check_menu_item_get_type(void)
GtkWidget *gtk_check_menu_item_new(void)
GtkWidget *gtk_check_menu_item_new_with_label(const gchar *label)
void gtk_check_menu_item_set_active(
GtkCheckMenultem *check_menu_item, gboolean is_active)
void gtk_check_menu_item_set_show_toggle(
GtkCheckMenultem *menu_item, gboolean always)
void gtk_check_menu_item_toggled(
GtkCheckMenultem *check_menu_item)
У ДаН□Check LabelУ ДаН□Check LabelРисунок 21.7.ВиджетGtkCheckMenuItem с отображаемой кнопкой-переключателемРисунок 21.7.ВиджетGtkCheckMenuItem с отображаемой кнопкой-переключателем
У ДаН
□Check Label
У ДаН
□Check Label
Рисунок 21.7.
Виджет
GtkCheckMenuItem с отображаемой кнопкой-переключателем
Рисунок 21.7.
Виджет
GtkCheckMenuItem с отображаемой кнопкой-переключателем
Сигнал "toggled" void cb(GtkWidget *, gpointer)
В этом примере выводится окно, показанное на рис. 21.7.
static GtkWidget *makeWidget() { GtkWidget *widget;
widget = gtk_check_menu_item_new_with_label( " Check Label");
gtk_check_menu_item_set_show_toggle( GTK_CHECK_MENU_ITEM(widget),TRUE);
return(widget); }
GtkCList
Виджет содержит один или несколько текстовых списков и позволяет пользователю выбрать одну или несколько строк. Большое количество функций управления делает этот виджет очень гибким.
Иерархия
GtkCList->GtkContainer->GtkWidget->GtkOb j ect
Функции
gint gtk_clist_append(GtkCList *clist, gchar *text [ ]) void gtk_clist_clear(GtkCList *clist) void gtk_clist_column_title_active(GtkCList *clist, gint column)
void gtk_clist_column_title_passive(GtkCList *clist, gint column)
void gtk_clist_column_titles_active(GtkCList *clist) void gtk_clist_column_titles_hide(GtkCList *clist) void gtk_clist_column_titles_passive(GtkCList *clist) void gtk_clistcolumn_titles_show(GtkCList *clist) gint gtk_clist_columns_autosize(GtkCList *clist) void gtk_clist_construct(GtkCList *clist, gint columns, gchar *titles [ ])
gint gtk_clist_find_row_from_data(GtkCList *clist, gpointer data)
void gtk_clist_freeze(GtkCList *clist)
GtkStyle *gtk_clist_get_cell__style(GtkCList *clist, gint row, gint column)
GtkCellType gtk_clist_get_cell_type(GtkCList *clist, gint row, gint column) gchar *gtk_clist_get_column_title(GtkCList *clist, gint column) GtkWidget *gtk_clist_get_column_widget(GtkCList *clist, gint column)
GtkAdjustment *gtk_clist_get_hadjustment(GtkCList *clist) gint gtk_clist_get_pixmap(GtkCList *clist, gint row, gint column, GdkPixmap **pixmap, GdkBitmap **mask) gint gtk_clist_get_pixtext(GtkCList *clist, gint row, gint column, gchar **text, guint8 *spacing, GdkPixmap **pixmap, GdkBitmap **mask)
gpointer gtk_clist_get_row_data(GtkCList *clist, gint row) GtkStyle *gtk_clist_get_row_style(GtkCList *clist, gint row) gboolean gtk_clist_get_selectable(GtkCList *clist, gint row)
gint gtk_clist_get selectioninfо(GtkCList *clist, gint x, gint y, gint *row, gint *column)
gint gtk_clist_get_text(GtkCList *clist, gint row, gint column, gchar **text)
GtkType gtk_clist_get_type(void)
GtkAdjustment *gtk_clist_get_vadjustment(GtkCList *clist)
gint gtk_clist_insert(GtkCList *clist, gint row, gchar *text [ ])
void gtk_clist_moveto(GtkCList *clist, gint row, gint column, gfloat row_align, gfloat col_align)
GtkWidget *gtk_clist_new(gint columns)
GtkWidget *gtk_clist_new_with_titles(gint columns, gchar *titles [ ])
gint gtk_clist_optimal_column_width(GtkCList *clist, gint column)
gint gtk_clist_prepend(GtkCList *clist, gchar *text [ ])
void gtk_clist_remove(GtkCList *clist, gint row)
GtkVisibility gtk_clist_row_is_visible(GtkCList *clist, gint row)
void gtk_clist_row_move(GtkCList *clist, gint source_row, gint dest_row)
void gtk_clist_select_all(GtkCList *clist)
void gtk_clist_select_row(GtkCList *clist, gint row, gint column)
void gtk_clist_set_auto_sort(GtkCList *clist, gboolean auto_sort)
void gtk_clist_set_background(GtkCList *clist, gint row, GdkColor *color)*
void gtk_clist_set_button_actions(GtkCList *clist, guint button, guint8 button_actions)
void gtk_clist_set_cell_style(GtkCList *clist, gint row, gint column, GtkStyle *style)
void gtk_clist_set_column_auto_resize(GtkCList *clist, gint column, gboolean auto_resize)
void gtk_clist_set_column_justification(GtkCList *clist, gint column, GtkJustification justification)
void gtk_clist_set_column_max_width(GtkCList *clist, gint column, gint maxwidth)*
void gtk_clist_set_column__min_width(GtkCList *clist,,
gint column, gint min_width)
void gtk_clist_set_column_resizeable(GtkCList *clist, gint column, gint resizeable)
void gtk_clist_set_column_title(GtkCList *clist, gint column, const gchar *title)
void gtk_clist_set_column visibility(GtkCList *clist, gint column, gboolean visible)
void gtk_clist_set_column_widget(GtkCList *clist, gint column, GtkWidget *widget)
void gtk_clist_set_column_width(GtkCList *clist, gint column, gint width)
void gtk_clist_set_compare_furlc(GtkCList *clist, GtkCListCompareFunc cmp_func)
void gtk_clist_set_foreground(GtkCList *clist, gint row, GdkColor *color)
void gtk_clist_set_hadjustment(GtkCList *clist, GtkAdjustment *adjustment)
void gtk_clist_set_pixmap(GtkCList *clist, gint row, gint column, GdkPixmap *pixmap, GdkBitmap *mask)
- void gtk_clist_set_pixtext(GtkCList *clist, gint row, gint column, const gchar *text, guint8 spacing, GdkPixmap *pixmap, GdkBitmap *mask)
void gtk_clist_set_reorderable(GtkCList *clist, gboolean reorderable)
void gtk_clist_set_row_data(GtkCList *clist, gint row, gpointer data)
void gtk_clist_set_row_data_full(GtkCList *clist, gint row, gpointer data, GtkDestroyNotify destroy)
void gtk_clist_set_row_height(GtkCList *clist, guint height) void gtk_clist_set_row_style(GtkCList *clist, gint row, GtkStyle *style)
void gtk_clist_set_selectable(GtkCList *clist, gint row, gboolean selectable)
void gtk_clist_set_selection_mode(GtkCList *clist, GtkSelectionMode mode)
void gtk_clist—Set_shadoW-type(GtkCList *clist, GtkShadowType type)
void gtk_clist_set_shift(GtkCList *clist, gint row,.
gint column, gint vertical, gint horizontal)
void gtk_clist_set_sort_column(GtkCList *clist, gint column) void gtk_clist_set_sort_type(GtkCList *clist, GtkSortType sort_type)
void gtk-Clist_set_text(GtkCList *clist, gint row, gint column, const gchar *text)
void gtk-dist_set_use-drag_icons(GtkCList *clist, gboolean use-icons).
void gtk-dist-Set-Vadjustment(GtkCList *clist, GtkAdjustment *adjustment)
void gtk-dist-Sort(GtkCList *clist)
void gtk-dist-Swap-rows(GtkCList *clist, gint rowl, gint row2) void gtk-dist-thaw(GtkCList *clist) void gtk-dist-UndO-Selection(GtkCList *clist).
void gtkclist_unselect_all(GtkCList *clist) void gtk-dist_unselect-row(GtkCList *clist, gint row, gint column)
Энумераторы typedef enum {
GTK—SHADOW—NONE,
GTK—SHADOW—IN,
GTK—SHADOW—OUT,
GTK_SHADOW—ETCHED—IN,
GTK—SHADOW—ETCHED—OUT } GtkShadowType;
typedef enum {
GTK_SELECTION—SINGLE, GTK—SELECTION—BROWSE, GTK—SELECTION—MULTIPLE, GTK_SELECTION—EXTENDED } GtkSelectionMode;
typedef enum {
GTK-SORT-ASCENDING,
GTK—SORT—DESCENDING•
} GtkSortType;
Сигналы
"aboгt_co1umn_rеsize" "click-Column" "end_selection" "extend_selection"
void cb(GtkWidget *, gpointer)
void cb(GtkWidget *, gint, gpointer)
void cb(GtkWidget *, gpointer)
void cb(GtkWidget *, GtkScrollType, gfloat, gboolean, gpointer)
"resize_column" "rowmove" "scroll-horizontal" "scroll-Vertical" "select-all" "select-row" "set-Scroll-adjustments"
void cb(GtkWidget *, gint, gint, gpointer) void cb(GtkWidget *, gint, gint, gpointer) void cb(GtkWidget ♦, GtkScrollType, gfloat, gpointer) void cb(GtkWidget *, GtkScrollType, gfloat, gpointer) void cb(GtkWidget *, gpointer)
void cb(GtkWidget *, gint, gint, GdkEvent *, gpointer) ' void cb(GtkWidget *, GtkAdjustment *,
GtkAdjustment ♦, gpointer)
"start-Selection" "toggle-add-mode" "toggle-focuS-row" "undO-Selection" "unselect-all" "unselect—row"
void cb(GtkWidget *, gpointer) void cb(GtkWidget *, gpointer) void cb(GtkWidget *, gpointer) void cb(GtkWidget *, gpointer) void cb(GtkWidget ♦, gpointer) void cb(GtkWidget *, gint, gint, GdkEvent *, gpointer)
Column 11 Column 2j Apple OrangeColumn 11 Column 2j Apple OrangeAirplane BirdAirplane BirdРисунок 21.8.Виджет GtkCList с двумя столбцами и заголовкамиРисунок 21.8.Виджет GtkCList с двумя столбцами и заголовкамиВ этом примере создается объект GtkCList с двумя столбцами и в каждый из них вставляются три строки данных. На рис. 21.8 показан объект с выбранной второй строкой. В него также включены необязательные заголовки столбцов, размер которых можно менять, перетаскивая указатель мыши между двумя кнопками.
Column 11 Column 2j Apple Orange
Column 11 Column 2j Apple Orange
Airplane Bird
Airplane Bird
Рисунок 21.8.
Виджет GtkCList с двумя столбцами и заголовками
Рисунок 21.8.
Виджет GtkCList с двумя столбцами и заголовками
static GtkWidget *makeWidget()
<
GtkWidget *widget;
static gchar *titles[] = { "Column 1","Column 2"
};'
static char *rowl[] = {
"Apple","Orange"
static char *row2[] = {
"Car"t"Truck"
};
static char *row3[] = { "Airplane","Bird"
widget = gtk_clist_new_with_titles(2,titles); gtk_clist_append(GTK_CLIST(widget),rowl); gtk_clist_append(GTK_CLIST(widget),row2); gtk_clist_append(GTK_CLIST(widget),row3);
return(widget);
GtkClock
Данный виджет — это таймер, ведущий отсчет как в сторону увеличения, так и в сторону уменьшения. Кроме того, с его помощью можно отображать текущее время.
Иерархия
GtkClock->GtkLabel->GtkMisc->GtkWidget->GtkObject
Функции
guint gtk_clock_get_type(void)
GtkWidget *gtk_clock_new(GtkClockType type)
void gtk_clock_set_format(GtkClock *clock, gchar *fmt)
void gtk_clock_set_seconds(GtkClock *clock, time_t seconds)
void gtk_clock_set_update_interval(GtkClock *clock,
gint seconds)
void gtk_clock_start(GtkClock *clock)
void gtk_clock_stop(GtkClock *clock)
Энумератор
typedef enum {
GTK_CLOCK_INCREASING,
GTK_CLOCK_DECREASING, GTK_CLOCK_REALTIME
} GtkClockType;
Рисунок 21.9.Виджет GtkClock, измеряющий ход времениРисунок 21.9.Виджет GtkClock, измеряющий ход времениВ примере создается таймер, ведущий отсчет с нуля в сторону увеличения. Как видно из рис. 21.9, приращение таймера — одна секунда.
Рисунок 21.9.
Виджет GtkClock, измеряющий ход времени
Рисунок 21.9.
Виджет GtkClock, измеряющий ход времени
static GtkWidget *makeWidget() <
GtkWidget *widget;
widget = gtk_clock_new(GTK_CLOCK_INCREASING);
gtk_clock_start(GTK_CLOCK(widget));
return(widget);
1
GtkColorSelection
Этот виджет дает информацию о цвете, так пользователь может с помощью мыши задать любой доступный цвет.
Иерархия
GtkColorSelection->GtkVBox->GtkBox->GtkContainer->GtkWidget->GtkObject
Функции
void gtk_color_selection_get_color(
GtkColorSelection *colorsel, gdouble *color)
guint gtk_color_selection_get_type(void)
GtkWidget *gtk_color_selection_new(void)
void gtk_color_selection_set_color(
GtkColorSelection *colorsel, gdouble *color)
void gtk_color_selection_set_opacity(
GtkColorSelection *colorsei, gint use_opacity)
void gtk_color_selection_set_update_policy(
GtkColorSelection *colorsel, GtkUpdateType policy)
Энумератор
typedef enum {
GTK_UPDATE_CONTINUOUS,
GTKUPDATEDISCONTINUOUS,
GTK_UPDATE_DELAYED
} GtkUpdateType;
Сигнал "color_changed" void cb(GtkWidget *, gpointer)
В следующем примере демонстрируется окно, показанное на рис. 21.10.
widget = gtk_color_selection_new(); return(widget);widget = gtk_color_selection_new(); return(widget);}}static GtkWidget *makeWidget() { GtkWidget *widget;
widget = gtk_color_selection_new(); return(widget);
widget = gtk_color_selection_new(); return(widget);
}
}
Рисунок 21.10.
Виджет GtkColorSelection с установками, принятыми no умолчанию
GtkColorSelectionDialog
Это виджет, возникающий в своем собственном диалоговом окне.
Иерархия
GtkColorSelectionDialog->GtkWindow->GtkBin->GtkContainer->GtkWidget->
GtkObject
Функции
guint gtk_color_selection_dialog_get_type(void)
GtkWidget *gtk_color_selection_dialog_new(const gchar *title)
При создании диалогового окна для GtkColorSelectionDialog возникает такое же изображение, как показанное на рис. 21.10 для виджета GtkColorSelection.
static void makeWidget()
{
GtkWidget *widget;
widget = gtk_color_selection_dialog_new("Color Title"); gtkwidgetshow(widget);
}
GtkCombo
Ящик GtkCombo отображает один элемент и создает опускающийся список пунктов (меню), которые могут быть выбраны. Если отображается единственный пункт, это значит, что именно он выбран в настоящее время.
Иерархия
GtkCombo->GtkHBox->GtkBox->GtkContainer->GtkWidget->GtkObject
Функции
void gtk_combo_disable_activate(GtkCombo *combo)
guint gtk_combo_get^type(void)
GtkWidget *gtk_combo_new(void)
void gtk_combo_set_case_sensitive(GtkCombo *combo, gint val)
void gtk_combo_set_item_string(GtkCombo *combo, Gtkltem *item, const gchar *item_value)
void gtk_combo_set_popdown_strings(GtkCombo *combo, GList *strings)
void gtk_combo_set_use_arrows(GtkCombo *combo, gint val)
void gtk_combo_set_use_arrows_always(GtkCombo *combo, gint val)
void gtk_combo_set_value_in_list(GtkCombo *combo, gint val, gint ok_if_empty)
Рисунок 21.11.Виджет GtkCombo с выбранным третьим пунктомРисунок 21.11.Виджет GtkCombo с выбранным третьим пунктомВ приведенном далее примере создается виджет GtkCombo с пятью пунктами меню, доступными для выбора. На рис. 21.11 показан виджет с опускающимся списком меню и выбранным в нем третьим элементом.
Рисунок 21.11.
Виджет GtkCombo с выбранным третьим пунктом
Рисунок 21.11.
Виджет GtkCombo с выбранным третьим пунктом
static GtkWidget *makeWidget()
GtkWidget *widget;
GList *glist;
glist = NULL;
glist = g_list_append(glist,"Selection 1");
glist = g_list_append(glist,"Selection 2"); glist = g_list_append(glist,"Selection 3"); glist = g_list_append(glist,"Selection 4"); glist = glist append(glist,"Selection 5");
widget = gtk_combo new();
gtk_combo_set_popdown_strings(GTK_COMBO(widget), glist);
return(widget);
GtkContainer
Виджет GtkContainer — базовый класс для виджетов-контейнеров. Виджеты, порожденные от GtkContainer, имеют возможность содержать, позиционировать, устанавливать размеры и отображать один или более других виджетов.
Иерархия
GtkContainer->GtkWidget->GtkObject
Функции
void gtk_container_add(GtkContainer *container, GtkWidget *widget)
void gtkcontainer add_child_arg_type(const gchar *arg_name, GtkType argtype, guint arg flags, guint argid)
void gtkcontainer addwithargs(GtkContainer *container, GtkWidget *widget, const gchar *firstargname, ...)
void gtk_container_addv(GtkContainer *container, GtkWidget *widget, guint nargs, GtkArg *args) void gtk_container_arg_get(GtkContainer *container, GtkWidget *child, GtkArg *arg, GtkArglnfo *info)
void gtk_container_arg_set(Gtkcontainer *container, GtkWidget *child, GtkArg *arg, GtkArglnfo *info) void gtk_container_check_resize(GtkContainer *container) gchar *gtk_container_child_arg get info(GtkType object_type, const gchar *arg_name, GtkArglnfo **info _p)
gchar *gtk_container_child_args_collect(GtkType object_type, GSList **arg listp, GSList **info listp, const gchar *first_arg_name, va list var_args)
gchar *gtk_container_child_composite_name(
GtkContainer *container, GtkWidget *child)
void gtk_container_child_getv(GtkContainer *container, GtkWidget *child, guint n_args, GtkArg *args)
void gtk_container_child_set(GtkContainer *container, GtkWidget *child, const gchar *first_arg_name, ...)
void gtk_container_child_setv(GtkContainer *container, GtkWidget *child, guint n^args, GtkArg *args)
GtkType gtk_container_child_type(GtkContainer *container) GList *gtkcontainer_children(GtkContainer *container) void gtk_container_clear_resize_widgets(
GtkContainer *container)
gint gtk_container_focus(GtkContainer *container, GtkDirectionType direction)
void gtk_container_forall(GtkContainer *container, GtkCallback callback, gpointer callback data)
void gtk_container_foreach(GtkContainer *container, GtkCallback callback, gpointer callback_data)
void gtk container_foreach_full(GtkContainer *container, GtkCallback callback, GtkCallbackMarshal marshal, gpointer callbackdata, GtkDestroyNotifу notify)
GList *gtk_container gettoplevels(void)
GtkType gtk containergettype(void)
GtkArg *gtk_container_query_child_args(GtkType class type, guint32 **arg_flags, guint *n_args)
void gtkcontainer queue resize(Gtkcontainer *container) void gtkcontainerrealsetfocuschild(
GtkContainer *container, GtkWidget *child)
void gtkcontainer register_toplevel(GtkContainer *container) void gtkcontainer remove(GtkContainer *container,.
GtkWidget *widget)
void gtk_container_resize_children(Gtkcontainer *container) void gtk_container_set_border_width(Gtkcontainer *container, guint border_width)’
void gtk_container_set_focus_child(Gtkcontainer *container, GtkWidget *widget)
void gtkcontainer setfocushadjustment( Gtkcontainer *container, GtkAdjustment *adjustment)
void gtk_container_set focus vadjustment(
Gtkcontainer *container, GtkAdjustment *adjustment)
void gtk_container_set_resize_mode(Gtkcontainer *container, GtkResizeMode resizemode)
void gtk container unregister toplevel( Gtkcontainer *container)
Энумераторы
typedef enum {
GTK_DIR_TAB_FORWARD,
GTK_DIR_TAB_BACKWARD,
GTK_DIR_UP,
GTK_DIR_DOWN,
GTK_DIR_LEFT, GTK_DIR_RIGHT
} GtkDirectionType;
typedef enum { GTK_RESIZE_PARENT, GTKRESIZENQUEUE, GTK_RESIZE_IMMEDIATE
} GtkResizeMode;
Сигналы
"add"
void cb(GtkWidget
*, GtkWidget *, gpointer)
"checkresize"
void cb(GtkWidget
*, gpointer)
"focus"
gint cb(GtkWidget
*, GtkDirectionType, GtkDirectionType,
gpointer)
"remove"
void cb(GtkWidget
*, GtkWidget *, gpointer)
"set-focus-child"
void cb(GtkWidget
*, GtkWidget *, gpointer)
GtkCTree
Отображает иерархическое дерево, такое, как дерево каталогов, и предоставляет пользователю возможность пройти по дереву, используя мышь. •
Иерархия
GtkCTree->GtkCList->GtkContainer->GtkWidget->GtkObject
Функции
void gtk_ctree_collapse(GtkCTree *ctree, GtkCTreeNode *node) void gtk_ctree_collapse_recursive(GtkCTree *ctree, GtkCTreeNode *node) void gtk_ctree_collapse_to_depth(GtkCTree *ctree, GtkCTreeNode *node, gint depth)
void gtk_ctree_construct(GtkCTree *ctree, gint columns, gint tree_column, gchar *titles [ ]) void gtk_ctree_expand(GtkCTree *ctree, GtkCTreeNode *node) void gtk_ctree_expand_recursive(GtkCTree *ctree, GtkCTreeNode *node) void gtk_ctree_expand_to_depth(GtkCTree *ctree, GtkCTreeNode *node, gint depth)
GNode *gtk_ctree_export_to_gnode(GtkCTree *ctree,
GNode *parent, GNode *sibling, GtkCTreeNode *node, GtkCTreeGNodeFuhc func, gpointer data) gboolean gtk_ctree_find(GtkCTree *ctree, GtkCTreeNode *node, GtkCTreeNode *child)
GList *gtk_ctree_find_all_by_row_data(GtkCTree *ctree, GtkCTreeNode *node, gpointer data)
GList *gtk_ctree_find_all_by_row_data_custom(GtkCTree *ctree, GtkCTreeNode *node, gpointer data, GCompareFunc func) GtkCTreeNode *gtk_ctree_find_by_row_data(GtkCTree *ctree, GtkCTreeNode *node, gpointer data)
GtkCTreeNode *gtk_ctree_find_by_row_data_custom(
GtkCTree *ctree, GtkCTreeNode *node, gpointer data, GCompareFunc func) GtkCTreeNode *gtk_ctree_find_node_ptr(GtkCTree *ctree, GtkCTreeRow *ctree_row) gint gtk_ctree_get_node_infо(GtkCTree *ctree, GtkCTreeNode *node, gchar **text, guint8 *spacing, GdkPixmap **pixmap_closed, GdkBitmap **mask_closed, GdkPixmap **pixmap_opened, GdkBitmap **mask_opened,
gboolean *is_leaf, gboolean *expanded)
GtkType gtk_ctree_get_type(void)
GtkCTreeNode *gtk_ctree insert_gnode(GtkCTree *ctree, GtkCTreeNode *parent, GtkCTreeNode *sibling, GNode *gnode, GtkCTreeGNodeFunc func, gpointer data)
GtkCTreeNode *gtk_ctree_insert_node(GtkCTree *ctree, GtkCTreeNode *parent, GtkCTreeNode *sibling, gchar *text [ ], guint8 spacing, GdkPixmap *pixmap_closed, GdkBitmap *mask_closed, GdkPixmap *pixmap opened, GdkBitmap *mask_opened, gboolean isleaf, gboolean expanded)
gboolean gtk_ctree_is_ancestor(GtkCTree *ctree, GtkCTreeNode *node, GtkCTreeNode *child)
gboolean gtkctreeishot spot(GtkCTree *ctree, gint x, gint y) gboolean gtk_ctree_is_viewable(GtkCTree *ctree, GtkCTreeNode *node)
GtkCTreeNode *gtkctree_last(GtkCTree *ctree, GtkCTreeNode *node)
void gtk_ctree_move(GtkCTree *ctree, GtkCTreeNode *node, GtkCTreeNode *new_parent, GtkCTreeNode *new sibling)
GtkWidget *gtk_ctree_new(gint columns/ gint tree_column) GtkWidget *gtk_ctree_new_with_titles(gint columns, gint treecolumn, gchar *titles [ ])
GtkStyle *gtk_ctree_node_get_cell_style(GtkCTree *ctree, GtkCTreeNode *node, gint column)
GtkCellType gtk_ctree_node_get_cell_type(GtkCTree *ctree, GtkCTreeNode *node, gint column)
gint gtk_ctree_node_get_pixmap(GtkCTree *ctree, GtkCTreeNode *node, gint column, GdkPixmap **pixmap, GdkBitmap **mask)
gint gtk_ctree_node_getpixtext(GtkCTree *ctree, GtkCTreeNode *node, gint column, gchar **text, guint8 *spacing, GdkPixmap **pixmap, GdkBitmap **mask) gpointer gtk_ctree_node_get_row_data(GtkCTree *ctree, GtkCTreeNode *node)
GtkStyle *gtk_ctree_node_get_row_style(GtkCTree *ctree, GtkCTreeNode *node)
gboolean gtkctree_node_get_selectable(GtkCTree *ctree, GtkCTreeNode *node)
gint gtk_ctree_node_get_text(GtkCTree *ctree, GtkCTreeNode *node, gint column, gchar **text) GtkVisibility gtk_ctree_node_is_visible(GtkCTree *ctree, GtkCTreeNode *node)
void gtk_ctree_node_moveto(GtkCTree *ctree, GtkCTreeNode *node, gint column, gfloat row_align, gfloat col align)
GtkCTreeNode *gtk_ctree_node nth(GtkCTree *ctree, guint row) void gtk_ctree_node_set_background(GtkCTree *ctrее, GtkCTreeNode *node, GdkColor *color)
void gtk_ctree_node_set_cell_style(GtkCTree *ctree, GtkCTreeNode *node, gint column, GtkStyle *style)
void gtk_ctree_node_set^foreground(GtkCTree *ctree, GtkCTreeNode *node, GdkColor *color)
void gtk_ctree_node_set_pixmap(GtkCTree *ctree, GtkCTreeNode *node, gint column, GdkPixmap *pixmap, GdkBitmap *mask)
void gtk_ctree_node_set_pixtext(GtkCTree *ctree, GtkCTreeNode *node, gint column, const gchar *text, guint8 spacing, GdkPixmap *pixmap, GdkBitmap *mask)
void gtkctree node_set_row_data(GtkCTree *ctree,
GtkCTreeNode *node, gpointer data) void gtk_ctree_node_set_row_data_full(GtkCTree *ctree, GtkCTreeNode *node, gpointer data, GtkDestroyNotify destroy) void gtk_ctree_node_set_row_style(GtkCTree *ctree, GtkCTreeNode *node, GtkStyle *style) void gtkctreenodeset selectable(GtkCTree *ctree, GtkCTreeNode *node, gboolean selectable) void gtk_ctree_node_set_shift(GtkCTree *ctree, GtkCTreeNode *node, gint column, gint vertical, gint horizontal) void gtk_ctree_node_set_text(GtkCTree *ctree, GtkCTreeNode *node, gint column, const gchar *text) void gtkctree post_recursive(GtkCTree *ctree, GtkCTreeNode *node, GtkCTreeFunc func, gpointer data) void gtk_ctree_post_recursive_to_depth(GtkCTree *ctree, GtkCTreeNode *node, gint depth, GtkCTreeFunc func, gpointer data) void gtk_ctree_pre_recursive(GtkCTree *ctree, GtkCTreeNode *node, GtkCTreeFunc func, gpointer data) void gtk_ctree_pre_recursive_to_depth(GtkCTree *ctree, GtkCTreeNode *node, gint depth, GtkCTreeFunc func, gpointer data) void gtkctree real_select_recursive(GtkCTree *ctree, GtkCTreeNode *node, gint state) void gtkctree remove_node(GtkCTree *ctree, GtkCTreeNode *node) void gtk_ctree_select(GtkCTree *ctree, GtkCTreeNode *node) void gtk_ctree_select_recursive(GtkCTree *ctree, GtkCTreeNode *node) void gtkctree set_drag_compare_func(GtkCTree *ctree, GtkCTreeCompareDragFunc cmp_func) void gtkctree_set_expander_style(GtkCTree *ctree, GtkCTreeExpanderStyle expanderstyle) void gtk_ctree_set_indent(GtkCTree *ctree, gint indent) void gtk_ctree_set_line_style(GtkCTree *ctree, GtkCTreeLineStyle line_style) void gtk_ctree_set_node_infо(GtkCTree *ctree, GtkCTreeNode *node, const gchar *text, guint8 spacing, GdkPixmap *pixmap_closed, GdkBitmap *mask_closed, GdkPixmap *pixmap_opened, GdkBitmap *mask_opened, gboolean is_leaf, gboolean expanded) void gtk_ctree_set_show_stub(GtkCTree *ctree, gboolean show_stub) void gtk_ctree_set_spacing(GtkCTree *ctree, gint spacing) void gtk_ctree_sort node(GtkCTree *ctree, GtkCTreeNode *node) void gtk_ctree_sort_recursive(GtkCTree *ctree, GtkCTreeNode *node) void gtk_ctree_toggle_expansion(GtkCTree *ctree, GtkCTreeNode *node) void gtk_ctree_toggle_expansion_recursive(GtkCTree *ctree, GtkCTreeNode *node) void gtk_ctree_unselect(GtkCTree *ctree, GtkCTreeNode *node) void gtk_ctree_unselect_recursive(GtkCTree *ctree, GtkCTreeNode *node)
Энумераторы typedef enum { GTK_CTREE_POS_BEFORE, GTK_CTREE_POS_AS_CHILD,
GTK_CTREE_POS_AFTER } GtkCTreePos;
typedef enum { GTK_CTREE_LINES_NONE, GTK_CTREE_LINES_SOLID, GTK_CTREE_LINES_DOTTED, GTK_CTREE_LINES_TABBED
} GtkCTreeLineStyle;
typedef enum {
GTK_CTREE_EXPANDER_NONE, GTK_CTREE_EXPANDER_SQUARE, GTK_CTREE_EXPANDER_TRIANGLE, GTK_CTREE_EXPANDER_CIRCULAR
} GtkCTreeExpanderStyle;
typedef enum {
GTK_CTREE_EXPANSION_EXPAND, GTKCTREEEXPANSION_EXPAND_RECURSIVE, GTKCTREEEXPANSIONCOLLAPSE, GTK_CTREE_EXPANSION_COLLAPSE_RECURSIVE, GTKCTREEEXPANSION TOGGLE, GTK_CTREE_EXPANSION_TOGGLE_RECURSIVE
} GtkCTreeExpansionType;
typedef enum {
GTK_SELECTION_SINGLE, GTK_SELECTION_BROWSE, GTK_SELECTION_MULTIPLE, GTKSELECTIONEXTENDED
} GtkSelectionMode;
Сигналы
"change focusrowexpansion"
void cb(GtkWidget gpointer)
*
GtkCTreeExpansionType,
"treecollapse"
void cb(GtkWidget
GtkCTreeNode *, gpointer)
"tree_expand"
void cb(GtkWidget
GtkCTreeNode *, gpointer)
"tree_move"
void cb(GtkWidget
*r
GtkCTreeNode *,
GtkCTreeNode
*
GtkCTreeNode *, gpointer)
"tree_select_row"
void cb(GtkWidget
GtkCTreeNode *, gint.
gpointer)
"tree_unselect_row"void cb(GtkWidget *, GtkCTreeNode, gint, nointer)
First Column|SecondColumn;T Level 1Number2В Level 1Number3|-Level 2Number1I i-Level 2Number 2First Column|SecondColumn;T Level 1Number2В Level 1Number3|-Level 2Number1I i-Level 2Number 2Level 1 Number 1t Level 2 Number 1Level 2 Number 2Level 1 Number 1t Level 2 Number 1Level 2 Number 2Рисунок 21.12.Двухуровневый виджет GtkCTree, демонстрирующий выбор и разворачивание узловРисунок 21.12.Двухуровневый виджет GtkCTree, демонстрирующий выбор и разворачивание узловКаждый узел в виджете GtkCTree — это структура GtkCTreeNode. Она содержит указатели на сестринский, родительский и дочерний узлы. Если родительский узел — NULL, то это корневой узел. При добавлении нового некорневого узла он добавляется либо к родительскому узлу, либо к сестринскому. В приведенном примере создается простое двухуровневое дерево, показанное на рис. 21.12.
First Column|SecondColumn;
T Level 1Number2
В Level 1Number3
|-Level 2Number1
I i-Level 2Number 2
First Column|SecondColumn;
T Level 1Number2
В Level 1Number3
|-Level 2Number1
I i-Level 2Number 2
Level 1 Number 1
t Level 2 Number 1
Level 2 Number 2
Level 1 Number 1
t Level 2 Number 1
Level 2 Number 2
Рисунок 21.12.
Двухуровневый виджет GtkCTree, демонстрирующий выбор и разворачивание узлов
Рисунок 21.12.
Двухуровневый виджет GtkCTree, демонстрирующий выбор и разворачивание узлов
static GtkWidget *makeWidget()
{
GtkCTreeNode *nodel_l;
GtkCTreeNode *nodel 3;
GtkWidget *widget;
static gchar *titles[] = {
"First Column",
"Second Column" };
widget = gtk_ctree_new_with_titles(2,0,titles);
nodell = makeNode(widget,NULL,NULL,1,1);
makeNode(widget,NULL,node1_1,1,2);
nodel_3 = makeNode(widget,NULL,node11,1,3);
makeNode(widget,NULL,nodel_l,1,4);
makeNode(widget,node11,NULL,2,1);
makeNode(widget,node11,NULL,2,2);
makeNode(widget,node13,NULL,2,1);
makeNode(widget,nodel_3,NULL,2,2); return(widget);
}
static GtkCTreeNode *makeNode(GtkWidget *widget, GtkCTreeNode *parent,GtkCTreeNode *sibling, gint level,gint count)
< GtkCTreeNode *node; gchar *text[2]; gchar linel[20]; gchar line2[20]; text[0] = linel; text[l] = line2;
sprintf(linel,"Level %d",level);
sptintf(line2,"Number %d",count);
node = gtk_ctree_insert_node(GTK_CTREE(widget), parent, sibling, text, 0,'
NULL,NULL,NULL,NULL, FALSE,TRUE);
return(node); }X
GtkCurve
Отображает сетку и по данному набору точек рисует график. Доступны три вида линий графика. Добавление новых точек и перемещение уже имеющихся можно производить интерактивно с помощью мыши.
Иерархия
GtkCurve->GtkDrawingArea->GtkWidget->GtkObj ect
Функции
GtkType gtk_curve_get_type(void)
void gtk_curve_get_vector(GtkCurve *c, int veclen, gfloat vector [ ])
GtkWidget *gtk_curve_new(void) void gtk_curve_reset(GtkCurve *c) void gtk_curve_set_curve_type(GtkCurve *c, GtkCurveType new_type) void gtk_curve_set_gamma(GtkCurve *c, gfloat gamma) void gtk_curve_set_range(GtkCurve *curve, gfloat minx, gfloat max x, gfloat min y, gfloat maxy)
void gtk_curve_set_vector(GtkCurve *с, int veclen, gfloat vector [ ])
Энумератор
typedef enum {
GTK_CURVE_TYPE_LINEAR,
GTK_CURVE_TYPE_SPLINE, GTK_CURVE_TYPE_FREE
} GtkCurveType;
Сигнал
"curve_type_changed” void cb(GtkWidget *, gpointer)
ПРИМЕЧАНИЕ НАУЧНОГО РЕДАКТОРА
В простейшей форме сплайн, или сплайн-функция, — это кусочный полином, часто лежащий в основе аппроксимаций.
Рисунок 21.13.Виджет GtkCurve, изображающий сплайнРисунок 21.13.Виджет GtkCurve, изображающий сплайнВ приведенном примере создается область для рисования размером 100x100. Добавление и размещение точек, показанных на рис. 21.13, осуществляется с помощью мыши. Эта кривая — сплайн, так что создаются сглаженные кривые линии, проходящие через каждую точку.
Рисунок 21.13.
Виджет GtkCurve, изображающий сплайн
Рисунок 21.13.
Виджет GtkCurve, изображающий сплайн
static GtkWidget *makeWidget() {
GtkWidget *widget;
widget = gtk_curve_new();
gtk_curve_set_range(GTKCURVE(widget), 0.0,100.0,0.0,100.0);
gtkcurve setcurvetype(GTKCURVE(widget), GTK_CURVE_TYPE_SPLINE);
return(widget);
}
GtkData
Виджеты, порожденные от базового класса GtkData, могут содержать данные, совместно используемые двумя или более виджетами. Примерами таких виджетов являются GtkAdjustment и GtkTooltips.
Иерархия
GtkData->GtkObject
Функция
GtkType gtk_data_get_type(void)
Сигнал
"disconnect" void cb(GtkWidget *, gpointer)
GtkDial
Отображает циферблат, представляющий значения от 0% до 100%. Если виджет не находится в режиме только отображения (только показа), то с помощью мыши можно передвигать указатель по шкале.
Иерархия
GtkDial->GtkWidget->GtkObject
Функции
GtkAdjustment *gtk_dial_get_adjustment(GtkDial *dial) gfloat gtk_dial_get_percentage(GtkDial *dial) guint gtk-dialget_type()
gfloat gtk_dial_get-Value(GtkDial *dial)
GtkWidget *gtk_dial_new(GtkAdjustment *adjustment) void gtk-dial-Setadjustment(GtkDial *dial, GtkAdjustment *adjustment)
gfloat gtk-dialset-percentage(GtkDial *dial, gfloat percent) void gtk-dial-Set_update_policy(GtkDial *dial, GtkUpdateType policy)
gfloat gtk-dial_set_value(GtkDial *dial, gfloat value) void gtk_dial_set_view_only(GtkDial *dial, gboolean viewonly)
Энумератор
typedef enum {
GTK—UPDATE—CONTINUOUS,
Рисунок 21.14.Виджет GtkDial, показывающий 22%Рисунок 21.14.Виджет GtkDial, показывающий 22%GTK—UPDATE—DISCONTINUOUS, GTK—UPDATE—DELAYED
Рисунок 21.14.
Виджет GtkDial, показывающий 22%
Рисунок 21.14.
Виджет GtkDial, показывающий 22%
} GtkUpdateType;
В приведенном примере строится виджет GtkDial, показанный на рис. 21.14. Текущее значение 44 составляет 22% от максимального значения 200.
static GtkWidget *makeWidget()
GtkWidget *widget;
GtkObject *adjustment;
adjustment = gtk_adjustment_new(44.0, 0.0,200.00,1.0,0.0,0.0);
widget = gtk_dial_new(GTK_ADJUSTMENT(adjustment)); return(widget);
}
GtkDialog
Это окно с некоторыми прединсталлированными и сконфигурированными контейнерами, которые вы можете использовать для создания ваших собственных всплывающих диалоговых окон.
Иерархия
GtkDialog->GtkWindow->GtkBin->GtkContainer->GtkWidget->GtkObject
Функции
GtkType gtk_dialog_get_type(void)
GtkWidget *gtk_dialognew(void)
В приведенном примере в каждом из двух доступных контейнеров размещаются три кнопки, что показано на рис. 21.15. Вертикальный ящик по имени vbox располагается в верхней части окна и предназначен для использования панелями инструментов и меню. Вы также можете использовать вертикальный ящик в качестве контейнера для растровых окон и текстовых меток (надписей). Горизонтальный ящик по имени action_area содержит виджеты, расположенные в центре и предназначенные реагировать на кнопки.
static void makeWidget() {
GtkWidget *dialog;
GtkWidget *button;
GtkWidget *vbox;
GtkWidget *hbox;
dialog = gtk_dialog_new();
vbox = GTK_DIALOG(dialog)->vbox;
button = gtk_button_new_with_label("VBOX First");
gtk_box_pack_start(GTK_BOX(vbox),button,TRUE,TRUE, 0); button = gtk_button_new_with_label("VBOX Second");
gtk_box_pack_start(GTK_BOX(vbox),button,TRUE,TRUE, 0); button = gtk_button_new_with_label("VBOX Third");
gtk_box_pack_start(GTK_BOX(vbox),button,TRUE,TRUE, 0);
hbox = GTK_DIALOG(dialog)->action_area;
button = gtk_button_new_with_label("HBOX First");
gtk_box_pack_start(GTK_BOX(hbox),button,TRUE,TRUE, 0); button = gtk_button_new_with_label("HBOX Second");
gtk_box_pack_start(GTK_BOX(hbox),button,TRUE,TRUE,0); button = gtk_button_new_with_label("HBOX Third");
gtk_box_pack_start(GTK_BOX(hbox),button,TRUE,TRUE, 0);
gtk_widget_show_all(dialog);
VBOX FirstVBOX FirstVBOX SecondVBOX SecondVBOX ThirdVBOX ThirdРисунок 21.15.'Виджет GtkDialog, отображающий кнопки верти-Рисунок 21.15.'Виджет GtkDialog, отображающий кнопки верти-
VBOX First
VBOX First
VBOX Second
VBOX Second
VBOX Third
VBOX Third
Рисунок 21.15.'
Виджет GtkDialog, отображающий кнопки верти-
Рисунок 21.15.'
Виджет GtkDialog, отображающий кнопки верти-
кально и горизонтально
GtkDrawingArea
Это очень простой виджет, предоставляющий доступ к окну, которое используется простейшими командами рисования и раскраски.
Иерархия
GtkDrawingArea->GtkWidget->GtkObject
Функции
guint gtk_drawing_area_get_type(void)
GtkWidget *gtk_drawing_area_new(void)
void gtk_drawing_area_size(GtkDrawingArea *darea, gint width, gint height)
В главах 10 и 11 приведены многочисленные примеры использования виджета GtkDrawingArea.
GtkEditable
Используется в качестве базового класса для виджетов, позволяющих выполнять редактирование текста. В таком качестве он используется для виджетов GtkEntry, GtkSpinButton и GtkText.
Иерархия
GtkEditable->GtkWidget->GtkObject
Функции
void gtk_editable_changed(GtkEditable ♦editable)
void gtk_editable_claim_selection(GtkEditable *editable, gboolean claim, guint32 time)
void gtk_editable_copy_clipboard(GtkEditable ♦editable) void gtk_editable_cut_clipboard(GtkEditable *editable) void gtk_editable_delete_selection(GtkEditable *editable) void gtk_editable_delete_text(GtkEditable *editable,
gint start_pos, gint endpos)
gchar *gtk_editable_get_chars(GtkEditable *editable, gint start, gint end)
gint gtk_editable_get_position(GtkEditable *editable)
GtkType gtk_editable_get_type(void)
void gtk_editable_insert text(GtkEditable *editable, const gchar *new_text, gint new_text length, gint *position)
void gtk_editable_paste__clipboard(GtkEditable *editable)
void gtk_editable_select_region(GtkEditable *editable, gint start, gint end)
void gtk_editable_set_editable(GtkEditable *editable, gboolean is_editable)
void gtk_editable_set_position(GtkEditable *editable, gint position)
Сигналы
"activate"
void cb(GtkWidget
*
gpointer)
"changed"
void
cb(GtkWidget
gpointer)
" copy__cl ipboard "
void
cb(GtkWidget
*,
gpointer)
"cut_clipboard"
void
cb(GtkWidget
gpointer)
"delete_text"
void
cb(GtkWidget
gint, gint, gpointer)
"insert_text"
void
cb(GtkWidget
gchar *, gint, gpointer, gpointer)
"killchar"
void
cb(GtkWidget
gint, gpointer)
"kill_line"
void
cb(GtkWidget
♦
gint, gpointer)
"kill_word"
void
cb(GtkWidget
gint, gpointer)
"move_cursor"
void
cb(GtkWidget
*
gint, gint, gpointer)
"move_page"
void
cb(GtkWidget
*,
gint, gint, gpointer)
"move_to_column"
void
cb(GtkWidget
gint, gint, gpointer)
"move_to_row"
void
cb(GtkWidget
♦
gint, gpointer)
"move_word"
void
cb(GtkWidget
*
gint, gpointer)
"paste_clipboard"
void
cb(GtkWidget
gpointer)
"set-editable"
void
cb(GtkWidget
*
gbolean, gpointer)
GtkEntry
Данный виджет представляет собой окно для ввода данных в виде одной строки текста.
Иерархия
GtkEntry->GtkEditable->GtkWidget->GtkObject
Функции
void gtk_entry_append_text(GtkEntry *entry, const gchar *text)
gchar *gtk_entry_get_text(GtkEntry *entry)
GtkType gtk_entry_get_type(void)
GtkWidget *gtk_entry_new(void)
GtkWidget *gtk_entry_new_with_max_length(guintl6 max)
void gtk_entry_prepend_text(GtkEntry *entry, const gchar *text) void gtk_entry_select_region(GtkEntry *entry, gint start, gint end) void gtk_entry_set_editable(GtkEntry *entry, gboolean editable) void gtk_entryset_max_length(GtkEntry *entry, guintl6 max) void gtk_entry_set_position(GtkEntry *entry, gint position) void gtk_entry_set_text(GtkEntry *entry, const gchar *text) void gtk_entry_set_visibility(GtkEntry *entry, gboolean visible)
Рисунок 21.16.Окно для ввода текста, который можно редактироватьРисунок 21.16.Окно для ввода текста, который можно редактироватьВ приведенном примере создается окно для ввода текста, показанное на рис. 21.16. Ширина окна составляет 40 символов. Окно создается и заполняется текстом.
Рисунок 21.16.
Окно для ввода текста, который можно редактировать
Рисунок 21.16.
Окно для ввода текста, который можно редактировать
static GtkWidget *makeWidget()
{
GtkWidget *widget;
widget = gtk_entry_new_with_max_length(40); gtk_entry_set_text(GTKENTRY(widget),"Edit me!"); return(widget);
}
GtkEventBox
Виджет GtkEventBox — это контейнер с окном просмотра, имеющим возможность получать события для содержащегося в нем виджета, обычно такого, который сам не может получать события. Так как события посылаются окнам, виджеты без окон не могут получать события.
Иерархия
GtkEventBox->GtkBin->GtkContainer->GtkWidget->GtkObject
Функции
GtkType gtk event_box_get_type(void)
GtkWidget *gtk event_box_new(void)
Mouse OutsideMouse OutsideРисунок 21.17.Виджет GtkEventBox, передающий события меткеРисунок 21.17.Виджет GtkEventBox, передающий события меткеВ приведенном примере в виджет GtkEventBox вставлен виджет GtkLabel, что позволяет сделать метку (надпись) чувствительной к перемещениям указателя мыши. Для изменения текста надписи используются обратные вызовы, которые, как показано на рис. 21.17, сообщают, находится ли указатель мыши внутри метки.
Mouse Outside
Mouse Outside
Рисунок 21.17.
Виджет GtkEventBox, передающий события метке
Рисунок 21.17.
Виджет GtkEventBox, передающий события метке
static GtkWidget *makeWidget() <
GtkWidget *eventbox;
GtkWidget *label;
eventbox = gtk_event_box_new();
label = gtk_label_new("Mouse Outside");
gtk_container_add(GTK_CONTAINER(eventbox),label);
gtks ignal_connect(GTK_OBJECT(eventbox), "enter notifyevent", GTK_SIGNAL_FUNC(mouseEnter),label);
gtk_signal_connect(GTK_OBJECT(eventbox), "leave_notify_event", GTK_SIGNAL_FUNC(mouseLeave),label);
return(eventbox);
}
static gboolean mouseEnter(GtkWidget *widget,
GdkEvent *event,gpointer data)
{
gtk_label_set_text(GTK_LABEL(data),"Mouse Inside");
return(TRUE);
}
static gboolean mouseLeave(GtkWidget *widget,
GdkEvent *event,gpointer data)
{
gtk_label_set_text(GTK_LABEL(data),"Mouse Outside");
return(TRUE);
}
GtkFileSelection
Перечисляет все файлы и каталоги текущего рабочего каталога и предоставляет пользователю возможность выбрать одно из имен файлов. Как показано на рис. 21.18, имеется ряд элементов управления, с помощью которых пользователь может просмотреть всю файловую систему. Кроме того, имеются кнопки, позволяющие создавать каталоги, удалять и переименовывать файлы.
Иерархия
GtkFileSelection->GtkWindow->GtkBin->GtkContainer->GtkWidget->GtkObject
Функции
void gtkfile_selection_complete(GtkFileSelection *filesel, const gchar *pattern)
gchar *gtk_file_selection_get_filename(
GtkFileSelection *filesel)
GtkType gtk_file_selection_get_type(void)
void gtk_file_selection_hide_fileop_buttons(
GtkFileSelection *filesel)
GtkWidget *gtk_file_selection_new(const gchar *title)
void gtk_file_selection_set_filename(
GtkFileSelection *filesel, const gchar *filename)
void gtk_file_selection_show_fileopbuttons(
GtkFileSelection *filesel)
int translate_win32_path(GtkFileSelection *filesel)
В приведенном примере отображается виджет GtkFileSelection с предварительно выбранным по умолчанию файлом xgtkfileselection.c, что показано на рис. 21.18. Поддерживаются три функции обратного вызова. Нажатие на кнопку Cancel закрывает окно без выбора хотя бы одного из файлов, а нажатие на кнопку ОК возвращает имя выбранного файла и закрывает окно. Поскольку данный виджет находится в своем собственном окне верхнего уровня, для закрытия необходимо вызвать функцию gtk_main_quit().
static void makeWidget()
{
GtkWidget *fileselection;
GtkWidget *okButton;
GtkWidget *cancelButton;
fileselection = gtk_file_selection_new("GtkFileSelection");
okButton = GTK_FILE_SELECTION(fileselection)->ok_button; cancelButton =
GTK_FILE_SELECTION(fileselection)->cancel_button;
gtk signal_connect (GTK_OBJECT(fileselection),"destroy", (GtkSignalFunc)gtk_widget_destroy, fileselection);
gtk_signal_connect(GTK_OBJECT(okButton),"clicked", (GtkSignalFunc)eventOk,fileselection);
gtk_signal_connect(GTK_OBJECT(cancelButton),"clicked", (GtkSignalFunc)eventcancel,fileselection);
gtk_file_selection_set_filename(
GTK_FILE_SELECTION(fileselection), "xgtkfileselection.c");
gtk_widgetshow(fileselection);
}
void eventOk(GtkWidget *widget,gpointer data)
<
GtkFileSelection *fileselection;
gchar *filename;.
fileselection = GTK_FILE_SELECTION(data);
filename = gtk_file_selection_get_filename(fileselection);
g_print("Selected File: %s\n",filename); gtk_main_quit();
}
void eventcancel(GtkWidget *widget,gpointer data)
{
gtk_main_quit();
}
_ □ x
Create Dir | Delete File | Rename File |
DirectoriesDirectoriesFiles хдтшэгг^е— xgtkdialog о xgtkentry xgtkentry.c xgtkentry.о xgtkeventbox xgtkeventbox.c xgtkeventbox о xgtkfileselectionFiles хдтшэгг^е— xgtkdialog о xgtkentry xgtkentry.c xgtkentry.о xgtkeventbox xgtkeventbox.c xgtkeventbox о xgtkfileselection/home7stuftrbook/gn/2Vcode _j
Directories
Directories
Files хдтшэгг^е— xgtkdialog о xgtkentry xgtkentry.c xgtkentry.о xgtkeventbox xgtkeventbox.c xgtkeventbox о xgtkfileselection
Files хдтшэгг^е— xgtkdialog о xgtkentry xgtkentry.c xgtkentry.о xgtkeventbox xgtkeventbox.c xgtkeventbox о xgtkfileselection
Рисунок 21.18.
Виджет GtkFileSelection с выбранным файлом
xgtktileselection.o
Selection. Zhome/stutIZbook/gn/21/code
|xgtkfileselection c
OK j Cancel |
GtkFixed
Этот контейнер позволяет вашей программе располагать виджеты в заданном месте и перемещать их из одного положения в другое.
Иерархия
GtkFixed->GtkContainer->GtkWidget->GtkObject
Функции
GtkType gtk_fixed_gettype(void) void gtk_fixed_move(GtkFixed *fixed, GtkWidget *widget, gintl6 x, gintl6 y)
GtkWidget *gtk_fixed_new(void) void gtk_fixed_put(GtkFixed *fixed, GtkWidget *widget, gintie x, gintie y)
Примеры использования GtkFixed приведены в главе 5.
GtkFontSelection
Виджет может быть использован в вашем приложении, чтобы предоставить пользователю возможность выбрать шрифт.
При использовании этого виджета в самом приложении определяется, когда производится выбор, и вызывается функция gtk_font_selection_get_font (). Виджет GtkFontSelectionDialog использует данный виджет, добавляет кнопки выбора и обратные вызовы.
Иерархия
GtkFontSelection->GtkNotebook->GtkContainer->GtkWidget~>GtkObject
Функции
GdkFont *gtk_font_selection_get_font( GtkFontSelection *fontsel) gchar *gtk_font_selection_get_font_name( GtkFontSelection *fontsel) gchar *gtk_font_selection_get_preview_text( GtkFontSelection *fontsel)
GtkType gtk_font_selection_get_type()
GtkWidget *gtk_font_selection_new() void gtk_font_selection_set_filter(GtkFontSelection *fontsel, GtkFontFilterType filtertype, GtkFontType font_type, gchar **foundries, gchar **weights, gchar **slants, gchar **setwidths, gchar **spacings, gchar **charsets) gboolean gtkfontselectionsetfontname(
GtkFontSelection *fontsei, const gchar *fontname) void gtk_font_selection_set_preview_text( GtkFontSelection *fontsel, const gchar *text)
Энумераторы
typedef enum {
GTK_FONT_FILTER_BASE, GTK_FONT_FILTER_USER
} GtkFontFilterType;
typedef enum {
GTK_FONT_BITMAP, GTKFONTSCALABLE, GTK_FONT_SCALABLE_BITMAP, GTK_FONT_ALL
} GtkFontFilterType;
Виджет GtkFontSelection, приведенный на рис. 21.19 после кода примера, в принятой по умолчанию конфигурации (без использования фильтров) показывает выбранный шрифт с его типом и размером. Выбранный шрифт отображается в нижней части окна. Клавиша Font Information приводит подробную информацию по выбранному шрифту и
длинную форму имени шрифта, описанную в главе 13. С помощью клавиши Filter в фокусе окажется окно, используемое при установке фильтров, которые применяются с целью ограничения отображаемых имен шрифтов. Фильтрация воздействует на каждую часть длинного имени шрифта.
static GtkWidget *makeWidget() {
GtkWidget *widget;
widget = gtk_font_selection_new(); return(widget);widget = gtk_font_selection_new(); return(widget);}}
widget = gtk_font_selection_new(); return(widget);
widget = gtk_font_selection_new(); return(widget);
}
}
Font ' j | Font Information | ■ FilterFont ' j | Font Information | ■ FilterPreview:Preview:abcdefghijk ABCDEFGH1J Кabcdefghijk ABCDEFGH1J К
Font ' j | Font Information | ■ Filter
Font ' j | Font Information | ■ Filter
Preview:
Preview:
abcdefghijk ABCDEFGH1J К
abcdefghijk ABCDEFGH1J К
Рисунок 21.19.
Виджет GtkFontSelection, показывающий выбранный шрифт
С помощью обращения к функции gtk_font_selection_set_f ilter () пользователь может указать такой же вид фильтрации, как и через клавишу Filter. Каждый фильтр представляет собой указатель на массив строк значений фильтров. Передаваемый указатель NULL удаляет все установленные для компонента фильтры.
GtkFontSelectionDialog
Этот виджет использует как свое главное окно виджет GtkFontSelection и добавляет кнопки, с помощью которых пользователь может подтвердить выбор шрифта или отказаться от него.
Иерархия
GtkFontSelectionDialog->GtkWindow->GtkBin->GtkContainer->GtkWidget->GtkOb ject
Функции
GdkFont *gtk_font_selection_dialog_get_font(
GtkFontSelectionDialog *fsd)
gchar *gtk_font_selection_dialog_get_font_name(
GtkFontSelectionDialog *fsd)
gchar *gtk_font_selection_dialog_get_preview_text(
GtkFontSelectionDialog *fsd)
guint gtk_font_selection_dialog_get_type(void)
GtkWidget *gtk_font_selection_dialog_new(const gchar *title)
void gtk_font_selection_dialog_set_filter(
GtkFontSelectionDialog *fsd, GtkFontFilterType filter_type,
GtkFpntType font_type, gchar **foundries, gchar **weights, gchar **slants, gchar **setwidthsr gchar **spacings, gchar **charsets)
gboolean gtk_font_selection_dialog_set_font_name( GtkFontSelectionDialog *fsd, const gchar *fontname)
void gtk_font_selection_dialog_set_preview_text( GtkFontSelectionDialog *fsdr const gchar *text)
Энумераторы
typedef enum {
GTK_FONT_FILTER_BASE,
GTK_FONT_FILTER_USER
} GtkFontFilterType;
typedef enum {.
GTK_FONT_BITMAP,
GTK_FONT_SCALABLE,
GTK_FONT_SCALABLE_BITMAP, GTK_FONT_ALL
} GtkFontFilterType;
В следующем примере отображается принятая по умолчанию конфигурация окна GtkFontSelectionDialog, что показано на рис. 21.20. Пример реагирования на кнопки диалогового окна приведен ранее в разделе по GtkDialog. Более подробная информация касательно фильтрации шрифтов и других элементов управления приведена в разделе по виджету GtkFontSelection. Общая информация по шрифтам дана в главе 13.
static void makeWidget()
{
GtkWidget *widget;
gtk_widget_show(widget);gtk_widget_show(widget);Рисунок 21.20.Принятое no умолчанию ' отображение окна виджетаGtkFontSelectionDialogРисунок 21.20.Принятое no умолчанию ' отображение окна виджетаGtkFontSelectionDialogwidget = gtk_font_selection_dialog_new( "GtkFontSelectionDialog");
gtk_widget_show(widget);
gtk_widget_show(widget);
Рисунок 21.20.
Принятое no умолчанию ' отображение окна виджета
GtkFontSelectionDialog
Рисунок 21.20.
Принятое no умолчанию ' отображение окна виджета
GtkFontSelectionDialog
GtkFrame
Представляет собой контейнер, в котором может размещаться один виджет, окруженный рамкой.
Иерархия
GtkFrame->GtkBin->GtkContainer->GtkWidget->GtkObject
Функции
GtkType gtk_frame_get_type(void)
GtkWidget *gtk_frame_new(const gchar *label) void gtkframe_set_label(GtkFrame *frame, const gchar *label) void gtk_frame_set_label_align(GtkFrame *frame, gfloat xalign, gfloat yalign)
void gtkframe_set_shadow_type(GtkFrame *frame, GtkShadowType type)
Энумератор
typedef enum {
GTK_SHADOW_NONE, GTK_SHADOW_IN, GTK_SHADOW_OUT, GTK_SHADOW_ETCHED_IN, GTK_SHADOW_ETCHED_OUT } GtkShadowType;
В следующем примере для включения метки (надписи) применяется виджет GtkFrame. В самой рамке содержится текстовая метка, вывод которой можно запретить, передав NULL функции gtk_frame_new().Примеры стилей рамок приведены в главе 5. В следующем примере отображается окно, показанное на рис. 21.21.static GtkWidget *makeWidget(){GtkWidget *label;GtkWidget *frame;В следующем примере для включения метки (надписи) применяется виджет GtkFrame. В самой рамке содержится текстовая метка, вывод которой можно запретить, передав NULL функции gtk_frame_new().Примеры стилей рамок приведены в главе 5. В следующем примере отображается окно, показанное на рис. 21.21.static GtkWidget *makeWidget(){GtkWidget *label;GtkWidget *frame;Frame Text The string of characters In the labelFrame Text The string of characters In the labelРисунок 21.21.Виджет GtkFrame co стилем рамки, устанавливаемым no умолчанию, и надписьюРисунок 21.21.Виджет GtkFrame co стилем рамки, устанавливаемым no умолчанию, и надписью
В следующем примере для включения метки (надписи) применяется виджет GtkFrame. В самой рамке содержится текстовая метка, вывод которой можно запретить, передав NULL функции gtk_frame_new().
Примеры стилей рамок приведены в главе 5. В следующем примере отображается окно, показанное на рис. 21.21.
static GtkWidget *makeWidget()
{
GtkWidget *label;
GtkWidget *frame;
В следующем примере для включения метки (надписи) применяется виджет GtkFrame. В самой рамке содержится текстовая метка, вывод которой можно запретить, передав NULL функции gtk_frame_new().
Примеры стилей рамок приведены в главе 5. В следующем примере отображается окно, показанное на рис. 21.21.
static GtkWidget *makeWidget()
{
GtkWidget *label;
GtkWidget *frame;
Frame Text
The string of characters In the label
Frame Text
The string of characters In the label
Рисунок 21.21.
Виджет GtkFrame co стилем рамки, устанавливаемым no умолчанию, и надписью
Рисунок 21.21.
Виджет GtkFrame co стилем рамки, устанавливаемым no умолчанию, и надписью
label = gtk_label_new(
"The string of characters in the label"); frame = gtk_frame_new("Frame Text");
gtkcontaineradd(GTK_CONTAINER(frame),label);
return(frame);
GtkGammaCurve
Этот виджет отображает интерактивное окно, позволяющее с помощью мыши вставлять и перемещать точки, которые могут соединяться кривыми линиями или отрезками прямых. Выбрав кнопку с символом у, можно поменять у-значение, определяющее тип сплайна.
Иерархия
GtkGammaCurve - >GtkVBox - >GtkBox - >GtkContainer - >GtkWidget - >GtkOb j ect
Функции
guint gtk_gamma_curve_get_type(void)
GtkWidget *gtk_gamma_curve_new(void)
В приведенном примере отображается окно, показанное на рис. 21.22.
static GtkWidget *makeWidget() {
GtkWidget *widget;
widget = gtk_gamma_curve_new(); return(widget);
Рисунок 21.22.
Окно виджета GtkGammaCurve с девятью точками и у-значением одной из них
GtkHandleBox
Виджет GtkHandleBox — это контейнер, на одной из четырех сторон которого имеется манипулятор. С помощью мыши, используя манипулятор, можно перенести виджет в другое место и даже за пределы окна приложения.
, Иерархия
GtkHandleBox->GtkBin->GtkContainer->GtkWidget->GtkObject
Функции guint gtk_handle_box_get_type(void)-
GtkWidget *gtk_handle_box_new(void) void gtk_handle_box_set_handle_position( GtkHandleBox *handle_box, GtkPositionType position) void gtk_handle_box_set_shadow_type(GtkHandleBox *handle_box, GtkShadowType type) void gtk_handle_box_set_snap_edge(GtkHandleBox *handle_box, GtkPositionType edge)
Энумераторы typedef enum { GTK_POS_LEFT, GTK_POS_RIGHT, GTK_POS_TOP, GTK_POS_BOTTOM } GtkPositionType; typedef enum { GTK_SHADOW_NONE, GTK_SHADOW_IN, GTK_SHADOW_OUT, GTK_SHADOW_ETCHED_IN, GTK_SHADOW_ETCHED_OUT } GtkShadowType;
Сигналы "chiId^attached"void cb(GtkWidget *, GtkWidget *, gpointer)
"child_detached"void cb(GtkWidget *, GtkWidget *, gpointer)
В следующем примере горизонтальный ящик, содержащий ряд из трех кнопок, вставляется в виджет GtkHandleBox. По умолчанию манипулятор располагается слева. На рис. 21.23 показан вид кнопок и манипулятора при запуске приложения. На рис. 21.24 показан результат перемещения с помощью мыши манипулятора, который может быть возвращен назад в первоначальное положение. Обратите внимание, что кнопки различаются по размеру. Это происходит потому, что в приведенном примере установку размеров кнопок производит родительское окно, а при перемещении кнопок за границы окна оно уже не определяет их размеры.
static GtkWidget *makeWidget()
{
GtkWidget *handlebox;
GtkWidget *box;
GtkWidget *button;-
box = gtk_hbox_new(FALSE,0);
button = gtk_button_new_with_label("First");
gtkboxpackstart(GTK_BOX(box),button,TRUE,TRUE, 0);
button = gtk_button_new_with_label("Second");
gtk_box_pack_start(GTK_BOX(box),button,TRUE,TRUE, 0);
button = gtk_button_new_with_label("Third");
gtk_box_pack_start(GTKHBOX(box),button,TRUE,TRUE, 0);
handlebox = gtk_handle_box_new();
return(handlebox);return(handlebox);First | Second | Third |First | Second | Third |Рисунок 21.23. Виджет GtkHandleBox с тремя кнопками и манипулятором, расположенным слева ■Рисунок 21.23. Виджет GtkHandleBox с тремя кнопками и манипулятором, расположенным слева ■gtk_container_add(GTK_CONTAINER(handlebox),box);
return(handlebox);
return(handlebox);
First | Second | Third |
First | Second | Third |
Рисунок 21.23. Виджет GtkHandleBox с тремя кнопками и манипулятором, расположенным слева ■
Рисунок 21.23. Виджет GtkHandleBox с тремя кнопками и манипулятором, расположенным слева ■
L о, х:L о, х:Рисунок 21.24. Виджет GtkHandleBox, перемещенный за пределы родительского окнаРисунок 21.24. Виджет GtkHandleBox, перемещенный за пределы родительского окна}
L о, х:
L о, х:
Рисунок 21.24. Виджет GtkHandleBox, перемещенный за пределы родительского окна
Рисунок 21.24. Виджет GtkHandleBox, перемещенный за пределы родительского окна
|| First] Second) Third]
GtkHBox
Виджет GtkHBox — это контейнер, который размещает содержащиеся в нем виджеты горизонтально (бок о бок).
Иерархия
GtkHBox->GtkBox->GtkContainer->GtkWidget->GtkObject
Функции
GtkType gtk_hbox_get_type(void)
GtkWidget *gtk_hbox_new(gboolean homogeneous, gint spacing)
Примеры использования виджета GtkHBox приведены в главе 4.
GtkHButtonBox
Это контейнер, предназначенный отображать набор кнопок горизонтально (бок о бок).
Иерархия
GtkHButtonBox->GtkButtonBox->GtkBox->GtkContainer->GtkWidget->GtkObject
Функции.
GtkButtonBoxStyle gtk_hbutton_box_get_layout_default(void) gint gtk~hbutton_box_get_spacing_default(void) guint gtk_hbutton_box_get_type(void) GtkWidget *gtk_hbutton_box_new(void) void gtk_hbuttonboxsetlayout_default(
GtkButtonBoxStyle layout) void gtk_hbutton_box_set_spacing_default(gint spacing)
Энумератор
typedef enum {
GTK_BUTTONBOX_DEFAULT_STYLE, GTK_BUTTONBOX_SPREAD, GTK_BUTTONBOX_EDGE,•
gtk2buttonbox_start,
GTK_BUTTONBOX_END
} GtkButtonBoxStyle;
Примеры использования виджета GtkHButtonBox приведены в главе 5.
GtkHPaned
Это контейнер с одной левой и одной правой панелями. Каждая панель может содержать один виджет. Вы можете использовать мышь на полосе, разделяющей панели, чтобы подстроить размеры каждой из них, не меняя размеров всего окна.
Иерархия
GtkHPaned->GtkPaned->GtkContainer->GtkWidget->GtkObj ect
Функции guint gtk_hpaned_get_type(void) GtkWidget *gtkhpaned_new(void)
Пример использования виджета GtkHPaned приведен в главе 5.
GtkHRuler'
Отображает горизонтально расположенную шкалу, которая может содержать деления и указатель текущего положения. С помощью мыши вы можете установить положение указателя внутри программы..
Иерархия ■
GtkHRuler->GtkRuler->GtkWidget->GtkObject,
Функции guint gtk_hruler_get_type(void).
GtkWidget *gtk_hruler_new(void)
В примере отображается окно, показанное на рис. 2L25.
static GtkWidget *makeWidget()
GtkWidget *widget;.
widget = gtk_hruler_new();
gtk_ruler_set_range(GTK_RULER(widget),0.0,100.0, 20.0,10.0);'
return(widget);
Рисунок 21.25. ■
10 ПО 120|Э0140150160170{00 ISO |Ш1ШМ11111111ШМш^10 ПО 120|Э0140150160170{00 ISO |Ш1ШМ11111111ШМш^Горизонтальная линейка со шкалой и указателем положения
10 ПО 120|Э0140150160170{00 ISO |
Ш1ШМ11111111ШМш^
10 ПО 120|Э0140150160170{00 ISO |
Ш1ШМ11111111ШМш^
GtkHScale
Этот виджет представляет собой горизонтальный желоб (паз), содержащий ползунок, который можно передвигать с помощью мыши.
Иерархия
GtkHScale->GtkScale->GtkRange->GtkWidget->GtkObject
Функции
GtkType gtk_hscale_get_type(void)
GtkWidget *gtk_hscale_new(GtkAdjustment *adjustment)
Рисунок 21.26.Горизонтальная шкала с ползунком, установленным в положение 45Рисунок 21.26.Горизонтальная шкала с ползунком, установленным в положение 45В следующем примере создается горизонтальная шкала в диапазоне от 0 до 100, а ползунок устанавливается в положение 45, как показано на рис. 21.26.
Рисунок 21.26.
Горизонтальная шкала с ползунком, установленным в положение 45
Рисунок 21.26.
Горизонтальная шкала с ползунком, установленным в положение 45
static GtkWidget *makeWidget()
GtkWidget *widget;
GtkObject *adjustment;
adjustment = gtk_adjustment_new(45.0,0.0,100.0, 1.0,0.0,0.0);
widget = gtk_hscale_new(GTK_ADJUSTMENT(adjustment)); return(widget);
GtkHScrollbar
Отображает горизонтальную полосу прокрутки с ползунком и двумя кнопками в виде стрелок. Для создания полосы прокрутки необходимо указать начальное и конечное значения, размер ползунка, его начальное положение и шаг, с которым он может перемещаться при щелчке мышью на полосе прокрутки..
Иерархия
GtkHScrollbar-> GtkScrollbar->GtkRange->GtkWidget->GtkObject
Функции
GtkType gtk_hscrollbar_get_type(void)
GtkWidget *gtk_hscrollbar_new(GtkAdjustment *adjustment)
Рисунок 21.27.Горизонтальная полоса прокрутки с ползунком размером в 20% от ее размераРисунок 21.27.Горизонтальная полоса прокрутки с ползунком размером в 20% от ее размераВ приведенном далее примере создается горизонтальная полоса прокрутки в диапазоне от 0 до 100, как показано на рис. 21.27. Установка диапазона указывает, что весь он разбит на 100 делений. Щелчок на стрелках в начале или в конце полосы перемещает ползунок на одну единицу, а щелчок на полосе прокрутки — на 5 единиц. Ширина ползунка составляет 20 единиц.
Рисунок 21.27.
Горизонтальная полоса прокрутки с ползунком размером в 20% от ее размера
Рисунок 21.27.
Горизонтальная полоса прокрутки с ползунком размером в 20% от ее размера
static GtkWidget *makeWidget()
{
GtkWidget *widget;
GtkObject *adjustment;
adjustment = gtk_adjustment_new(45.0,0.0,100.0,
1.0,5.0,20.0);
widget = gtk_hscrollbar_new(GTK_ADJUSTMENT(adjustment)); return(widget);
}
GtkHSeparator
Виджет рисует горизонтальную линию, служащую разделителем между вертикально расположенными виджетами. Чаще всего он используется в меню.
Иерархия
GtkHSeparator->GtkSeparator->GtkWidget->GtkObject
Функции
GtkType gtk_hseparator_get_type(void)
GtkWidget *gtkhseparator_new(void)
ButtonljButton 2|ButtonljButton 2|В приведенном примере горизонтальный разделитель упаковывается в ящик, разделяющий две кнопки, как показано на рис. 21.28. Если контейнер не выставляет размер разделителя, то необходимо явно указывать его толщину, поскольку по умолчанию толщина разделителя равна 0 и он невидим.
Buttonlj
Button 2|
Buttonlj
Button 2|
Рисунок 21.28.Горизонтальный разделитель между двумя кнопкамиРисунок 21.28.Горизонтальный разделитель между двумя кнопкамиstatic GtkWidget *makeWidget() <
Рисунок 21.28.
Горизонтальный разделитель между двумя кнопками
Рисунок 21.28.
Горизонтальный разделитель между двумя кнопками
GtkWidget *box;
GtkWidget *button;
GtkWidget *separator;
box = gtk_vbox_new(FALSE,0);
button = gtk_button_new_with_label("Button 1");
gtkboxpackstart(GTKBOX(box),button,FALSE,FALSE, 0);
separator = gtk_hseparator_new();
gtk_box_pack_start(GTKBOX(box),separator,FALSE,FALSE,0); gtk_widget_set_usize(separator,0,20);
button = gtk_button_new_with label("Button 2");
gtkboxpackstart(GTK_BOX(box),button,FALSE,FALSE,0);
return(box);
}
Gtklmage
Содержит и отображает объект Gdklmage.
Иерархия
GtkImage->GtkMisc->GtkWidget->GtkObject
Функции
void gtk_image_get(Gtklmage ♦image, Gdklmage **val, GdkBitmap **mask)
GtkType gtk_image_get_type(void)
GtkWidget *gtk_image_new(Gdklmage *val, GdkBitmap *mask) void gtk_image_set(GtkImage *image, Gdklmage *val, . GdkBitmap *mask) В примере создаются объект Gdklmage и для его отображения виджет Gtklmage. По умолчанию цвет объекта Gdklmage черный, а путем перебора значений х и у в цикле рисуется белая буква X (крест из угла в угол), как показано на рис. 21.29. static GtkWidget *makeWidget()
{.Рисунок 21.29.
J^ *'Объект Gdklmage,
GtkWidget *widget;отображаемый
GdkVisual *visual;виджетом Gtklmage
Gdklmage *gdkimage; visual = gdk_visual_get_system(); gdkimage = gdk_image_new(GDK_IMAGE_NORMAL,visual,100,100); for(x=0; x<100; x++) { у = x; gdk_image_put_pixel(gdkimage,x,у,OxFFFFFFFF); у » 100 - x; gdk_image_put_pixel(gdkimage,x,у,OxFFFFFFFF); } widget = gtk_image_new(gdkimage,NULL); return(widget);
}
Gtklnput Dialog
Окно предназначено специально для использования в программном обеспечении, которое управляет доступом к устройствам XInput (устройства ввода, иные, чем мышь и клавиатура)..
Иерархия
GtkInputDialog->GtkDialog->GtkWindow->GtkBin->GtkContainer->GtkWidget-> GtkObject
Функции
GtkType gtk_input_dialog_get_type (void) .GtkWidget *gtk_input_dialog_new(void) Сигналы "disable_device"void cb(GtkWidget *, gint, gpointer)
"enable_device"void cb(GtkWidget *, gint, gpointer)
Пример демонстрирует окно, показанное на рис. 21.30. static void makeWidget() {
GtkWidget «dialog;Рисунок 21.30.
dialog = gtk_input_dialog_new();Принятое no
gtk_widget_show_all (dialog);умолчанию
}окно виджета
GtklnputDialog
Gtklnvisible
Виджет выводит пустое окно. Он может использоваться для создания заполнения. Его размеры можно установить при обращении к функции gtk_widget_usize(), данный виджет можно применять внутри контейнера для облегчения размещения других виджетов.
Иерархия
GtkInvisible->GtkBin->GtkContainer->GtkWidget->GtkObject
Функции
GtkType gtk_invisible_get_type(void)
GtkWidget *gtk_invisible_new(void)
Left Button, Right ButtonLeft Button, Right ButtonРисунок 21.31.Невидимый виджет, разделяющий две кнопкиРисунок 21.31.Невидимый виджет, разделяющий две кнопкиВ приведенном примере в горизонтальный ящик вставляются две кнопки, что показано на рис. 21.31. Две кнопки разделены виджетом Gtklnvisible шириной 30 пикселов и высотой 60 пикселов. Поскольку виджет Gtklnvisible самый "высокий", то контейнер определяет полную высоту именно по нему. Это приводит к тому, что кнопки растягиваются по вертикали, заполняя весь ящик.
Left Button, Right Button
Left Button, Right Button
Рисунок 21.31.
Невидимый виджет, разделяющий две кнопки
Рисунок 21.31.
Невидимый виджет, разделяющий две кнопки
GtkWidget *makeWidget() {
GtkWidget *box;
GtkWidget *button;
GtkWidget *invisible;
box = gtk_hbox_new(FALSE, 0);
button = gtk_button_new_with_label("Left Button"); gtk_box_pack_start(GTK_BOX(box),button,FALSE,FALSE, 0);
invisible = gtk_invisible_new();
gtk_widget_set_usize(invisible,30,60);. _,,-
gtkboxpackstart(GTKBOX(box),invisible,FALSE,FALSE,0);
button = gtk_button_new_with_label("Right Button");'
gtkboxpackend(GTK BOX(box),button,FALSE,FALSE,0);ч . ,. f .
return(box);"
Gtkltem
Этот виджет предназначен выступать в роли базового класса для виджетов, которые можно выделить (выбрать) и снять с них выделение. Виджеты, порожденные от Gtkltem, — это GtkCheckMenuItem, GtkListltem, GtkMenuItem, GtkPixmapMenuItem, GtkRadioMenuItem, GtkTearoffMenuItem и GtkTreeltem.
Иерархия
GtkItem->GtkBin->GtkContainer->GtkWidget->GtkObject
Функции
void gtk_item_deselect(Gtkltem *item)
GtkType gtk_item_get_type(void)
void gtk_item_select(Gtkltem *item)
void gtk~item_toggle(Gtkltem *item)
Сигналы "deselect"voidcb(GtkWidget*,gpointer)
"select"voidcb(GtkWidget*,gpointer)
"toggle"voidcb(GtkWidget*,gpointer)
GtkltemFactory
Вспомогательный объект, предназначенный для создания меню. Он считывает данные из массива структур GtkltemFactoryEntry, чтобы определить содержимое меню.
Наследование
GtkItemFactory->GtkObject
Функции void gtk_item_factories_path_delete( const gchar *ifactory_path, const gchar *path) void gtkitemfactory_add_foreign(GtkWidget *accel_widget, const gchar *full_path, GtkAccelGroup *accel__group, guint keyval, GdkModifierType modifiers) void gtk_item_factory_construct(GtkltemFactory *ifactory, GtkType container_type, const gchar *path, GtkAccelGroup *accel_group) void gtk_item_factory_create_item(GtkltemFactory *ifactory, GtkltemFactoryEntry *entry, gpointer callback_data, guint callbacktype) void gtk_item_factory_create_iterns(GtkltemFactory *ifactory, guint n_entries, GtkltemFactoryEntry *entries, gpointer callback_data)'
void gtk_item_factory_create_items_ac(
GtkltemFactory *ifactory, guint reentries,
GtkltemFactoryEntry *entries, gpointer callback_data, guint callback_type) void gtk_item_factory_create_menu_entries(guint n_entries, GtkMenuEntry *entries) void gtkitemfactory_delete_entries(
GtkltemFactory *ifactory, guint n_entries, GtkltemFactoryEntry *entries) void gtkitemfactory_delete_entry(GtkltemFactory *ifactory, GtkltemFactoryEntry *entry) void gtk_item_factory_delete_item(GtkltemFactory *ifactory, const gchar *path) void gtk_item_factory_dump_iterns(GtkPatternSpec *path_pspec, gboolean modified_only, GtkPrintFunc print_func, gpointer func_data) void gtk_item_factory_dump_rc(const gchar *file_name, GtkPatternSpec *path_pspec, gboolean modified_only) GtkltemFactory *gtk_item_factory_from_path(const gchar *path) GtkltemFactory *gtk_item_factory_from_widget(
GtkWidget *widget)
GtkWidget *gtk_item_factory_get_itern(
GtkltemFactory *ifactory, const gchar *path)
GtkWidget *gtk_item_factory_get_item_by_action(
GtkltemFactory *ifactory, guint action)
GtkType gtk_item_f actory_get_type (void) GtkWidget *gtk_item_factory_get_widget( GtkltemFactory *ifactory, const gchar *path)
GtkWidget *gtk_item_factory_get_widget_by_action( GtkltemFactory *ifactory, guint action)
GtkltemFactory *gtk_item_factory__new(GtkType container_type, const gchar *path, GtkAccelGroup *accel_group) void gtk_item_factory_parse_rc(const gchar *file_name) void gtk_item_factory_parse_rc_scanner(GScanner *scanner) void gtk_item_factory_parse_rc_string(const gchar *rc_string) gchar *gtk_item_factory_path_from_widget(GtkWidget *widget) void gtk_itemfactory_popup(GtkltemFactory *ifactory, guint x, guint y, guint mouse_button, guint32 time) gpointer gtk_item_factory_popup_data(
GtkltemFactory *ifactory) gpointer gtk_item_factory_popup_data_from_widget ( GtkWidget *widget) void gtk_item_factory_popup_with_data( GtkltemFactory *ifactory, gpointer popup_data, GtkDestroyNotify destroy, guint x, guint y, guint mouse_button, guint32 time) void gtk_item_factory_print_func(gpointer FILE_pointer, gchar *string) void gtk_item_factory_set_translate_func( GtkltemFactory *ifactory, GtkTranslateFunc func, gpointer data, GtkDestroyNotify notify)
GtkltemFactory оставлен в GTK только для обратной совместимости. Был разработан более удобный способ создания меню. Примеры создания меню и панелей инструментов приведены в главе 8.
GtkLabel .
Виджет GtkLabel отображает строку текста. '
Иерархия
GtkLabe1->GtkMisc->GtkWidget->GtkOb ject
Функции
void gtk_label_get(GtkLabel *label, char **str)
GtkType gtk_label_get_type(void)
GtkWidget *gtk_label^new(const char *str) guint gtk_label_parse_uline(GtkLabel *label, const gchar *string) void gtk_label_set_justify(GtkLabel *label, GtkJustification jtype) void gtk_label_set_line_wrap(GtkLabel *label, gboblean wrap) void gtk_label_set_pattern(GtkLabel *label, const gchar *pattern) void gtklabelsettext(GtkLabel ♦label, const char *str)
Энумератор
typedef enum { GTKJUSTIFYLEFT, GTK_JUSTIFY_RIGHT, GTK_JUSTIFY_CENTER, GTK_JUSTIFY_FILL ' } GtkJustification;
В примере отображается окно, показанное на рис. 21.32.
static GtkWidget *makeWidget() {
GtkWidget *widget;
widget = gtk_label_new("Label String"); return(widget);
Label StringLabel String}
Label String
Label String
Рисунок 21.32.
Виджет GtkLabel, отображающий текст
GtkLayout.
Вы можете применять этот виджет-контейнер для размещения виджетов в виртуальном окне, размеры которого гораздо больше, чем видимая в настоящий момент область. Для просмотра различных частей окна используются горизонтальные и вертикальные полосы прокрутки.
Иерархия
GtkLayout->GtkContainer->GtkWidget->GtkObj ect
Функции•
void gtk_layout_freeze(GtkLayout *layout)
GtkAdjustment *gtk_layout_get_hadjustment(GtkLayout *layout)
GtkType gtk_layout_get_type(void)
GtkAdjustment *gtk_layout_get_vadjustment(GtkLayout *layout)
void gtk_layout_move(GtkLayout *layout,
GtkWidget *child__widget, gint x, gint y)
GtkWidget *gtk_layout_new(GtkAdjustment *hadjustment,
GtkAdjustment *vadjustment)
void gtk_layout_put(GtkLayout *layout, GtkWidget *child_widget, gint x, gint y)
void gtk_layout_set_hadjustment(GtkLayout *layout,
GtkAdjustment *adjustment)
void gtk_layout_set_size(GtkLayout *layout, guint width, guint height)
void gtk_layout_set_vadjustment(GtkLayout *layout, GtkAdjustment *adjustment).
void gtk_layout_thaw(GtkLayout *layout)
Сигнал
"set_scroll_adjustments" void cb(GtkWidget *, GtkAdjustment
♦, GtkAdjustment *, gpointer)
Пример контейнера GtkLayout приведен в главе 5.
GtkList■
Этот контейнер управляет списком пунктов текста, позволяя выбрать один или более пунктов.
Иерархия
GtkList->GtkContainer->GtkWidget->GtkObj ect
Функции
void gtk_list_append_iterns(GtkList *list, GList *items)
gint gtk_list_child_position(GtkList *list, GtkWidget *child)
void gtk_list_clear_iterns(GtkList *list, gint start, gint end)
void gtk_list_end_drag_selection(GtkList *list)
void gtk_list_end_selection(GtkList *list)
void gtk_list_extend_selection(GtkList *list,
GtkScrollType scroll_type, gfloat position, gboolean auto_start_selection)■.
GtkType gtk_list_get_type(void) void gtk_list_insert_items(GtkList *list, GList *items, gint position)
GtkWidget *gtk_list_new(void)
void gtk_list_prepend_iterns(GtkList *list, GList *items)
void gtk_list_remove_iterns(GtkList *list, GList *items)
void gtk_list_remove_items_no_unref(GtkList *list,v
GList *items)
void gtk_list_scroll_horizontal(GtkList *list, GtkScrollType scroll__type, gfloat position) void gtk_list_scroll_vertical(GtkList *list,•* - •
GtkScrollType scroll_type, gfloat position)
void gtk_list_select_all(GtkList *list)
void gtk_list_select_child(GtkList *list, GtkWidget *child)
void gtk_list_select_item(GtkList *list, gint item)
void gtk_list_set_selection_mode(GtkList *list,.-
GtkSelectionMode mode)
void gtk_list_start_selection(GtkList *list) void gtk_list_toggle_add_mode(GtkList *list) void gtk_list_toggle_focus_row(GtkList *list) void gtk_list_toggle_row(GtkList *list, GtkWidget *item) void gtk_list_undo_selection(GtkList *list) void gtk_list_unselect_all(GtkList *list) void gtk_list_unselect_child(GtkList *list, GtkWidget *child) void gtk_list_unselect_item(GtkList *list, gint item)
Энумераторы
typedef enum { GTK_SCROLL_NONE, GTK_SCROLL_STEP_BACKWARD,'
GTK_SCROLL_STEP_FORWARD,'
GTK_SCROLL_PAGE_BACKWARD,-- ---
GTK_SCROLL_PAGE_FORWARD,'
GTK_SCROLL_JUMP■
} GtkScrollType;r
typedef enum {
GTK_SELECTION_SINGLE,
GTK_SELECTION_BROWSE,*
GTK_SELECTION_MULTIPLE, GTK_SELECTION_EXTENDED } GtkSelectionMode;-
Сигналы
"select_child" void cb(GtkWidget *, GtkWidget *, gpointer) "selection changed" void cb(GtkWidget *, gpointer) "unselect_child" void cb(GtkWidget *, GtkWidget *, gpointer)
В примере создается список виджетов GtkListltem и вставляется в GtkList. Виджет GtkListltem может сам себя отображать, будучи выбранным (выделенным) или
Рисунок 21.33.Виджет GtkList с одним выбранным пунктомРисунок 21.33.Виджет GtkList с одним выбранным пунктомневыбранным, а виджет GtkList реагирует на события мыши и осуществляет переключение выбора, что показано на рис. 21.33.
Рисунок 21.33.
Виджет GtkList с одним выбранным пунктом
Рисунок 21.33.
Виджет GtkList с одним выбранным пунктом
static GtkWidget *makeWidget()
{
GtkWidget *list;
GList *glist;
glist=NULL;
glist = g_list append(glist, gtk_list_item_new_with_label("Maximum"));
glist = g_list_append(glist, gtk_list_item_new_with_label("Minimum"));
glist = g_list_append(glist, gtk_list_item_new_with_label("Average"));
glist = g_list_append(glist, gtk_list_item_new_with_label("Projection"));
list = gtk_list__new();
gtk_list appenditems(GTK_LIST(list),glist); return(list);
GtkListltem
Может быть включен в виджет GtkList, что позволяет вам выбирать элементы (пункты). Обычно виджет GtkListltem содержит текст, но, поскольку он порожден от GtkBin, в нем может содержаться любой виджет.
Иерархия
GtkListItem->GtkItem->GtkBin->GtkContainer->GtkWidget->GtkObject
Функции
void gtk_list_item_deselect(GtkListItem *list_item)
GtkType gtk_list_item_get_type(void)
GtkWidget *gtk_listitem_new(void)
GtkWidget *gtk_list_item_new_with_label(const gchar *label)
void gtklist item_select(GtkListltem *list_item)
Сигналы
"endselection" void cb(GtkWidget *, gpointer)
"extendselection" void cb(GtkWidget *, gint, gfloat, gboolean, gpointer)
"scrollhorizontal" void cb(GtkWidget *, gint, gfloat, gpointer)
"scrollvertical"
void cb(GtkWidget
*, gint, gfloat, gpointer)
"selectall"
void cb(GtkWidget
*, gpointer)
"startselection"
void cb(GtkWidget
*, gpointer)
"togg1e addmode"
void cb(GtkWidget
*, gpointer)
"toggle focus row"
void cb(GtkWidget
*, gpointer)
"undoselection"
void cb(GtkWidget
*, gpointer)'
"unselect all"
void cb(GtkWidget
*, gpointer)
Пример использования GtkListltem см. ранее в этой главе при описании GtkList.
GtkMenu
Этот виджет-контейнер предназначен для работы в качестве опускающегося меню.
Иерархия
GtkMenu->GtkMenuShell->GtkContainer->GtkWidget->GtkObject
Функции void gtk_menu_append(GtkMenu *menu, GtkWidget *chiId) void gtk_menu_attach_to_widget(GtkMenu *menu, GtkWidget *attach_widget, GtkMenuDetachFunc detacher) void gtk_menu_detach(GtkMenu *menu) GtkAccelGroup *gtk_menu_ensure_uline_accel_group(
GtkMenu *menu)
GtkAccelGroup *gtk_menu_get_accel_group(GtkMenu *menu) GtkWidget *gtk_menu_get_active(GtkMenu *menu) GtkWidget *gtk_menu_get_attach_widget(GtkMenu *menu) GtkType gtk_menu_get_type(void) GtkAccelGroup *gtk_menu_get_uline_accel_group(GtkMenu *menu) void gtk_menu_insert(GtkMenu *menu, GtkWidget *chiId, gint position)
GtkWidget *gtk_menu_new(void) void gtk_menu_popdown(GtkMenu *menu) void gtk_menu_popup(GtkMenu *menu, GtkWidget *parent_menu_shell, GtkWidget *parent_menu_item, GtkMenuPositionFunc func, gpointer data, guint button, guint32 activatetime) void gtk_menu_prepend(GtkMenu *menu, GtkWidget *chiId) void gtkmenu reorder child(GtkMenu *menu, GtkWidget *chiId, gint position) void gtk_menu reposition(GtkMenu *menu) void gtk_menu_set_accel_group(GtkMenu *menu, GtkAccelGroup *accel_group) void gtk_menu_set_active(GtkMenu *menu, guint index) void gtk_menu_set_tearoff_state(GtkMenu *menu, gboolean torn_off) void gtk_menu_set_title(GtkMenu *menu, const gchar *title)'
Рисунок 21.34.Меню с подменюРисунок 21.34.Меню с подменюВ примере создается строка меню, содержащая одно меню, которое, в свою очередь, содержит подменю, как показано на рис. 21.34. Создание меню сводится к созданию каждой отдельной части и соединению всех частей в единое целое.
Рисунок 21.34.
Меню с подменю
Рисунок 21.34.
Меню с подменю
Вызов gtk_menu_new () создает виджет GtkMenu, который может содержать список пунктов меню. Каждый пункт, который необходимо добавить в меню, создается обращением к функции gtk_menu_item_new_with_label ( ). В процессе создания подменю подключается к родительскому меню путем вызова gtk_menu_append (). Каждое меню вставляется в строку главного меню с помощью обращения к функции gtk__menu__bar_append ().
static GtkWidget *makeWidget() {
GtkWidget *fileMenu;
GtkWidget *fileNewMenu;
GtkWidget *fileltem;
GtkWidget *fileNewItem;
GtkWidget *menuBar;
/* Create the 'new' menu */
fileNewMenu = gtkmenu_new();
fileNewItem = gtk_menu_item_new_with_label("Template"); gtk_menu_append(GTK_MENU(fileNewMenu),fileNewItem);
fileNewItem = gtk_menu item_new_with_label("Empty");
gtk_menu_append(GTK_MENU(fileNewMenu),fileNewItem);
/* Create the 'file' menu */ fileMenu = gtk_menu_new(); fileitem = gtk_menu_item_new_with_label("Open");
gtk_menu_append(GTK_MENU(fileMenu),fileitem);
fileitem = gtk_menu_item_new_with_label("Close");
gtk_menu_append(GTK_MENU(fileMenu),fileitem);
fileitem = gtk_menu_item_new_with_label("Save");
gtk_menu_append(GTK_MENU(fileMenu),fileitem);
/* Attach 'new' menu to 'file' menu */
fileitem = gtk_menu_item_new_with_label("New");
gtk_menu_append(GTK_MENU(fileMenu),fileitem);
gtk_menu_item_set_submenu(GTK_MENU_ITEM(fileitem), fileNewMenu);
/* Add the label on top of the 'file' menu */ fileitem = gtk_menu_item_new_with_label("File"); gtk_menu_item_set_submenu(GTK_MENU_IТЕМ(fileitem),*
fileMenu);
/* Append the 'file' menu to the menu bar */ menuBar = gtk_menu_bar_new();
gtk_menu_bar_append(GTK_MENU_BAR(menuBar),fileitem);
return(menuBar); }
GtkMenuBar
Это контейнер, предназначенный для управления набором опускающихся меню. Он отображает метку (надпись) для каждого содержащегося в нем меню.
Иерархия
GtkMenuBar->GtkMenuShell->GtkContainer->GtkWidget->GtkObject
Функции
void gtk_menu_bar_append(GtkMenuBar *menu_bar, GtkWidget *child)
GtkType gtk_menu_bar_get_type(void)
void gtk_menu_bar_insert(GtkMenuBar *menu_bar,
GtkWidget *child, gint position)
GtkWidget *gtk_menu_bar_new(void)'
void gtk_menu_bar_prepend(GtkMenuBar *menu_bar, GtkWidget *child)
void gtk_menu_bar_set_shadow_type(GtkMenuBar *menu_bar, GtkShadowType type)
Энумератор typedef enum {.
GTK_SHADOW_NONE,■
GTK_SHADOW_IN,
GTK_SHADOW_OUT,
GTK_SHADOW_ETCHED_IN,
GTK_SHADOW_ETCHED_OUT } GtkShadowType;
Пример использования GtkMenuBar см. в описании GtkMenu.
GtkMenultem
Это виджет, который можно вставить в меню. Он может отображать текст и работать в качестве заголовка подменю.
Иерархия
GtkMenuItem->GtkItem->GtkBin->GtkContainer->GtkWidget->GtkObject
Функции
void gtk_menu_item_activate(GtkMenultem *menu_item)
void gtk_menu_item_configure(GtkMenultem *menu_item,
gint show_toggle_indicator, gint show_submenu_indicator) void gtk_menu_item_deselect(GtkMenultem *menu_item) GtkType gtk_menu_item_get_type(void) GtkWidget *gtk_menu_item_new(void) GtkWidget *gtk_menu_item_new_with_label(const gchar *label) void gtk_menu_item_remove_submenu(GtkMenultem *menu_item) void gtk_menu_item_right_justify(GtkMenultem *menuitem) void gtk_menu_item_select(GtkMenultem *menu_item) void gtk_menu_item_semplacement(GtkMenultem *menu_item, GtkSubmenuPlacement placement)
void gtk_menu_item_set_submenu(GtkMenultem *menu_item, GtkWidget *submenu)
Энумераторы
typedef enum {
GTK_DIRECTION_LEFT,
GTK_DIRECTION_RIGHT } GtkSubmenuDirection;
Сигнал
"activate" void cb(GtkWidget *, gpointer)
Пример использования GtkMenultem см. в описании GtkMenu.
GtkMenuShell
Это базовый класс для GtkMenu и GtkMenuBar.
Иерархия
GtkMenuShell->GtkContainer->GtkWidget->GtkObject
Функции
void gtk_menu_shell_activate_item(GtkMenuShell *menu_shell,
GtkWidget *menu item, gboolean force_deactivate) void gtk_menu_shell_append(GtkMenuShell *menu_shell, GtkWidget *child) void gtk_menu_shell_deactivate(GtkMenuShell *menu_shell) void gtk_menu_shell_deselect(GtkMenuShell *menu_shell) GtkType gtk_menu_shell_get_type(void) void gtk_menu_shell_insert(GtkMenuShell *menu_shell, GtkWidget *child, gint position)
void gtk_menu_shell_prepend(GtkMenuShell *menu_shell, GtkWidget *child)
void gtk_menu_shell_select_item(GtkMenuShell *menu_shell, GtkWidget *menu_item)
Сигналы
"activate_current" void cb(GtkWidget *, gboolean, gpointer) "cancel"void cb(GtkWidget *, gpointer)
"deactivate"voidcb(GtkWidget*,gpointer)
"movecurrent"voidcb(GtkWidget*,GtkMenuDirectionType,gpointer)
"selection-done"voidcb(GtkWidget*,gpointer)
GtkMisc
Это базовый класс, который обеспечивает настройку (выравнивание) и задание интервалов для целого ряда отображаемых виджетов.
Иерархия
GtkMisc->GtkWidget->GtkObject
Функции
GtkType gtkmisc get_type(void)
void gtk_misc_set_alignment(GtkMisc *misc, gfloat xalign, gfloat yalign)
void gtk_misc_set_padding(GtkMisc *misc, gint xpad, gint уpad)
GtkNotebook
Объект GtkNotebook - это контейнер, который за один раз отображает один из содержащихся в нем виджетов. Наверху изображения имеется ряд клавиш, через которые с помощью мыши можно получить доступ к отдельным виджетам.
Иерархия.
GtkNotebook->GtkContainer->GtkWidget->GtkObject
Функции
void gtknotebook append page(GtkNotebook *notebook,
GtkWidget *child, GtkWidget *tab_label)
void gtk_notebook_append_page_menu(GtkNotebook *notebook,
GtkWidget *child, GtkWidget *tab_label,
GtkWidget *menu_label)
gint gtk_notebook_get_current_page(GtkNotebook *notebook)
GtkWidget *gtk_notebook_get_menu_label(GtkNotebook *notebook,
GtkWidget *child)
GtkWidget *gtk_notebook_get nth page(GtkNotebook *notebook, gint page_num)
GtkWidget *gtknotebook_get_tab_label(GtkNotebook *notebook,
GtkWidget *child)
GtkType gtknotebookget type(void)
void gtknotebookinsert page(GtkNotebook *notebook,
GtkWidget *child, GtkWidget *tab_label, gint position)
void gtk_notebook_insert_page_menu(GtkNotebook *notebook,
GtkWidget *child, GtkWidget *tab label,
GtkWidget *menu_label, gint position)
GtkWidget *gtk_notebook_new(void)
void gtk_notebook_next_page(GtkNotebook *notebook)
gint gtk_notebook_page_num(GtkNotebook *notebook,
GtkWidget *child)
void gtk notebook popup_disable(GtkNotebogk *notebook)
void gtk_notebook popup enable(GtkNotebook *notebook)
void gtk_notebook_prepend_page(GtkNotebook *notebook,
GtkWidget *child, GtkWidget *tab_label)
void gtk notebook_prepend_page_menu(GtkNotebook *notebook,
• GtkWidget *child, GtkWidget *tab_label,
GtkWidget *menu_label)
void gtknotebookprev page(GtkNotebook *notebook)
void gtk_notebook_query_tab_label_packing(
. GtkNotebook *notebook, GtkWidget *child, gboolean *expand, gboolean *fill, GtkPackType *pack_type)
void gtk_notebook_remove_page(GtkNotebook *notebook, gint page_num)
void gtk_notebook_reorder_chiId(GtkNotebook *notebook, GtkWidget *child, gint position)
void gtk_notebook_set_homogeneous_tabs(GtkNotebook *notebook, gboolean homogeneous)
void gtk_notebook_set_menu_label(GtkNotebook *notebook, GtkWidget *child, GtkWidget *menu_label)
void gtk_notebook_set_menu_label_text(GtkNotebook *notebook, GtkWidget *child, const gchar *menu_text)
void gtk_notebook_set_page(GtkNotebook *notebook, gint page_num)
void gtk_notebook_set_scrollable(GtkNotebook *notebook, gint scrollable)
void gtk_notebook_set_show_border(GtkNotebook *notebook,
gint show_border)
void gtk_notebook_set_show_tabs(GtkNotebook *notebook, gboolean show_tabs)
void gtk_notebook_set_tab_border(GtkNotebook *notebook, guint tabborder)
void gtk_notebook_set_tab_hborder(GtkNotebook *notebook, guint tab_hborder)
void gtk_notebook_set_tab_label(GtkNotebook *notebook, GtkWidget *child, GtkWidget *tab_label)
void gtk_notebook_set_tab_label_packing(
GtkNotebook *notebook, GtkWidget *child, gboolean expand, gboolean fill, GtkPackType pack_type)
void gtknotebooksettablabel text(GtkNotebook *notebook, GtkWidget *child, const gchar *tab_text)
void gtk_notebook_set_tab_pos(GtkNotebook *notebook, GtkPositionType pos)
void gtk_notebook_set_tab_vborder(GtkNotebook *notebook, guint tabvborder)
Энумераторы
typedef enum {
GTK_POS_LEFT,
GTK_POS_RIGHT,
GTK_POS_TOP, GTKPOSBOTTOM
} GtkPositionType;
typedef enum {
GTK_PACK_START,
GTK_PACK_END
} GtkPackType;
Сигнал
"switchpage" void cb(GtkWidget *, gpointer, guint, gpointer)
Пример использования GtkNotebook приведен в главе 5.
GtkObject
Это базовый класс для всех объектов GTK+.
Иерархия
GtkObject
Функции
gchar *Gtk_object_args_collect(GtkType object_type, GSList **arg_list_p, GSList **info_list_p, const gchar *first_arg_name, va_list var_args) void gtk_object_add_arg_type(const char *arg_name, GtkType arg_type, guint arg_flags, guint arg_id) void gtk_object_arg_get(GtkObject *object, GtkArg *arg, GtkArglnfo *info)
gchar *gtk_object_arg_get_infо(GtkType object_type, const gchar *arg_name, GtkArglnfo **info_p)
void gtk_object_arg_set(GtkObject ♦object, GtkArg *arg, GtkArglnfo *info)
void gtk_object_class_add_signals(GtkObjectClass *class, guint *signals, guint nsignals)
guint gtk_object_class_user_signal_new(GtkObjectClass *class, const gchar *name, GtkSignalRunType signal_flags, GtkSignalMarshaller marshaller, GtkType return_val, guint nparams, ...)
guint gtk_object_class_user_signal_newv(
GtkObjectClass *class, const gchar *name, GtkSignalRunType signal_flags, GtkSignalMarshaller marshaller, GtkType return_val, guint nparams, GtkType *params)
void gtk_object_constracted(GtkObject *object)
void gtk_object_default_construct(GtkObject ♦object)
void gtk_object_destroy(GtkObject *object) •
gpointer gtk_object_get_data(GtkObject *object, const gchar *key)
gpointer gtk_object_get_data_by_id(GtkObject *object,-
GQuark data_id)
GtkType gtk_object_get_type(void)
gpointer gtk_object_get_user_data(GtkObject *object)
void gtk_object_getv(GtkObject *object, guint n_args, GtkArg *args)
void gtk_object_init_type(void)
GtkObject *gtk_object_new(GtkType object_type, const gchar *first_arg_name, ...)
GtkObject *gtk_object_newv(GtkType object_type, guint n_args, GtkArg *args)
void gtk_object_post_arg_parsing_init(void)
GtkArg *gtk_object_query_args(GtkType class_type, guint32 **arg_flags, guint *n__args)
void gtk_object_ref(GtkObject *object)
void gtk_object_remove_data(GtkObject *object, const gchar *key)
void gtk_object_remove_data_by_id(GtkObject *object, GQuark data_id)
void gtk_object_remove_no_notify(GtkObject *object, ' const gchar *key)
void gtk_object_remove_no_notify_by_id(GtkObject *object, GQuark keyid)
void gtkobjectset(GtkObject ♦object,
const gchar *first_arg_name, ...)
void gtk_object_set_data(GtkObject *object, const gchar *key, gpointer data)
void gtk_object_set_data_by_id(GtkObject *object, GQuark data_id, gpointer data)
void gtk_object_set_data_by_id_fnil(GtkObject *object, GQuark data_id, gpointer data, GtkDestroyNotify destroy)
void gtk_object_set_data_full(GtkObject *object,
const gchar *key, gpointer data, GtkDestroyNotify destroy) void gtk_object_set_user_data(GtkObject *object, gpointer data) void gtk_object_setv(GtkObject *object, guint n_args, GtkArg *args)
void gtk_object_sink(GtkObject *object)
void gtk_object_unref(GtkObject *object)
void gtk_object_weakref(GtkObject *object, GtkDestroyNotify notify, gpointer data) void gtk_object_weakunref(GtkObject *object, GtkDestroyNotify notify, gpointer data) void gtk_trace_referencing(GtkObject *object, const gchar *func, guint dummy, guint line, gboolean do_ref)
Энумераторы
typedef enum { GTK_RUN_FIRST, GTK_RUN_LAST, GTK_RUN_BOTH, GTK_RUN_NO_RECURSE, GTK_RUN_ACTION, GTK_RUN_NO_HOOKS
} GtkSignalRunType;
Сигнал
"switch_page" void cb(GtkWidget *, gpointer, guint, gpointer)
GtkOptionMenu
Этот контейнер способен управлять одноуровневым меню, которое может быть использовано для выбора одного из нескольких вариантов. Обычно этот виджет свернут, и отображается только текущий выбранный вариант.
Иерархия
GtkOptionMenu->GtkButton->GtkBin->GtkContainer->GtkWidget->GtkObject
Функции
GtkWidget *gtk_option_menu_get_menu( GtkOptionMenu *option_menu)
GtkType gtk_option_menu_get_type(void)
GtkWidget *gtk option_menu_new(void)
void gtk_option_menu_remove_menu(GtkOptionMenu *option_menu) void gtk_option_menu_set_history(GtkOptionMenu *option_menu, guint index)
void gtk_option_menu_set_menu(GtkOptionMenu *option_menu, GtkWidget *menu)
В этом примере создается трехкнопочное меню и вставляется в виджет GtkOptionMenu, с помощью которого оно отображается и управляется. На рис. 21.35 показан внешний вид виджета в свернутом и развернутом состояниях.
static GtkWidget *makeWidget() {
GtkWidget *optionmenu;
GtkWidget *menu;
GtkWidget *item;
menu = gtk_menu_new();
item = gtk_menu_item_new_with_label("Open");
gtk_menu_append(GTK_MENU(menu),item);
item = gtkmenu item_new_with_label("Close");
gtk_menu_append(GTK_MENU(menu),item);
item = gtk_menu_item_new_with_label("Save");
gtk_menu_append(GTK_MENU(menu),item);
optionmenu = gtk_option_menu_new();
gtkoptionmenu set menu(GTKOPTION MENU(optionmenu),menu);
return(optionmenu); }
Рисунок 21.35.
Два состояния виджета GtkOptionMenu
GtkPacker
Виджет GtkPacker — это контейнер, предоставляющий функции, которые позволяют вашей программе осуществлять управление с помощью правил позиционирования виджетов и задания интервалов между ними. Интервалы и размеры в правилах задаются в относительных величинах, таким образом, схема размещения автоматически подстраивается под высочу и ширину контейнера.
Иерархия
GtkPacker->GtkContainer->GtkWidget->GtkObject
Функции
void gtk_packer_add(GtkPacker *packer, GtkWidget *child,
GtkSideType side, GtkAnchorType anchor,
GtkPackerOptions options, guint border^width, guint pad_x, guint pad_y, guint ipadx, guint i_pad_y)
void gtk_packer_add defaults(GtkPacker *packer,
GtkWidget *child, GtkSideType side, GtkAnchorType anchor, GtkPackerOptions options)
GtkType gtk_packer_get_type(void)
GtkWidget *gtk_packer_new(void)
void gtk_packer_reorder_child(GtkPacker *packer,
GtkWidget *child, gint position)
void gtk_packer_set_child_packing(GtkPacker *packer,
GtkWidget *child, GtkSideType side, GtkAnchorType anchor, GtkPackerOptions options, guint border__width, guint pad_x, guint pad_y, guint i_pad_x, guint i_pad_y)
void gtk_packer_set_default_border_width(GtkPacker *packer, guint border)
void gtk_packer_set default_ipad(GtkPacker *packer, guint i_pad_x, guint i_pad_y)
void gtk_packer_set_default_pad(GtkPacker *packer, guint pad_x, guint pad_y)
void gtk_packer_set spacing(GtkPacker *packer, guint spacing) Энумераторы typedef enum {
GTK_PACK_EXPAND, GTK_FILL_X, GTK_FILL_Y } GtkPackerOptions;.
typedef enum { GTK_SIDE_TOP, GTK_SIDE_BOTTOM, GTK_SIDE_LEFT, GTK_SIDE_RIGHT } GtkSideType;
typedef enum { GTK_ANCHOR_CENTER, GTK_ANCHOR_NORTH, GTK_ANCHOR_NORTH_WEST, GTK_ANCHOR_NORTH_EAST, GTK_ANCHOR_SOUTH, GTK_ANCHOR_SOUTH_WEST, GTK_ANCHOR_SOUTH_EAST, GTK_ANCHOR_WEST, GTK_ANCHOR_EAST, GTK_ANCHOR_N, GTK_ANCHOR_NW, GTK_ANCHOR_NE, ' GTK_ANCHOR_S, GTKANCHORSW, GTKANCHORSE, GTK_ANCHOR_W, GTK_ANCHOR_E } GtkAnchorType;
В следующем примере создается окно, показанное на рис. 21.36. В контейнер вставляются две кнопки, но для каждой из них установлены разные правила.
static GtkWidget *makeWidget()'
{•
GtkWidget *packer; GtkWidget *button; packer = gtk_packer_new();
button = gtk_button_new_with_label("First Button");
gtk_packer_add_defaults(GTK_PACKER(packer),button, GTK_SIDE_LEFT, GTK_ANCHOR_SOUTH, GTK_FILL__Y) ;
button = gtk_button_new_with_label("Second Button"); gtk_packer_add_defaults(GTK_PACKER(packer),button, GTK_SIDE_LEFT,GTK_ANCHOR__CENTER,GTK_PACK_EXPAND);
gtk_widget_set_usize(GTK_WIDGET(packer),200,200);
return(packer);.
Рисунок 21.36.
Виджет GtkPacker с двумя кнопками, использующими разные правила
GtkPaned
Это базовый класс для контейнеров GtkHPaned и GtkVPaned.
Иерархия
GtkPaned->GtkContainer->GtkWidget->GtkObject
Функции
void gtk_paned_addl(GtkPaned *paned, GtkWidget *widget)
void gtk_paned_add2(GtkPaned *paned, GtkWidget *widget)
void gtk_paned_compute_position(GtkPaned *paned,
gint allocation, gint childl_req, gint child2_req)
GtkType gtk_paned_get_type(void)
void gtk_paned pack1(GtkPaned *paned, GtkWidget *widget,,
gboolean resize, gboolean shrink)
void gtk_paned_pack2(GtkPaned *paned, GtkWidget *widget, gboolean resize, gboolean shrink)
void gtk_paned_set_gutter_size(GtkPaned *paned, guintl6 size)
void gtkpanedsethandlesize(GtkPaned *paned, guintl6 size)
void gtkpaned_set_position(GtkPaned *paned, gint position)
GtkPixmap
Этот виджет содержит расположенное в оперативной памяти окно, в нем вы можете создавать изображения, как в обычном окне, но они не отображаются на экране.
Иерархия
GtkPixmap->GtkMisc->GtkWidget->GtkObject
Функции
void gtk_pixmap_get(GtkPixmap *pixmap, GdkPixmap **val, GdkBitmap **mask)
GtkType gtk_pixmap_get_type(void)
GtkWidget *gtk_pixmap_new(GdkPixmap *val, GdkBitmap *mask)
void gtk_pixmap_set(GtkPixmap *pixmap, GdkPixmap *val, GdkBitmap *mask)'
void gtk_pixmap_set_build_.insensitive(GtkPixmap *pixmap, guint build)
Примеры использования GtkPixmap приведены в главе 7.
GtkPixmapMenultem
Виджет используется для позиционирования кнопок меню таким образом, чтобы слева от текста мог появиться растровый рисунок или переключатель. Виджет GtkPixmapMenultem создается автоматически, если это необходимо для меню в GNOME.
Иерархия
GtkPixmapMenuItem->GtkMenuItem->GtkItem->GtkBin->GtkContainer->GtkWidget-> GtkObject
Функции
GtkType gtk_pixmap_menu_item_get_type(void)
GtkWidget *gtk_pixmap_menu_item_new(void)
void gtk_pixmap_menu_item_set_pixmap(
GtkPixmapMenultem *menu_item, GtkWidget *pixmap)
Виджет GtkPixmapMenultem применяется внутри программ, создающих меню. Примеры использования GtkPixmapMenultem приведены в главе 8.
GtkPlug
Виджет представляет собой окно верхнего уровня, которое от создавшего его процесса можно сделать доступным для другого процесса. Для получения доступа к данному виджету другой процесс использует GtkSocket, как если бы он был локальным виджетом.
Иерархия
GtkPlug->GtkWindow->GtkBin->GtkContainer->GtkWidget->GtkObject
Функции
void gtk_plug_construct{GtkPlug *plug, guint32 socketid)
guint gtk_plug_get_type()
GtkWidget *gtk_plug new(guint32 socketid)
GtkPreview
Виджет снабжает вас графическим окном и некоторыми функциями для управления им. Приложения используют данный виджет для предварительного просмотра графических операций и отображения доступных цветов.
Иерархия
GtkPreview->GtkWidget->GtkObject
Функции
void gtk_preview_draw_row(GtkPreview *preview, guchar *data, gint x, gint y, gint w)
GdkColormap *gtk_preview_get_cmap(void)
GtkPreviewInfо *gtk_preview_get_infо(void)
guint gtk_preview_get_type(void)
GdkVisual *gtk_preview_get_visual(void)
GtkWidget *gtk_preview_new(GtkPreviewType type)
void gtk_preview_put(GtkPreview *preview, GdkWindow *window,
GdkGC *gc, gint srcx, gint srcy, gint destx, gint desty, gint width, gint height)
void gtk_preview_reset(void)
void gtk_preview_set_color_cube(guint nredshades,
guint ngreen_shades, guint nblueshades,
guint ngray_shades)
void gtk_preview_set_dither(GtkPreview *preview, GdkRgbDither dither)
void gtk_preview_set_expand(GtkPreview *preview, gint expand)
void gtk_preview_set_gamma(double _gamma)
void gtk_preview_set_install_cmap(gint _install_cmap)
void gtk_preview_set_reserved(gint nreserved)
void gtk_preview_size(GtkPreview *preview, gint width, gint height)
void gtk_preview_uninit(void)
Энумераторы
typedef enum {
GTK_PREVIEW_COLOR,
GTK_PREVIEW_GRAYSCALE } GtkPreviewType;
typedef enum {
GDK_RGB_DITHER_NONE, GDK_RGB_DITHER_NORMAL, GDK_RGB_DITHER_MAX
} GdkRgbDither;
Рисунок 21.37.Окно виджета GtkPreview, отображающее прямоугольникРисунок 21.37.Окно виджета GtkPreview, отображающее прямоугольникВ этом примере создается объект GtkPreview, а затем устанавливается функция обратного вызова, чтобы нарисовать в окне прямоугольник, как показано на рис. 21.37. Рисование должно происходить в функции обратного вызова обязательно после отображения окна на экране, поскольку актуальное окно должно существовать.
Рисунок 21.37.
Окно виджета GtkPreview, отображающее прямоугольник
Рисунок 21.37.
Окно виджета GtkPreview, отображающее прямоугольник
static GtkWidget *makeWidget()
{
GtkWidget *preview;
preview = gtk_preview_new(GTK_PREVIEW_COLOR); gtk_preview_size(GTK_PREVIEW(preview),200,100);
gtk_signal_connect(GTK_OBJECT(preview),"event", GTK_SIGNAL_FUNC(eventDraw),NULL);
return(preview);
}
static gboolean eventDraw(GtkWidget *widget, GdkEvent *event,gpointer data) {
GdkGC *gc;
GdkColor foreground;
GdkColormap *colormap;
colormap = gdk_colormap_get_system();
gc = gdk gc_new(widget->window);
gdk_color_parse("blue",&foreground);
gdk_color^alloc(colormap,&foreground);
gdkgcset foreground(gc,&foreground);
gdkdrawrectangle(widget->window,gc, TRUE,20,10,160,80);
return(TRUE);
i
GtkProgress
Виджет GtkProgress является базовым классом для GtkProgressBar.
Иерархия
GtkProgress->GtkWidget->GtkObject
Функции
void gtk_progress_configure(GtkProgress *progress, gfloat value, gfloat min, gfloat max)
gfloat gtk_progress_get_current_percentage( GtkProgress *progress)
gchar *gtk_progress_get_current_text(GtkProgress *progress)
gfloat gtk_progress_get_percentage_from_value( GtkProgress *progress, gfloat value) gchar *gtk_progress_get_text_fromvalue(
GtkProgress *progress, gfloat value)
GtkType gtk_progress_get_type(void)
gfloat gtk_progress_get_value(GtkProgress *progress)
void gtk_progress_set_activity_mode(GtkProgress *progress, guint activity_mode)
void gtk_progress_set_adjustment(GtkProgress *progress, GtkAdjustment *adjustment)
void gtk_progress_set_format_string(GtkProgress *progress, gchar *format)
void gtk_progress_set_percentage(GtkProgress *progress, gfloat percentage)
void gtk_progress_set_show_text(GtkProgress *progress, gint show_text)
void gtk_progress_set_text_alignment(GtkProgress *progress, gfloat x_align, gfloat y_align)
void gtk_progress_set_value(GtkProgress ^progress, gfloat value)
GtkProgressBar
Виджет отображает перемещающийся индикатор, который показывает процент выполнения нескольких задач.
Иерархия
GtkProgressBar->GtkProgress->GtkWidget->GtkObject
Функции
GtkType gtk_progress_bar_get_type(void)
GtkWidget *gtk_progress_bar_new(void)
GtkWidget *gtk_progress_bar_new_with_adjustment(,
GtkAdjustment *adjustment) void gtk_progress_bar_set activityblocks(
GtkProgressBar *pbar, guint blocks)
void gtk_progress_bar_set_activity_step(GtkProgressBar *pbar, guint step)
void gtk_progress_bar_set_bar_style(GtkProgressBar *pbar, GtkProgressBarStyle bar_style)'
void gtk_progress_bar_set_discrete_blocks( GtkProgressBar *pbar, guint blocks)
void gtk_progress_bar_set_orientation(GtkProgressBar *pbar, GtkProgressBarOrientation orientation)
void gtk_progress_bar_update(GtkProgressBar *pbar,’
gfloat percentage)
Энумераторы
typedef enum {
GTK_PROGRESS_CONTINUOUS, GTK_PROGRESS_DISCRETE
} GtkProgressBarStyle;
typedef enum {
GTK_PROGRESS_LEFT_TO_RIGHT, GTK_PROGRESS_RIGHT_TO_LEFT, GTK_PROGRESS_BOTTOM_TO_TOP, GTK_PROGRESS_TOP_TO_BOTTOM
} GtkProgressBarOrientation;
Рисунок 21.38.Индикатор хода выполнения, показывающий 70%Рисунок 21.38.Индикатор хода выполнения, показывающий 70%Как показано на рис. 21.38, приведенный ниже пример создает горизонтальную движущуюся полосу, которая перемещается от 0 слева и до 100 справа. Для инициализации пределов и текущих установок движения используется виджет GtkAd justment. Для перемещения полосы ваше приложение должно вызвать функцию gtk_progress_bar_update().
Рисунок 21.38.
Индикатор хода выполнения, показывающий 70%
Рисунок 21.38.
Индикатор хода выполнения, показывающий 70%
static GtkWidget *makeWidget() {
GtkWidget *bar;
GtkObject *adjustment;
adjustment = gtk_adjustment_new(70.25,0.0,100.0, 0.25,0.0,0.0);
bar = gtk_progress_bar_new_with_adjustment( GTK_ADJUSTMENT(adjustment));
gtk_progress_bar_set_bar_style(GTK_PROGRESS_BAR(bar), GTK_PROGRESS_CONTINUOUS);
gtk_progress_bar_set_orientation(GTKPROGRESS_BAR(bar), GTK_PROGRESS_LEFT_TO_RIGHT);
return(bar);
GtkRadioButton
Виджеты GtkRadioButton представляют собой переключатели и предназначены для использования в группе, в которой в любое время может быть выбран лишь один из ее элементов.
Иерархия
GtkRadioButton->GtkCheckButton->GtkToggleButton->GtkButton->GtkBin-> GtkContainer->GtkWidget->GtkObject
Функции
GtkType gtk_radio_button_get_type(void)
GSList *gtk_radio_button_group(GtkRadioButton *radio_button)
GtkWidget *gtk_radio_button_new(GSList *group)
GtkWidget *gtk_radio_button_new_from_widget(
GtkRadioButton *group)
GtkWidget *gtk_radio_button_new_with_label(GSList *group, const gchar *label)
GtkWidget *gtk_radio_button_new_with_label_from_widget(
GtkRadioButton *group, const gchar *label)
void gtk_radio_button_set_group(GtkRadioButton *radio_button, GSList *group)
В примере создается набор радиокнопок, показанных на рис. 21.39. Первая кнопка создается обращением к функции gtk_radio_button_new_with_label (), которой в качестве указателя группы передается NULL. Для создания следующей кнопки необходимо получить указатель GSList на группу и использовать его вместо NULL при вызове функции gtk_radio_button_new_with_label (). При создании третьей кнопки необходимо снова извлечь указатель на группу, поскольку старый указатель может уже быть недействительным.
ЖЯЦДГ- о xv Apples v Bananas* OrangesЖЯЦДГ- о xv Apples v Bananas* OrangesПо умолчанию в группе активна первая кнопка, но в обращении к функции gtk_toggle_button_set_active() указывается, что активной будет третья кнопка.
ЖЯЦДГ- о x
v Apples v Bananas
* Oranges
ЖЯЦДГ- о x
v Apples v Bananas
* Oranges
static GtkWidget *makeWidget()
{
Рисунок 21.39.Три радиокнопки в вертикальном ящикеРисунок 21.39.Три радиокнопки в вертикальном ящикеGtkWidget *box;
Рисунок 21.39.
Три радиокнопки в вертикальном ящике
Рисунок 21.39.
Три радиокнопки в вертикальном ящике
GSList *group;
GtkWidget *radiobutton;
box = gtk_vbox_new(FALSE, 0);
radiobutton = gtk_radio_button_new_with_label(NULL, "Apples");
gtk_box_pack_start(GTK_BOX(box),radiobutton,
FALSE,TRUE,0);
group = gtk_radio_button_group(
GTK_RADIO_BUTTON (radioblitton));
radiobutton = gtk_radio_button_new_with_label(group, "Bananas");
gtkbox pack start(GTK_BOX(box),radiobutton, FALSE,TRUE,0);
group = gtk_radio_button_group(
GTK_RADIO_BUTTON(radiobutton));
radiobutton = gtk_radio_button_new_with_label(group, "Oranges");
gtk_toggle_button_set_active(
GTK_TOGGLE_BUTTON(radiobutton),TRUE);
gtk_box_pack_start(GTK_BOX(box),radiobutton,
FALSE,TRUE,0);
return(box);
}
GtkRadioMenultem
Вы можете добавить в меню группу из двух или более таких кнопок. Выбор одной из кнопок в группе приводит к отмене выбора всех остальных кнопок.
Иерархия
GtkRadioMenuItem->GtkCheckMenuItem->GtkMenuItem->GtkItem->GtkBin->
GtkContainer->GtkWidget->GtkObject
Функции
GtkType gtk_radio_menu_item_get_type(void)
GSList *gtk_radio_menu_item_group(
GtkRadioMenuItem *radio_menu_item)
GtkWidget *gtk_radio_menu_item_new(GSList *group)
GtkWidget *gtk_radio_menu_item_new_with_label(GSList *group, const gchar *label)
void gtk_radio_menu_item_set_group(
GtkRadioMenuItem *radio_menu item, GSList *group)
- в xRadioMen4l I- в xRadioMen4l IFirst RadioЧ л Second RadioI Third RadioFirst RadioЧ л Second RadioI Third RadioРисунок 21.40.Набор из трех радиокнопок в менюРисунок 21.40.Набор из трех радиокнопок в менюВ приведенном примере создается меню, которое содержит три радиокнопки, как показано на рис. 21.40. Первая кнопка создается с указателем группы, равным NULL. Далее возвращается указатель GSList, который используется при создании следующей кнопки. Если группа используется несколько раз, то необходимо каждый раз получать указатель GSList.
- в x
RadioMen4l I
- в x
RadioMen4l I
First Radio
Ч л Second Radio
I Third Radio
First Radio
Ч л Second Radio
I Third Radio
Рисунок 21.40.
Набор из трех радиокнопок в меню
Рисунок 21.40.
Набор из трех радиокнопок в меню
static GtkWidget *makeWidget()
{
GtkWidget *menu;
GtkWidget *item;
GtkWidget *menubar;
GSList *group;
/* Create the menu */ menu = gtk_menu_new(); item = gtk_radio_menu_item_new_with label(NULL, "First Radio");
gtk_menu_append(GTK_MENU(menu),item);
group = gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM(item));
item = gtk_radio_menu_item_new_with_label(group, "Second Radio");
gtkmenu append(GTK_MENU(menu),item);
group = gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM(item));
item = gtk_radio_menu_item_new_with label(group, "Third Radio");
gtk_menu_append(GTKMENU(menu),item);
/* Add the label on top of the menu */
item = gtk_menu_item_new_with_label("RadioMenu");
gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), menu);
/* Append the menu to the menu bar */ menubar = gtk_menu_bar_new();
gtk_menu_bar_append(GTK MENUBAR(menubar),item);
return(menubar); }
GtkRange
Это базовый класс для группы виджетов, которые используют графическое изображение и манипулируют значением, находящимся внутри заданного диапазона. К таковым относятся следующие виджеты: GtkHScale, GtkHScrollbar, GtkVScale и GtkVScrollbar.
Иерархия
GtkRange->GtkWidget->GtkOb ject
Функции
void gtk_range_clear_background(GtkRange *range)
void gtk_range_default_hmotion(GtkRange *range, gint xdelta, gint ydelta)
void gtk_range_default_hslider_update(GtkRange *range) gint gtk_range_default_htrough_click(GtkRange *range, gint x, gint y, gfloat *jump_perc)
void gtk_range_default_vmotion(GtkRange *range, gint xdelta, gint ydelta)
void gtk_range_default_vslider_update(GtkRange *range) gint gtk_range_default_vtrough_click(GtkRange *range, gint x, gint y, gfloat *jump_perc)
void gtk_range_draw_background(GtkRange *range) void gtk_range_draw_slider(GtkRange *range) void gtk_range_draw_step_back(GtkRange *range) void gtk_range_draw_step_forw(GtkRange *range) void gtk_range_draw_trough(GtkRange *range) GtkAdjustment *gtk_range_get_adjustment(GtkRange *range) GtkType gtk_range_get_type(void) void gtk_range_set_adjustment(GtkRange *range, GtkAdjustment *adjustment)
void gtk_range_set_update_policy(GtkRange *range, GtkUpdateType policy)
void gtk_range_slider update(GtkRange *range) gint gtk_range_trough_click( GtkRange *range, gint x, gint у, gfloat *jump_perc),
GtkRuler
Этот виджет — базовый класс для GtkHRuler и GtkVRuler. Он содержит программное обеспечение конфигурирования и вычислений, но не имеет средств для отображения результатов.
Иерархия
GtkRuler->GtkWidget->GtkObject
Функции
void gtk_ruler_draw_pos(GtkRuler *ruler) void gtk_ruler_draw_ticks(GtkRuler *ruler) guint gtk_ruler_get_type(void) void gtk_ruler_set_metric(GtkRuler *ruler, GtkMetricType metric)
void gtk_ruler_set_range(GtkRuler *ruler, gfloat lower, gfloat upper, gfloat position, gfloat maxsize)
Энумератор typedef enum { GTKPIXELS, GTK_INCHES, GTK_CENTIMETERS } GtkMetricType;
GtkScale
Это базовый класс для виджетов GtkHScale и GtkVScale.
Иерархия
GtkScale->GtkRange->GtkWidget->GtkOb ject
Функции
void gtk_scale_draw_value(GtkScale *scale) GtkType gtk_scale_get_type(void) gint gtk_scale_get_value_width(GtkScale ♦scale) void gtk_scale_set_digits(GtkScale *scale, gint digits) void gtk_scale_set_draw_value(GtkScale *scale, gboolean draw_value)
void gtk_scale_set_value_pos(GtkScale *scale, GtkPositionType pos)
Энумератор typedef enum <
GTKJ?OS_LEFT, GTK_POS_RIGHT, GTKPOSTOP, GTKJPOSJBOTTOM } GtkPositionType;
GtkScrollbar
Класс GtkScrollbar является базовым для виджетов GtkHScrollbar и GtkVScrollbar.
Иерархия'
GtkScrollbar->GtkRange->GtkWidget->GtkObject
Функция
GtkType gtk_scrollbar_get_type(void)
GtkScrolledWindow
Это контейнер, который не изменяет своих размеров для заполнения всей выделенной под него области. Вместо этого он добавляет (при необходимости) полосы прокрутки, так что вы можете просмотреть любую часть окна.
Иерархия
GtkScrolledWindow->GtkBin->GtkContainer->GtkWidget->GtkObject
Функции void gtk_scrolled_window_add_with_viewport( GtkScrolledWindow *scrolled_window, GtkWidget *child) GtkAdjustment *gtk_scrolled_window_get_hadjustment('
GtkScrolledWindow *scrolled_window)
GtkType gtk_scrolled_window_get_type(void)
GtkAdjustment *gtk_scrolled_window_get_vadjustment( GtkScrolledWindow *scrolled_window) GtkWidget *gtk_scrolled_window_new(
GtkAdjustment *hadjustment, GtkAdjustment *vadjustment) void gtk_scrolled_window_set_hadjustment(
GtkScrolledWindow *scrolled_window, GtkAdjustment *hadjustment)-
void gtk_scrolled_window_set_placement(. _
GtkScrolledWindow *scrolled_window,
GtkCornerType window_placement)
void gtk_scrolled_window_set_policy(
GtkScrolledWindow *scrolled_window,
GtkPolicyType hscrollbar_policy,
GtkPolicyType vscrollbar_policy)
void gtk_scrolled_window_set_vadjustment(
GtkScrolledWindow *scrolled_window,
GtkAdjustment *vadjustment)
Энумераторы
typedef enum {
GTK_POLICY_ALWAYS,
GTK_POLICY_AUTOMATIC,
GTK_POLICY_NEVER
} GtkPolicyType;
typedef enum {
GTK_CORNER_TOP_LEFT,
GTK_CORNER_BOTTOM_LEFT,
GTK_CORNER_TOP_RIGHT,
GTK_CORNER_BOTTOM_RIGHT
} GtkCornerType;
Примеры использования GtkScrolledWindow приведены в главе 5.
GtkSeparator
Это базовый класс для GtkHSeparator и GtkVSeparator.
Иерархия
GtkSeparator->GtkWidget->GtkObject
Функция
GtkType gtk_separator_get_type(void)
GtkSocket
Виджет GtkSocket может получить доступ к окнам виджета из дистанционного (удаленного) процесса и отображать их, как если бы они были*локальными. Удаленный процесс создает виджет GtkPlug как окно, которое должно быть сделано доступным для GtkSocket этого процесса.
Иерархия
GtkSocket->GtkContainer->GtkWidget->GtkObject
Функции'
guint gtk_socket_get_type()
GtkWidget *gtk_socket_new()
void gtk__socket_steal (GtkSocket *socket, guint32 id)
GtkSpinButton
Виджет отображает одно численное значение, которое можно изменить с помощью двух кнопок со стрелками, находящимися справа, или путем прямого редактирования числа.
Иерархия
GtkSpinButton->GtkEntry->GtkEditable->GtkWidget->GtkObject
Функции
void gtk_spin_button_configure(GtkSpinButton *spin_button, GtkAdjustment *adjustment, gfloat climb_rate, guint digits)
GtkAdjustment *gtk_spin_button_get_adjustment(
GtkSpinButton *spin_button)
GtkType gtk_spin_button_get_type(void)
gfloat gtk_spin_button_get_value_as_float(
GtkSpinButton *spin_button)
gint gtk_spin_button_get_value_as_int(
GtkSpinButton *spin_button)
GtkWidget *gtk_spin_button_new(GtkAdjustment *adjustment, gfloat climb_rate, guint digits)
void gtk_spin_button_set_adjustment(
GtkSpinButton *spin_button, GtkAdjustment *adjustment)
void gtk_spin_button_set_digits(GtkSpinButton *spin_button, guint digits)
void gtk_spin_button_set_numeric(GtkSpinButton *spin_button, gboolean numeric)
void gtk_spin_button_set_shadow_type(
GtkSpinButton *spin_button, GtkShadowType shadowtype)
void gtk_spin_button_set_snap_to_ticks(
GtkSpinButton *spin_button, gboolean snap_to_ticks)
void gtk_spin_button_set_update_policy(
GtkSpinButton *spin_button,
GtkSpinButtonUpdatePolicy policy)
void gtk_spin_button_set_value(GtkSpinButton *spin_button, gfloat value)
void gtk_spin_button_set~wrap(GtkSpinButton *spin_button, gboolean wrap)
void gtk_spin_button_spin(GtkSpinButton *spin_button, GtkSpinType direction, gfloat increment)
void gtk_spin_button_update(GtkSpinButton *spin_button)
Сигналы
"input" void cb(GtkWidget *, gpointer, gpointer)
"output" gboolean cb(GtkWidget *, gpointer)
В следующем примере показано, как создается вертящаяся кнопка, и устанавливается ее начальное значение 80, как отражено на рис. 21.41. Согласно объекту GtkAdjustment значения могут изменяться от 100 до -100 с шагом 1. В обращении к функции gtk_spin_button_new() кнопки приращения/уменьшения устанавливаются таким образом, что при их нажатии значение меняется на 3; установлен формат с одной цифрой после десятичной запятой (точки).
static GtkWidget *makeWidget()
{
GtkWidget *spin;
GtkObject *adjustment;
adjustment = gtkadjustment_new(80.0, -100.0,100.0,1.0,0.0,0.0);
spin = gtk_spin_button_new(GTK_ADJUSTMENT(adjustment),3.0,1); return(spin);
i
Рисунок 21.41.
Вертящаяся кнопка с отображенным на ней текущим значением и ее кнопки-стрелки для подстройки значения
GtkStatusbar
Виджет GtkStatusbar имеет окно, в котором выводится текстовая информация по текущему состоянию. Внутри виджета может поддерживаться отдельный список статусных сообщений с любым количеством контекстных идентификаторов; каждый из таких списков поддерживается отдельно. Кроме того, каждому текстовому сообщению присваивается идентификатор, который может быть использован для удаления этого сообщения.
Иерархия
GtkStatusbar->GtkHBox->GtkBox->GtkContainer->GtkWidget->GtkObject
Функции
guint gtk_statusbar_get_context_id(GtkStatusbar *statusbar, const gchar *context_description)
guint gtk_statusbar_get_type(void)
GtkWidget *gtk_statusbar_new(void)
void gtk_statusbar_pop(GtkStatusbar *statusbar, guint contextid)
guint gtk_statusbar push(GtkStatusbar *statusbar, guint context_id, const gchar *text)
void gtk_statusbar_remove(GtkStatusbar *statusbar, guint contextid, guint message_id)
Сигналы
"text popped*void cb(GtkWidget *, guint, gchar ♦, gpointer)
"textpushed"void cb(GtkWidget *, guint, gchar ♦, gpointer)
Примеры использования GtkStatusbar приведены в главе 8.
GtkTable
Виджет GtkTable — это контейнер, создающий сетку гибких или статических прямоугольников, которую можно использовать для размещения виджетов и установки их размеров.
Иерархия.
GtkTable->GtkContainer->GtkWidget->GtkObject
Функции
void gtk_table_attach(GtkTable *table, GtkWidget *child, guint leftattach, guint right_attach, guint top_attach, guint bottom_attach, GtkAttachOptions xoptions, GtkAttachOptions yoptions, guint xpadding, guint ypadding)
void gtk_table_attach defaults(GtkTable *table, GtkWidget *widget, guint leftattach, guint right attach, guint top_attach, guint bottomattach)
GtkType gtk_table_get_type(void)
GtkWidget *gtk_table_new(guint rows, guint columns, gboolean homogeneous)
void gtk_table resize(GtkTable *table, guint n_rows, guint ncols)
void gtk_table_set_col_spacing(GtkTable *table, guint column, guint spacing)
void gtk_table_set_col_spacings(GtkTable *table, guint spacing) void gtk_table_set_homogeneous(GtkTable *table, gboolean homogeneous) void gtk_table_set_row_spacing(GtkTable *table, guint row, guint spacing)
void gtk_table_set_row_spacings(GtkTable *table, guint spacing) Энумератор typedef enum { GTK_EXPAND, GTK_SHRINK, GTK_FILL
} GtkAttachOptions;
Примеры использования GtkTable приведены в главе 4.
GtkTearoffMenultem
GNOME использует этот виджет для вставки манипулятора (переключателя) в левую часть строки меню. Это позволяет перемещать меню и иметь к нему доступ, даже когда его окно становится невидимым.
Иерархия
GtkTearoffMenuItem->GtkMenuItem->GtkItem->GtkBin->GtkContainer->GtkWidget-> GtkObject
Функции
GtkType gtk_tearoff_menu_item_get_type(void) GtkWidget *gtk_tearoff_menu_item_new(void)
В следующем прил^ре сначала создается строка меню и к ней добавляется меню. Первым компонентом меню является виджет GtkTearoffMenultem, который появляется в меню в виде пунктирной линии. В приведенном примере GtkTearoffMenultem расположен в верхней части меню, но его можно разместить в любом месте, и он будет работать в качестве манипулятора для всего меню.
static GtkWidget *makeWidget() <.
GtkWidget *menu; GtkWidget *item;-
GtkWidget *menuBar; /* Create the 'transform' menu */ menu = gtk_menu_new(); item = gtk_tearoff_menu_item_new(); gtk_menu_append(GTK_MENU(menu),item); item = gtk_menu_item_new_with_label("Rotate"); gtk_menu_append(GTK_MENU(menu),item); item = gtk_menu_item_new_with_label("Resize"); gtk_menu_append(GTK_MENU(menu),item); item = gtk_menu_item_new_with_label("Select Color"); gtk_menu_append(GTK_MENU(menu),item);
/* Add the label on top of the 'transform' menu */ item = gtk_menu_item_new_with_label("Transform"); gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), menu);
/* Append the 'transform' menu to the menu bar */
menuBar = gtk_menu_bar_new();
gtk_menu~bar_append(GTK_MENU_BAR(menuBar),item);
return(menuBar);
}’
На рис. 21.42 показано отрывное меню в его двух состояниях. Слева показано меню, состыкованное со строкой меню. Справа показано меню в своем собственном окне верхнего уровня после отрыва его с помощью мыши от строки. Меню отрывается путем выбора с помощью мыши пунктирной линии, пока оно еще остается присоединенным.
ЖИрП :р хЖИрП :р хg T - Q xg T - Q xTransform!Transform!Rotate ResizeSelect ColorRotate ResizeSelect ColorRotate Resize Select ColorRotate Resize Select ColorРисунок 21.42.Меню до и после отрываРисунок 21.42.Меню до и после отрыва
ЖИрП :р х
ЖИрП :р х
g T - Q x
g T - Q x
Transform!
Transform!
Rotate Resize
Select Color
Rotate Resize
Select Color
Rotate Resize Select Color
Rotate Resize Select Color
Рисунок 21.42.
Меню до и после отрыва
Рисунок 21.42.
Меню до и после отрыва
GtkTed
Виджет GtkTed — это контейнер, который, как ожидается, будет удален из последующих версий GTK+.
Иерархия
GtkTed->GtkTable->GtkContainer->GtkWidget->GtkObject
Функции
void gtk_ted_add(GtkTed *ted, GtkWidget *widget, char *original_name),
guint gtk_ted_get_type() GtkWidget *gtk_ted_new(char *name) GtkWidget *gtk_ted_new_layout(char *name, char *layout) void gtk_ted_prepare(GtkTed *ted) void gtk_ted_Set_app_name(char *str)
GtkText
Виджет может использоваться просто для отображения текста или для предоставления возможности пользователю редактировать текст. Возможности редактирования довольно примитивные. Виджет автоматически переносит текст строк более длинных, чем он может отобразить.■
Иерархия*
GtkText->GtkEditable->GtkWidget~>GtkObject
Функции'
gint gtk_text_backward_delete(GtkText *text, guint nchars)
gint gtk_text_forward_delete(GtkText *text, guint nchars)
void gtk_text_freeze(GtkText *text)
guint gtk_text_get_length(GtkText *text)
guint gtk_text_get_point(GtkText *text)
GtkType gtk_text_get_type(void)
void gtk_text_insert(GtkText *text, GdkFont *font,
GdkColor *fore, GdkColor *back, const char *chars, gint nchars)
GtkWidget *gtk_text_new(GtkAdjustment *hadj,
GtkAdjustment *vadj)
void gtk_text_set_adjustments(GtkText *textr
GtkAdjustment *hadj, GtkAdjustment *vadj)
void gtk_text_set_editable(GtkText *text, gboolean is_editable)
void gtk_text_set_line_wrap(GtkText *text, gint line_wrap)
void gtk_text_set_point(GtkText *text, guint index)
void gtk_text_set_word_wrap(GtkText *text, gint wordwrap)
void gtk_text_thaw(GtkText *text)
Сигнал
"set_scroll_adjustments" void cb(GtkWidget *, GtkTypeAdjustment *, GtkTypeAdjustment *, gpointer)
Примеры использования виджета GtkText приведены в главах 5 и 16.
GtkTipsQuery
Виджет GtkTipsQuery - это метка с добавленной возможностью переключаться в режим запроса. В этом режиме курсор меняется и имеет вид вопросительного знака, а при прохождении мыши над виджетами немедленно отображаются подсказки. При выборе пользователем одного из виджетов объект GtkTipsQuery генерирует сигнал "widget_selected", по которому ваша программа может отображать определенную информацию.
Иерархия
GtkTipsQuery->GtkLabel->GtkMisc->GtkWidget->GtkObject
Функции
guint gtk_tips_query_get_type(void)
GtkWidget *gtk_tips_query_new(void)
void gtk_tips_query_set_caller(GtkTipsQuery *tips_query,
GtkWidget *qaller)
void gtk_tips_query_set_labels(GtkTipsQuery *tips_query, const gchar *label_inactive, const gchar *label_no_tip)
void gtk_tips_query_start_query(GtkTipsQuery *tips_query)
void gtk_tips_query_stop_query(GtkTipsQuery *tips_query)
Сигналы
"startquery"void cb(GtkWidget *, gpointer)
"stop query"void cb(GtkWidget *, gpointer)
"widgetentered" void cb(GtkWidget ♦, GtkWidget *, gchar *, gchar *, gpointer)
"widgetselected" gboolean cb(GtkWidget *, GdkWdiget *, gchar *, gchar *, GdkEvent *, gpointer)
GtkToggleButton
Виджет GtkToggleButton — это кнопка, которая изменяет и сохраняет свое состояние ’’включено” или ’’выключено” всякий раз при выборе ее с помощью мыши.
Иерархия
GtkToggleButton->GtkButton->GtkBin->GtkContainer->GtkWidget->GtkOb ject
Функции
gboolean gtk_toggle_button_get_active(
GtkToggleButton *toggle_button)
GtkType gtk_toggle_button_get_type(void)
GtkWidget *gtk_toggle_button_new(void)
GtkWidget *gtk_toggle_button_new_with_label(
const gchar *label)
void gtk_toggle_button_set_active(
GtkToggleButton *toggle_button, gboolean is_active) void gtk_toggle_button_set_mode(
GtkToggleButton *toggle_button, gboolean draw_indicator) void gtk_toggle_button_toggled(
GtkToggleButton *toggle_button)
Сигнал "toggled" void cb(GtkWidget *, gpointer)
Примеры использования GtkToggleButton приведены в главе 8.
GtkToolbar
Применяется при создании панелей инструментов. Он является контейнером, который управляет положением набора пиктограмм, чувствительных к нажатиям кнопок мыши.
Иерархия
GtkToolbar->GtkContainer->GtkWidget->GtkObject
Функции
GtkWidget *gtk_toolbar_append_element(GtkToolbar ‘toolbar, GtkToolbarChildType type, GtkWidget *widget, const char ‘text, const char *tooltip_text, const char *tooltip_private_text, GtkWidget ‘icon, GtkSignalFunc callback, gpointer userdata)
GtkWidget *gtk_toolbar_append_item(GtkToolbar ‘toolbar, const char ‘text, const char *tooltip_text, const char *tooltip_private_text, GtkWidget ‘icon, GtkSignalFunc callback, gpointer user_data) void gtk_toolbar_append_space(GtkToolbar *toolbar) void gtktoolbarappendwidget(GtkToolbar ‘toolbar, /GtkWidget ‘widget, const gchar *tooltip_text, I const gchar ‘tooltipprivatetext)
GtkReliefStyle gtk_toolbar_get_button_relief(
GtkToolbar ‘toolbar) guint gtk_toolbar_get_type(void) GtkWidget *gtk_toolbar_insert_element(GtkToolbar ‘toolbar, GtkToolbarChildType type, GtkWidget ‘widget, const char ‘text, const char *tooltip_text, const char *tooltip_private_text, GtkWidget ‘icon, GtkSignalFunc callback, gpointer user_data, gint position) GtkWidget *gtk_toolbar_insert_item(GtkToolbar ‘toolbar, const char ‘text, const char ‘tooltip text, const char *tooltip_private_text, GtkWidget ‘icon, GtkSignalFunc callback, gpointer userdata, gint position) void gtktoolbarinsertspace(GtkToolbar ‘toolbar, gint position) void gtktoolbarinsertwidget(GtkToolbar ‘toolbar, GtkWidget ‘widget, const char *tooltip_text, const char ‘tooltipprivatetext, gint position) GtkWidget *gtk_toolbar_new(GtkOrientation orientation, GtkToolbarStyle style) GtkWidget ‘gtktoolbarprependelement(GtkToolbar ‘toolbar, GtkToolbarChildType type, GtkWidget ‘widget, const char ‘text, const char *tooltip_text, const char *tooltip_private_text, GtkWidget ‘icon, GtkSignalFunc callback, gpointer user_data) GtkWidget *gtk_toolbar_prepend_item(GtkToolbar ‘toolbar,
const char ‘text, const char *tooltip_text, const char *tooltip_private_text, GtkWidget ‘icon, GtkSignalFunc callback, gpointer user_data) void gtk_toolbar_prepend_space(GtkToolbar *toolbar) void gtk_toolbar_prepend_widget(GtkToolbar ♦toolbar, GtkWidget ‘widget, const gchar ‘tooltiptext, const gchar *tooltip_private_text) void gtk_toolbar_set_button_relief(GtkToolbar ♦toolbar, GtkReliefStyle relief)
void gtk_toolbar_set_orientation(GtkToolbar ‘toolbar, GtkOrientation orientation)
void gtk_toolbar_set_space_size(GtkToolbar ‘toolbar, gint spacesize)
void gtk_toolbar_set_space_style(GtkToolbar ‘toolbar, GtkToolbarSpaceStyle space_style)
void gtk_toolbar_set_style(GtkToolbar *toolbar,
GtkToolbarStyle style),
void gtk_toolbar_set_tooltips(GtkToolbar ‘toolbar, gint enable)
Энумераторы
typedef enum {
GTKTOOLBARICONS,
GTK_TOOLBAR_TEXT, GTKTOOLBARBOTH
} GtkToolbarStyle;
typedef enum {•
GTK TOOLBARCHILDSPACE, gtk"toolbar_child_button, GTK_TOOLBAR_CHILD_TOGGLEBUTTON, GTKTOOLBARCHILDRADIOBUTTON, GTKTOOLBARCHILDWIDGET
} GtkToolbarChildType;
typedef enum {
GTK_TOOLBAR_SPACE_EMPTY,’
GTK_TOOLBAR_SPACE_LINE
} GtkToolbarSpaceStyle;
typedef enum {
GTKORIENTATIONHORIZONTAL, GTKORIENTATIONVERTICAL
} GtkOrientation;
Сигналы
"orientationchanged"void cb(GtkWidget *, gint, gpointer)
"style_changed"void cb(GtkWidget *, gint, gpointer)
Примеры создания панелей инструментов в GNOME приведены в главе 8.
GtkTooltips
К любому виджету можно добавить объект GtkTooltips. При зависании на несколько секунд указателя мыши над каким-либо виджетом на экране появляется прямоугольник, который содержит краткое описание действий виджета.
Иерархия
GtkTooltips->GtkDatа->GtkObj ect
Функции
GtkTooltipsData *gtk_tooltips_data_get(GtkWidget *widget) void gtk_tooltips_disable(GtkTooltips *tooltips) void gtk_tooltips_enable(GtkTooltips *tooltips) void gtk_tooltips_force_window(GtkTooltips *tooltips) GtkType gtk_tooltips_get_type(void)
GtkTooltips *gtk_tooltips_new(void) - void gtk_tooltips_set_colors(GtkTooltips *tooltips, GdkColor *background, GdkColor *foreground)
void gtk_tooltips_set_delay(GtkTooltips *tooltips, guint delay) void gtk_tooltips_set_tip(GtkTooltips *tooltips, GtkWidget *widget, const gchar *tip_text, const gchar *tip_private)
liGI- a x
Button|
[Button Tool Tip Text|[Button Tool Tip Text|Рисунок 21.43.Кнопка с подсказкойРисунок 21.43.Кнопка с подсказкойВ этом примере создается виджет-кнопка, к которой присоединяется подсказка. Всякий раз, когда указатель мыши остается внутри прямоугольника кнопки на протяжении нескольких секунд, окно выглядит так, как показано на рис. 21.43.
[Button Tool Tip Text|
[Button Tool Tip Text|
Рисунок 21.43.
Кнопка с подсказкой
Рисунок 21.43.
Кнопка с подсказкой
static GtkWidget ♦makeWidget()
{
GtkTooltips *tooltips;
GtkWidget *button;
button = gtk_button_new_with_label("Button"); tooltips = gtk_tooltips_new();
gtk_tooltips_set_tip(tooltips,button, "Button Tool Tip Text",NULL);
return(button);
GtkTree
Виджет GtkTree является контейнером виджетов GtkTreeItem и других виджетов GtkTree для создания и отображения дерева имен, по которому можно путешествовать с помощью мыши.
Иерархия
GtkTree->GtkContainer->GtkWidget->GtkObject
Функции
void gtk_tree_append(GtkTree *tree, GtkWidget *tree_item) ' '
gint gtk_tree_child_position(GtkTree *tree, GtkWidget *child)•
void gtk_tree_clear_items(GtkTree *tree, gint start, gint end) GtkType gtk_tree_get_type(void),
void gtk_tree_insert(GtkTree *tree, GtkWidget *tree_item, gint position)
GtkWidget *gtk__tree_new(void)
void gtk_tree_prepend(GtkTree *tree, GtkWidget *tree_item)
void gtk_tree_remove_item(GtkTree *container, GtkWidget *widget)
void gtk_tree_remove_iterns(GtkTree *tree, GList *items)
void gtk_tree_select_child(GtkTree *tree, GtkWidget *tree_item)
void gtk_tree_select_item(GtkTree *tree, gint item)
void gtk_tree_set_selection_mode(GtkTree *tree,_.
GtkSelectionMode mode)'
void gtk_tree_set_view_lines(GtkTree *tree, guint flag) void gtk_tree_set_view_mode(GtkTree *tree,
GtkTreeViewMode mode)
void gtk_tree_unselect_child(GtkTree *tree, GtkWidget *tree_item)
void gtk_tree_unselect_item(GtkTree *treef gint item) Энумератор
typedef enum {
GTK_TREE_VIEW_LINE, GTK_TREE_VIEW_ITEM } GtkTreeViewMode;
Сигналы
"selectchild" void cb(GtkWidget *, GtkWidget *, gpointer) "selectionchanged" void cb(GtkWidget ♦, gpointer)
"unselect_child" void cb(GtkWidget *, GtkWidget *, gpointer)
GfU гееGfU гееEh OneFirst OneSecond OneThird Onet First TwoSecond TwoEh OneFirst OneSecond OneThird Onet First TwoSecond TwoРисунок 21.44.Виджет GtkTree, содержащий два поддерева и пять узловРисунок 21.44.Виджет GtkTree, содержащий два поддерева и пять узловВиджет GtkTree содержит список из одного или более виджетов GtkTreeltem. Виджет GtkTreeltem может содержать метку. Кроме того, он может содержать виджет GtkTree, который становится поддеревом. Дерево из приведенного примера содержит два элемента на верхнем уровне, каждый из которых имеет поддерево, что показано на рис. 21.44. Обратите внимание, что всякий раз, когда каждое дерево или поддерево сформировано (после вставки всех элементов), необходимо вызвать функцию gtk_widget_show_all() для отображения всех элементов.
GfU гее
GfU гее
Eh One
First One
Second One
Third One
t First Two
Second Two
Eh One
First One
Second One
Third One
t First Two
Second Two
Рисунок 21.44.
Виджет GtkTree, содержащий два поддерева и пять узлов
Рисунок 21.44.
Виджет GtkTree, содержащий два поддерева и пять узлов
static GtkWidget *makeWidget() {
GtkWidget *tree;
GtkWidget *subtree;
GtkWidget *treeitem; tree = gtk_tree_new();
treeitem = gtk_tree_item_new_with_label("One"); gtk_tree_append(GTK_TREE(tree),treeitem);
subtree = gtk_tree_new(); gtk_tree_item_set_subtree(GTK_TREE_ITEM(treeitem),subtree); treeitem = gtk_tree_item_new_with label("First One"); gtk_tree_append(GTK_TREE(subtree),treeitem);
treeitem = gtk_tree_item_new_with_label("Second One"); gtk_tree_append(GTK TREE(subtree),treeitem);
treeitem = gtk_tree_item_new_with_label("Third One"); gtktree append(GTK TREE(subtree),treeitem);
gtk_widget_show_all(subtree);
treeitem = gtk_tree_item_new_with_label("Two");
gtktree append(GTK_TREE(tree),treeitem);
subtree = gtk_tree_new();
gtk_tree_item_set_subtree(GTK_TREE_ITEM(treeitem),subtree); treeitem = gtk_tree_item_new_with_label("First Two");
gtktree_append(GTK_TREE(subtree),treeitem);
treeitem = gtk_tree_item_new_with_label("Second Two"); gtk_treei_append(GTK_TREE(subtree),treeitem);
gtk_widget_show_all(subtree);
gtk_widget_show_all(tree);
return(tree); }
GtkTreeltem
Виджет GtkTreeltem, который может содержаться в GtkTree, — это контейнер с единственным дочерним виджетом.
Иерархия
GtkTreeItem->GtkItem->GtkBin->GtkContainer->GtkWidget->GtkObject
Функции
void gtk_tree_item_collapse(GtkTreeltem *tree_item)
void gtk_tree_item_deselect(GtkTreeltem *tree_item) void gtk_tree_item_expand(GtkTreeItem *tree_item) GtkType gtk_tree_item_get_type(void)
GtkWidget *gtk_tree_item_new(void)'
GtkWidget *gtk_tree_item_new_with_label(gchar *label) void gtk_tree_item_remove_subtree(GtkTreeltem *item) void gtk_tree_item_select(GtkTreeltem *tree_item) void gtk_tree_item_set_subtree(GtkTreeltem *tree_item, GtkWidget *subtree)
Сигналы "collapse"void cb(GtkWidget *, gpointer)
"expand"void cb(GtkWidget *r gpointer)
Пример использования GtkTreeltem приведен в описании виджета GtkTree.
GtkVBox
Это контейнер, который располагает содержащиеся в нем виджеты вертикально (один над другим).
Иерархия
GtkVBox->GtkBox->GtkContainer->GtkWidget->GtkObject
Функции
GtkType gtkvboxgettype(void).
GtkWidget *gtk_vbox_new(gboolean homogeneous, gint spacing)
Примеры использования виджета GtkVBox приведены в главе 4.
GtkVButtonBox
Является контейнером, предназначенным для размещения в нем кнопок вертикально (одна над другой).
Иерархия
GtkVButtonBox->GtkButtonBox->GtkBox->GtkContainer->GtkWidget->GtkOb ject
Функции
GtkButtonBoxStyle gtk_vbutton_box_get_layout_default(void) gint gtk_vbutton_box_get_spacing_default(void) guint gtkvbuttonboxgettype(void)
GtkWidget *gtk_vbutton_boxnew(void) void gtk_vbutton_box_set_layout_default(GtkButtonBoxStyle layout) void gtk_vbutton_box_set_spacing_default(gint spacing)
Энумератор
typedef enum {
GTK_BUTTONBOX_DEFAULT_STYLE, GTKBUTTONBOXSPREAD, GTK_BUTTONBOX_EDGE, GTKBUTTONBOXSTART, GTKBUTTONBOXEND
} GtkButtonBoxStyle;
Примеры использования контейнера GtkVButtonBox приведены в главе 5.
GtkViewport
Это контейнер, который не изменяет своих размеров до размеров выделенной под него области. Вместо этого он при необходимости добавляет полосы прокрутки, таким образом пользователь может просмотреть любую часть окна. -
Иерархия
GtkViewport->GtkBin->GtkContainer->GtkWidget->GtkOb j ect*
Функции
GtkAdjustment *gtk_viewport_get_hadjustment(GtkViewport *viewport) GtkType gtk_viewport_get_type(void)
GtkAdjustment *gtk_viewport_get_vadjustment(GtkViewport *viewport)
GtkWidget *gtk_viewport_new(GtkAdjustment *hadjustment, GtkAdjustment *vadjustment)
void gtk_viewport_set_hadjustment(GtkViewport *viewport, GtkAdjustment *adjustment)
void gtk_viewport_set_shadow_type(GtkViewport *viewport, GtkShadowType type)
void gtk_viewport_set_vadjustment(GtkViewport *viewport, GtkAdjustment *adjustment)
Энумератор typedef enum {
GTKSHADOWNONE,
GTK_SHADOW_IN,
GTKSHADOWOUT,-
GTK_SHADOW_ETCHED_IN,,
GTK_SHADOW_ETCHED_OUT
} GtkShadowType;
Сигнал
"set_scroll_adjustmentsn void cb(GtkWidget *, GtkAdjustment *, GtkAdjustment *, gpointer)
Как правило, виджет GtkViewport не применяется сам по себе, обычно он используется внутри контейнера GtkScrolledWindow. Примеры использования GtkViewport приведены в главе 5.
GtkVPaned
Это контейнер с двумя панелями, расположенными одна над другой. Каждая панель может содержать один виджет. С помощью мыши, применяя ее на разделяющей эти панели полосе, можно изменять размеры каждой панели, не изменяя размеров всего окна.
Иерархия
GtkVPaned->GtkPaned->GtkContainer->GtkWidget->GtkObject
Функции.
guint gtk_vpaned_get_type(void) GtkWidget *gtk_vpaned_new(void).
Пример использования GtkVPaned приведен в главе 5.
GtkVRuler
Отображает вертикально расположенную шкалу, которая может содержать деления и указатель текущего положения. Позицию указателя можно установить из вашей програм
мы, и, кроме того, его можно перемещать с помощью мыши.
Иерархия
GtkVRuler->GtkRuler->GtkWidget->GtkObj ect
Рисунок 21.45. Вертикальная линейка co шкалой и указателем положенияРисунок 21.45. Вертикальная линейка co шкалой и указателем положенияФункции guint gtk_vruler_get_type(void) GtkWidget *gtk_vruler_new(void)
Рисунок 21.45. Вертикальная линейка co шкалой и указателем положения
Рисунок 21.45. Вертикальная линейка co шкалой и указателем положения
В следующем примере отражается окно, показанное на рис. 21.45.
static GtkWidget *makeWidget() {
GtkWidget *widget;
widget = gtk_vruler_new();
gtk_ruler_set_range(GTKVRULER(widget),0.0,100.0, 20.0,10.0);
return(widget); }
GtkVScale
Этот виджет представляет собой вертикальный слот (паз, или желоб) с ползунком, который можно передвигать с помощью мыши.
Иерархия
GtkVScale->GtkScale->GtkRange->GtkWidget->GtkObject
Функции
GtkType gtk_vscale_get_type(void)
GtkWidget *gtk_vscale_new(GtkAdjustment *adjustment)
Рисунок 21.46. Вертикальная шкала с ползунком, установленным в положение 45Рисунок 21.46. Вертикальная шкала с ползунком, установленным в положение 45В примере создается вертикальная шкала в диапазоне от 0 до 100, а ползунок устанавливается в начальное положение 45, как показано на рис. 21.46.
Рисунок 21.46. Вертикальная шкала с ползунком, установленным в положение 45
Рисунок 21.46. Вертикальная шкала с ползунком, установленным в положение 45
static GtkWidget *makeWidget()
{
GtkWidget *widget;
GtkObject *adjustment;
adjustment = gtk_adjustment_new(45.0,0.0,100.0,
.0,0.0,0.0);
widget * gtkvscalenew(GTK_ADJUSTRENT(adjustment)); return(widget);
GtkVScrollbar
Виджет GtkVScrollbar отображает вертикальную полосу прокрутки с ползунком и двумя кнопками в виде стрелок. Для создания полосы прокрутки необходимо указать начальное и конечное значения, размер ползунка, начальное положение ползунка, а также как далеко он может перемещаться при щелчке мышью на полосе прокрутки.
Иерархия
GtkVScrollbar->GtkScrollbar->GtkRange->GtkWidget->GtkObject
Функции
GtkType gtk_vscrollbar_get_type(void)
GtkWidget *gtk_vscrollbar_new(GtkAdjustment *adjustment)
В приведенном далее примере создается вертикальная
h-:<BRk;
Рисунок 21.47.
полоса прокрутки в диапазоне от 0 до 100, как показано на
ГХ
Вертикальная
рис. 21.47. Установки диапазона указывают, что он разбит
полоса про
на 100 единиц. Щелчок на одной из кнопок перемещает пол
крутки с
зунок на одну единицу, а щелчок на полосе прокрутки — на
J
ползунком
5 единиц. Ширина ползунка составляет 20 единиц.
размером в
/
20% от длины
static GtkWidget *makeWidget() <
диапазона
GtkWidget *widget;
GtkObject *adjustment;
adjustment = gtk_adjustment_new(45.0,0.0,100.0, 1.0,5.0,20.0);
widget = gtkvscrollbar new(GTKADJUSTMENT(adjustment)); return(widget);
GtkVSeparator
Виджет рисует вертикальную линию, которая служит разделителем между горизонтально расположенными виджетами.
Иерархия
GtkVSeparator->GtkSeparator->GtkWidget->GtkObject
Функции
GtkType gtk vseparatorget type(void)
GtkWidget *gtk vseparator new(void)
Button One! Button TwoButton One! Button TwoРисунок 21.48.Вертикальный разделитель между двумя кнопкамиРисунок 21.48.Вертикальный разделитель между двумя кнопкамиВ приведенном примере вертикальный разделитель упакован в ящик между двумя кнопками, как показано на рис. 21.48. Если контейнер не выставляет размер разделителя, то необходимо явно указывать его толщину, поскольку по умолчанию толщина разделителя равна 0 и он невидим.
Button One! Button Two
Button One! Button Two
Рисунок 21.48.
Вертикальный разделитель между двумя кнопками
Рисунок 21.48.
Вертикальный разделитель между двумя кнопками
static GtkWidget *makeWidget() {
GtkWidget *box;
GtkWidget *button;
GtkWidget *separator;
box = gtk_hbox_new(FALSE,0);
button = gtk_button_new_with_label("Button One"); gtk_box_pack_start(GTK_BOX(box),button,FALSE,FALSE,0);
separator = gtk_vseparator_new();
gtk_box_pack_start(GTK_BOX(box),separator,FALSE,FALSE, 0); gtk_widget_set_usize(separator,20,0);
button = gtk_button_new_with_label("Button Two"); gtk_box_pack_start(GTK_BOX(box),button,FALSE,FALSE,0);
return(box); }
GtkWidget'
Это базовый класс для всех виджетов.
Иерархия
Gtkwidget->GtkObject
Функции
quint gtk_widget_accelerator_signal(GtkWidget *widget,
GtkAccelGroup *accel_group, guint accel_key, guint accel mods) gboolean gtk_widget_accelerators_locked(GtkWidget *widget) gboolean gtk_widget_activate(GtkWidget *widget) void gtk_widget_add_accelerator(GtkWidget *widget, const gchar *accel_signal, GtkAccelGroup *accel_group, guint accel_key, guint accel_mods, GtkAccelFlags accel flags) void gtk_widget_add_events(GtkWidget *widget, gint events) void gtk_widget_class_path(GtkWidget *widget, guint *path_length_p, gchar **path_p, gchar **path_reversed_p) void gtk_widget_destroy(GtkWidget *widget) void gtk_widget_destroyed(GtkWidget *widget, GtkWidget **widget_pointer) void gtk_widget_draw(GtkWidget *widget, GdkRectangle *area) void gtkwidget drawdefault(GtkWidget *widget) void gtk_widget_draw focus(Gtkwidget *widget) void gtk_widget ensurestyle(Gtkwidget *widget) gint gtk_widget_event(Gtkwidget *widget, GdkEvent *event) void gtk_widget get(Gtkwidget *widget, GtkArg *arg) Gtkwidget *gtk_widget^get_ancestor(Gtkwidget *widget, GtkType widgettype) void gtkwidget getchildrequisition(Gtkwidget *widget,
GtkRequisition *requisition)
GdkColormap *gtkwidget_get colormap(Gtkwidget *widget) gchar *gtk_widget get composite_name(Gtkwidget *widget) GdkColormap *gtk_widget get default colormap(void) GtkStyle *gtk_widget_get_defaultstyle(void) GdkVisual *gtk_widget getdefault_visual(void) gint gtk_widget_get_events(Gtkwidget *widget) GdkExtensionMode gtk_widget_get_extension_events(Gtkwidget *widget) gchar *gtk_widget_get name(Gtkwidget *widget) GdkWindow *gtk_widget_get_parent_window(Gtkwidget *widget) void gtkwidget getpointer(Gtkwidget *widget, gint *x, gint *y) GtkStyle *gtk widgetget style(Gtkwidget *widget) Gtkwidget *gtk_widget_get_toplevel(Gtkwidget *widget) GtkType gtk_widget_get_type(void)
4 GdkVisual *gtk_widget_get visual(Gtkwidget *widget) void gtk_widget_getv(Gtkwidget *widget, guint nargs, GtkArg *args) void gtk_widget_grab_default(Gtkwidget *widget) void gtk_widget_grab_focus(Gtkwidget *widget)
void gtk_widget_hide(GtkWidget *widget)
void gtk_widget_hide_all(GtkWidget *widget)
gint gtk_widget_hide_on_delete(GtkWidget *widget)
gint gtk_widget_intersect(GtkWidget *widget,
GdkRectangle *area, GdkRectangle *intersection)
gint gtk_widget_is_ancestor(GtkWidget *widget, GtkWidget *ancestor) void gtkwidgetlockaccelerators(GtkWidget *widget)
void gtk_widget_map(GtkWidget *widget)
void gtk_widget_modify_style(GtkWidget *widget, GtkRcStyle *style)
GtkWidget *gtk_widget_new(GtkType widget_type,
const gchar *first_arg_name, ...)
GtkWidget *gtk_widget_newv(GtkType type, guint nargs, GtkArg *args) void gtk_widget_path(GtkWidget *widget, guint *path_length_p, gchar **path_p, gchar **path_reversed_p)
void gtk_widget_pop_colormap(void)
void gtk_widget_pop_composite_child(void)
void gtk_widget_pop style(void)
void gtk_widget_pop_visual(void)
void gtk_widget_popup(GtkWidget *widget, gint x, gint y)
void gtk_widget_push_colormap(GdkColormap *cmap)
void gtk_widget_push_composite_child(void)
void gtk_widget_push_style(GtkStyle *style)
void gtk_widget_push_visual(GdkVisual *visual)
void gtk_widget_queue_clear(GtkWidget *widget)
void gtk_widget_queue_clear_area(GtkWidget *widget, gint x, gint y, gint width, gint height)
void gtk_widget_queue_draw(GtkWidget *widget)
void gtk_widget_queue_draw_area(GtkWidget *widget, gint x, gint y, gint width, gint height)
void gtk_widget_queue_resize(GtkWidget *widget)
void gtk_widget_realize(GtkWidget *widget)
void gtk_widget_ref(GtkWidget *widget)
void gtk_widget_remove_accelerator(GtkWidget *widget, GtkAccelGroup *accel_group, guint accelkey, guint accelmods)
void gtk_widget_remove_accelerators(GtkWidget *widget, const gchar *accel_signal, gboolean visibleonly)
void gtk_widget_reparent(GtkWidget *widget, GtkWidget *new_parent) void gtk_widget_reset_rc_styles(GtkWidget *widget)
void gtk_widget_reset_shapes(GtkWidget *widget)
void gtk_widget_restore_default_style(GtkWidget *widget)
void gtk_widget_set(GtkWidget *widget, const gchar *first_arg_name, ...) void gtk_widget_set_app_paintable(GtkWidget *widget, gboolean apppaintable)
void gtk_widget_set_colormap(GtkWidget *widget, GdkColormap *colormap) void gtk_widget_set_composite_name(GtkWidget *widget, gchar *name) void gtk_widget_set_default_colormap(GdkColormap *colormap)
void gtk_widget_set_default_style(GtkStyle *style)
void gtk_widget_set_default_visual(GdkVisual *visual)
void gtk_widget_set_events(GtkWidget *widget, gint events)
void gtk_widget_set_extension_events(GtkWidget *widget, GdkExtensionMode mode)
void gtk_widget_set_name(GtkWidget *widget, const gchar *name) void gtk_widget_set_parent(GtkWidget *widget, GtkWidget *parent) void gtk_widget_set_parent_window(GtkWidget *widget,
GdkWindow *parent_window)
void gtk_widget_set_rc_style(GtkWidget *widget)
gboolean gtk_widget_set_scroll_adjustments(GtkWidget *widget, GtkAdjustment *hadjustment, GtkAdjustment *vadjustment)
void gtk_widget_set_sensitive(GtkWidget *widget, gint sensitive) void gtk_widget_set_state(GtkWidget *widget, GtkStateType state) void gtk_widget_set_style(GtkWidget *widget, GtkStyle *style) void gtk_widget_set_uposition(GtkWidget *widget, gint x, gint y) void gtk_widget_set_usize(GtkWidget *widget, gint width, gint height) void gtk_widget_set_visual(GtkWidget**widget, GdkVisual *visual) void gtk_widget_setv(GtkWidget *widget, guint nargs, GtkArg *args) void gtk_widget_shape_combine_mask(GtkWidget *widget, GdkBitmap *shape_mask, gint offset_x, gint offset y)
void gtk_widget_show(GtkWidget *widget)
void gtk_widget_show_all(GtkWidget *widget)
void gtk_widget_show_now(GtkWidget *widget)
void gtk_widget_size_allocate(GtkWidget *widget, GtkAllocation *allocation) void gtk_widget_size_request(GtkWidget *widget, GtkRequisition *requisition)
void gtk_widget_unlock_accelerators(GtkWidget *widget)
void gtk_widget_unmap(GtkWidget *widget)
void gtk_widget_unparent(GtkWidget *widget)
void gtk_widget_unrealize(GtkWidget *widget)
void gtk_widget_unref(GtkWidget *widget)
Энумераторы
typedef enum { GTK_ACCEL_VISIBLE, GTK_ACCEL_SIGNAL_VISIBLE, GTK_ACCEL_LOCKED, GTK_ACCEL_MASK
} GtkAccelFlags;
typedef enum { GTK_STATE_NORMAL, GTK_STATE_ACTIVE, GTK_STATE_PRELIGHT, GTK_STATE_SELECTED, GTK_STATE_INSENSITIVE
} GtkStateType;
Сигналы
"button_press_event" "button_release_event" "clientevent"
"configure_event" "debug__msg" "deleteevent" "destroy_event" "drag_begin" "drag_data_delete" "drag_data_get"
GtkSelectionData *, < "drag datareceived"
gboolean gboolean gboolean gboolean
cb(GtkWidget cb(GtkWidget cb(GtkWidget cb(GtkWidget
GdkEvent GdkEvent GdkEvent GdkEvent
void cb(GtkWidget *, gchar *, gpointer)
gpointer) gpointer) gpointer) gpointer)
gint, GtkSelectionData "dragdrop"
gint, guint, gpointer) "drag_end"
"drag_leave"
"dragmotion"
gint, guint, gpointer) "draw"
"draw default"
gboolean cb(GtkWidget *, GdkEvent *, gboolean cb(GtkWidget *, GdkEvent * void cb(GtkWidget *, GdkDragContext void cb(GtkWidget *, GdkDragContext void cb(GtkWidget *, GdkDragContext guint, guint, gpointer)
void cb(GtkWidget *, GdkDragContext
gpointer) gpointer)
*, gpointer) '
*, gpointer)
gint
*, guint, guint, gpointer) gboolean cb(GtkWidget *, GdkDragContext *, gint,
void cb(GtkWidget *, GdkDragContext *, gpointer) void cb(GtkWidget *, GdkDragContext *, gpointer) gboolean cb(GtkWidget *, GdkDragContext *, gint,
void cb(GtkWidget *, gpointer, gpointer) void cb(GtkWidget *, gpointer)
"drawfocus""enter notify_event" "event""expose event""focus in^event""focusout event""grab focus""hide""keypressevent""key_release_event" "leavenotifyevent" "map""map_event""motion_notify_event""noexposeevent""parent set""propertynotifу event""proximityin event""proximity_out_event" "realize""selection_clear_event""selection_get"guint, gpointer)"selection_notify_event""selection_received" gpointer)"selectionrequestevent" "show""size_allocate” "size_request" "state_changed" "style_set" "unmap""unmapevent""unrealize"Mvisibility_notify_eventn"drawfocus""enter notify_event" "event""expose event""focus in^event""focusout event""grab focus""hide""keypressevent""key_release_event" "leavenotifyevent" "map""map_event""motion_notify_event""noexposeevent""parent set""propertynotifу event""proximityin event""proximity_out_event" "realize""selection_clear_event""selection_get"guint, gpointer)"selection_notify_event""selection_received" gpointer)"selectionrequestevent" "show""size_allocate” "size_request" "state_changed" "style_set" "unmap""unmapevent""unrealize"Mvisibility_notify_eventn
"drawfocus"
"enter notify_event" "event"
"expose event"
"focus in^event"
"focusout event"
"grab focus"
"hide"
"keypressevent"
"key_release_event" "leavenotifyevent" "map"
"map_event"
"motion_notify_event"
"noexposeevent"
"parent set"
"propertynotifу event"
"proximityin event"
"proximity_out_event" "realize"
"selection_clear_event"
"selection_get"
guint, gpointer)
"selection_notify_event"
"selection_received" gpointer)
"selectionrequestevent" "show"
"size_allocate” "size_request" "state_changed" "style_set" "unmap"
"unmapevent"
"unrealize"
Mvisibility_notify_eventn
"drawfocus"
"enter notify_event" "event"
"expose event"
"focus in^event"
"focusout event"
"grab focus"
"hide"
"keypressevent"
"key_release_event" "leavenotifyevent" "map"
"map_event"
"motion_notify_event"
"noexposeevent"
"parent set"
"propertynotifу event"
"proximityin event"
"proximity_out_event" "realize"
"selection_clear_event"
"selection_get"
guint, gpointer)
"selection_notify_event"
"selection_received" gpointer)
"selectionrequestevent" "show"
"size_allocate” "size_request" "state_changed" "style_set" "unmap"
"unmapevent"
"unrealize"
Mvisibility_notify_eventn
void cb(GtkWidget *, gpointer) gboolean cb(GtkWidget *, GdkEvent *, gpointer) gboolean cb(GtkWidget *, GdkEvent *, gpointer) gboolean cb(GtkWidget *, GdkEvent *, gpointer) gboolean cb(GtkWidget *, GdkEvent *, gpointer) gboolean cb(GtkWidget *, GdkEvent *, gpointer) void cb(GtkWidget *, gpointer) void cb(GtkWidget *, gpointer) gboolean cb(GtkWidget *, GdkEvent *, gpointer) gboolean cb(GtkWidget *, GdkEvent *, gpointer) gboolean cb(GtkWidget *, GdkEvent *, gpointer) void cb(GtkWidget *, gpointer) gboolean cb(GtkWidget *, GdkEvent *, gpointer) gboolean cb(GtkWidget *, GdkEvent *, gpointer) gboolean cb(GtkWidget *, GdkEvent *, gpointer) void cb(GtkWidget *, GtkObject *, gpointer) gboolean cb(GtkWidget *, GdkEvent *, gpointer) gboolean cb(GtkWidget *, GdkWidget *, gpointer) gboolean cb(GtkWidget *, GdkEvent *, gpointer) void cb(GtkWidget *, gpointer) gboolean cb(GtkWidget *, GdkEvent *, gpointer) void cb(GtkWidget *, GtkSelectionData *, guint,
gboolean cb(GtkWidget *, GdkEvent *, gpointer) void cb(GtkWidget *, GtkSelectionData *,
gboolean cb(GtkWidget *, GdkEvent *, gpointer) voidcb(GtkWidget*,gpointer)
voidcb(GtkWidget*,gpointer,gpointer)
voidcb(GtkWidget*,gpointer,gpointer)
void cb(GtkWidget *, GtkStateType, gpointer) voidcb(GtkWidget*,GtkStyle *, gpointer)
voidcb(GtkWidget*,gpointer)
gboolean cb(GtkWidget *, GtkEvent *, gpointer) void cb(GtkWidget *, gpointer)
gboolean cb(GtkWidget *, GdkEvent *, gpointer)
GtkWindow
Виджет GtkWindow — это окно, которое может быть отображено на экране. Он так* же является контейнером, который может содержать единственный дочерний виджет. Общепринято иметь окно в GtkWindow, обеспечивая окантовку (рамку) вокруг окна.
Иерархия
GtkWindow->GtkBin->GtkContainer->GtkWidget->GtkObject
Функции
gint gtk_window_activate_default(GtkWindow *window)
gint gtkwindow activate focus(GtkWindow *window)
void gtk_window_add_accel_group(GtkWindow *window,
GtkAccelGroup *accel_group)
void gtk_window_add_embedded_xid(GtkWindow *window, guint xid)
GtkType gtk_window_get_type(void)
GtkWidget *gtk_window_new(GtkWindowType type)
void gtkwindow removeaccelgroup(GtkWindow *window,
GtkAccelGroup *accel_group)
void gtk_window_remove_embedded_xid(GtkWindow *window, guint xid)
void gtkwindowset default(GtkWindow *window,
GtkWidget *default_widget)
void gtk_window_set_default_size(GtkWindow *window, gint width, gint height)
void gtk_window_set_focus(GtkWindow *window, GtkWidget *focus)
void gtk_window_set_geometry_hints(GtkWindow *window,
GtkWidget *geometry_widget, GdkGeometry *geometry,
GdkWindowHints geom_mask)
void gtk_window_set_modal(GtkWindow *window, gboolean modal)
void gtk_window_set_policy(GtkWindow *window,
gint allow_shrink, gint allowgrow, gint auto_shrink)
void gtk_window_set_position(GtkWindow *window,
GtkWindowPosition position)
void gtk_window_set_title(GtkWindow *window, const gchar *title)
void gtk_window_set_transient_for(GtkWindow *window, GtkWindow *parent)
void gtk_window_set_wmclass(GtkWindow *window,
const gchar *wmclass_name, const gchar *wmclass_class)
Энумератор
typedef enum {
GTK_WINDOW_TOPLEVEL,
GTK_WINDOW_DIALOG, GTKWINDOWPOPUP.
} GtkWindowType;
Сигнал
"set_focus" void cb(GtkWidget *, GtkWidget *, gpointer)
Поскольку каждое GUI-приложение должно иметь окно, примеры создания окон верхнего уровня можно найти по всей книге. В частности, в главе 3 приведен пример создания всплывающего диалогового окна.
Выводы
В настоящей главе приведен перечень все виджетов GTK+ в алфавитном порядке и ряд других объектов GTK+, которые используются при создании любого приложения. Каждый класс был приведен вместе с (со):
Списком сигналов, перечислимыми типами (энумераторами) и функциями, определенными для объекта
U Иерархией каждого объекта, по которой можно .отследить все сигналы и функции, определенные для любого указанного виджета
? Примерами отображаемых виджетов и контейнеров виджетов и ссылками на другие главы книги, где располагаются примеры
В следующей главе приведен в алфавитном порядке перечень объектов и виджетов GNkME. Каждый виджет GNkME основан на GTK+. Это означает, что в следующей главе будет необходимо проследить иерархию каждого виджета GNkME, вернувшись к его предку из GTK+, описанному в настоящей главе.
ГЛАВА
В этой главе
Перечисление и разъяснение виджетов и некоторых других объектов Gnome.
Определение всех сигналов и функций, задаваемых для каждого объекта.
Нахождение всех наследуемых функций, доступных в объекте, путем изучения его иерархии.
Определение перечислимых констант (энумераторов), задаваемых для передачи функциям конфигурационных установок.
Начинаем с включения простого примера каждого виджета.
В этой главе приводится список виджетов в алфавитном порядке и некоторых других объектов GNkME. Каждый виджет описан со своей иерархией, всеми доступными вашему приложению функциями и простыми примерами.
В большинстве случаев код примера, приведенный с каждым виджетом, — это функция, которая создает отображаемый виджет и возвращает его адрес. В начале главы 21 описана основная ветвь программы, отображающая виджеты.
GnomeAbout
Диалоговое окно виджета GnomeAbout всплывает при нажатии кнопки About из меню приложения и предназначено для стандартизации формы и содержимого.
Иерархия
GnomeAbout->GnomeDialog->GtkWindow->GtkBin->GtkContainer->GtkWidget-> GtkObject
Функции
void gnome_about_construct(GnomeAbout *about, const gchar *title, const gchar *version, const gchar *copyright, const gchar **authors, const gchar *comments, const gchar *logo) guint gnome_about_get_type() GtkWidget *gnome_about_new(const gchar *title, const gchar *version, const gchar *copyright, const gchar **authors, const gchar *comments, const gchar *logo)
В главе 2 показан пример кнопки меню, запускающей окно About. "
GnomeAnimator
Виджет GnomeAnimator показывает по одному изображению списка таким образом, что когда изображения нарисованы правильно, то демонстрируется анимированная последовательность. Причем последовательность может быть постоянно повторяющейся в цикле от последнего изображения к первому, а может останавливаться после того, как показано последнее изображение, или выводить по одному изображению.
ПРИМЕЧАНИЕ
Текущий виджет GnomeAnimator не полный, поскольку можно найти отличия между информацией, представленной здесь и в новой версии.
Иерархия
GnomeAnimator->GtkWidget->GtkObject
Функции
gboolean gnome_animator_advance(GnomeAnimator *animator, gint num) gboolean gnome_animator_append_frame_from_file( GnomeAnimator *animator, const gchar *name, gint xoffset, gint yoffset, guint32 interval)
gboolean gnome_animator_append_frame_from_fileatsize(
GnomeAnimator *animator, const gchar *name, gint x_offset, gint y_offset, guint32 interval, guint width, guint height) gboolean gnome_animator_append_frame_from_gnome_pixmap(
GnomeAnimator *animator, GnomePixmap *pixmap, gint x_offset, gint yoffset, guint32 interval) gboolean gnome_animator_append_frame_fromimlib( GnomeAnimator *animator, Gdklmliblmage *image, gint x_offset, gint y_offset, guint32 interval) gboolean gnome_animator_append_frame_from_imlib_at_size( GnomeAnimator *animator, Gdklmliblmage *image, gint xoffset, gint y_offset, guint32 interval, guint width, guint height) gboolean gnome_animator_append_frames_frpm_file(
GnomeAnimator *animator, const gchar *name, gint x_offset, gint y_offset, guint32 interval, gint x_unit) gboolean gnome_animator_append_frames_from_file_at_size( GnomeAnimator *animator, const gchar *name, gint xoffset, gint y_offset, guint32 interval, gint x_unit, guint width, guint height) gboolean gnome_animator_append_frames_from_imlib( GnomeAnimator *animator, Gdklmliblmage *image, gint x_offset, gint y_offset, guint32 interval, gint x_unit) gboolean gnome_animator_append_frames_from_imlib_at_size( GnomeAnimator *animator, Gdklmliblmage *image, gint x_offset, gint yoffset, guint32 interval, gint x_unit, guint width, guint height) guint gnome_animator_get_current_frame_number(GnomeAnimator *animator) GnomeAnimatorLoopType gnome_animator_get_loop_type(GnomeAnimator *animator) gint gnome_animator_get_playback_direction(GnomeAnimator *animator) double gnome_animator_get_playback_speed(GnomeAnimator *animator) GnomeAnimatorStatus gnome_animator_get_status(GnomeAnimator *animator) guint gnome_animator_get_type(void) void gnome_animator_goto_frame(GnomeAnimator *animator, guint frame_number) GtkWidget *gnome_animator_new_with_size(guint width, guint height)
void gnome_animator_set_loop_type(GnomeAnimator *animator, GnomeAnimatorLoopType looptype)
void gnome_animator_set_playback_direction(
GnomeAnimator *animator, gint playbackdirection)
void gnome_animator_set_playback speed(
GnomeAnimator *animator, double speed)
void gnome_animator_start(GnomeAnimator *animator)
void gnome_animator_stop(GnomeAnimator *animator)
Энумераторы
typedef enum {K
GNOME_ANIMATOR_LOOP_NONE,
GNOME_ANIMATOR_LOOP_RESTART, GNOME_ANIMATOR_LOOP_PING_PONG
GnomeAnimatorLoopType;
GnomeAnimatorStatus {
GNOME_ANIMATOR_STATUS_STOPPED, GNOME_ANIMATOR_STATUS_RUNNING
} GnomeAnimationStatus;,
Si- о x"Si- о x"Рисунок 22.1.Один кадр анимации в среде GnomeРисунок 22.1.Один кадр анимации в среде GnomeВ следующем примере анимируется график модуляции, изображенный на рис. 22.1. Кадры последовательности хранятся как данные в формате ХРМ в файле "animator .xpm", и адрес каждого кадра хранится в массиве anim. Это делается в верхней части программы следующим образом:
Si- о x"
Si- о x"
Рисунок 22.1.
Один кадр анимации в среде Gnome
Рисунок 22.1.
Один кадр анимации в среде Gnome
♦include "animator.xpm"
static char **anim[] = {
animl,anim2,anim3,anim4,anim5
};
Этот цикл создает GnomePixmap (растровое изображение в форме окна) для каждого кадра и добавляет в последовательность как кадр каждое цветное растровое изображение. Аниматор установлен для показа кадров по порядку, а затем возвращается к началу цикла. Аниматор можно установить для одноразового прохождения через последовательность кадров или можно сделать, чтобы он показывал только первый кадр и ожидал приложения, чтобы переключать кадры.
static GtkWidget *makeWidget()
<
int i;
GtkWidget *animator;
GtkWidget *pixmap;
animator = gnome_animator_new_with size(100,100);
for(i=0; i<5; i++) {
pixmap = gnome_pixmap_newfrom_xpm_d(anim[i]);
gnome_animator_append_framefrom_gnome_pixmap(
GNOME_ANIMATOR(animator),GNOME_PIXMAP(pixmap), 0,0,50);
}
'gnome_animator_set_loop_type(GNOME_ANIMATOR(animator),
GNOME_ANIMATOR_LOOP_RESTART);
gnome_animator_start(GNOME_ANIMATOR(animator));
return(animator); }
GnomeApp
Виджет GnomeApp — это главное окно приложения Gnome, виджет-контейнер, содержащий единственный дочерний виджет. В нем также предусмотрены возможности для присоединения меню, панели инструментов, строки текущего состояния и виджетов, которые могут быть состыкованы.
Иерархия
GnomeApp->GtkWindow->GtkBin->GtkContainer->GtkWidget->GtkObject
Функции
void gnome_app_add_dock_item(GnomeApp *app,
GnomeDockltem *item, GnomeDockPlacement placement, gint band_num, gint band position, gint offset) void gnome appadd-docked(GnomeApp *app, GtkWidget *widget, const gchar *name, GnomeDockltemBehavior behavior, GnomeDockPlacement placement, gint band_num, gint band^position, gint offset)
void gnome_appadd_toolbar(GnomeApp *app, GtkToolbar *toolbar, const gchar *name, GnomeDockltemBehavior behavior, GnomeDockPlacement placement, gint band_num, gint band_position, gint offset)
void gnome_app_construct(GnomeApp *app, gchar *appname, char *title) void gnome_app_enable—layout_config(GnomeApp *app, gboolean enable) GnomeDock *gnome_app_get_dock(GnomeApp *app) GnomeDockltem *gnome_app_get_dock_item_by_name(GnomeApp *app, const gchar *name)
GtkType gnomeapp get type(void),
GtkWidget *gnome_app_new(gchar *appname, char *title)’
void gnome_app_set—contents(GnomeApp *app, GtkWidget *contents) void gnome_app_set_menus(GnomeApp *app, GtkMenuBar *menubar) void gnome_app_set_statusbar(GnomeApp *app, GtkWidget *statusbar) void gnome_app_set_statusbar_custom(GnomeApp *app, GtkWidget *container, GtkWidget *statusbar)
void gnome_app_set_toolbar(GnomeApp *app, GtkToolbar *toolbar)
Энумераторы
typedef enum {
GNOME_DOCK_ITEM_BEH_NORMAL = 0,
GNOME_DOCK_ITEM_BEH_EXCLUSIVE = 1 « 0,
GNOME_DOCK_ITEM_BEH_NEVER_FLOATING = 1 « 1, GNOME_DOCK_ITEM_BEH_NEVER_VERTICAL = 1 « 2, GNOME_DOCK_ITEM_BEH_NEVER_HORIZONTAL = 1 « 3, GNOME_DOCK_ITEM_BEH_LOCKED = 1 « 4
} GnomeDockltemBehavior;
typedef enum {
GNOMEDOCKTOP,
GNOME_DOCK_RIGHT, GNOMEDOCKBOTTOM, GNOME_DOCK_LEFT, GNOME_DOCK_FLOATING } GnomeDockPlacement;
В главе 2 приводятся некоторые предварительные примеры виджета GnomeApp.
GnomeAppBar
Виджет GnomeAppBar — это строка отражения динамики процесса (движущаяся строка состояния) с текстовым комментарием.
Иерархия
GnomeAppBar->GtkHBox->GtkBox->GtkContainer->GtkWidget->GtkObject
Функции
void gnome_appbar_clear_prompt(GnomeAppBar *appbar)
void gnome_appbar_clear_stack(GnomeAppBar *appbar)
void gnome_appbar_construct(GnomeAppBar *ab,
gboolean has_progress, gboolean has_status, GnomePreferencesType interactivity)
GtkProgress *gnome_appbar_get_progress(GnomeAppBar *ab) gchar *gnome_appbar_get_response(GnomeAppBar *appbar) guint gnome_appbar_get_type()
GtkWidget *gnome_appbar_new(gboolean has_progress, gboolean has_status, GnomePreferencesType interactivity)
void gnome_appbar_pop(GnomeAppBar *appbar)
void gnome_appbar_push(GnomeAppBar *appbar, const gchar *status)
void gnome_appbar_refresh(GnomeAppBar *appbar)•
void gnome_appbar_set_default(GnomeAppBar *appbar, const gchar *default_status)
void gnome_appbar_set_progress(GnomeAppBar *ab, gfloat percentage)
void gnome_appbar_set_prompt(GnomeAppBar *appbar, const gchar *prompt, gboolean modal)
void gnome_appbar_set_status(GnomeAppBar *appbar, const gchar *status) Энумератор
typedef enum {
GNOME_PREFERENCES—NEVER,
GNOME_PREFERENCES—USER,
GNOME—PREFERENCES—ALWAYS
} GnomePreferencesType;
Виджет GnomeAppBar отображает информацию из двух частей. Как видно из рис. 22.2, слева имеется строка описания, а справа — строка отражения динамики процесса. Обращение к функции gnome_appbar_set_progress () позволяет установить значение индикатора процесса, а обращение к функции gnome_appbar_set_prompt () устанавливает строку отражения динамики процесса.
static GtkWidget *makeWidget()
{
GtkWidget *appbar;
appbar = gnome_appbar_new(TRUE,TRUE,
GNOME_PREFERENCES—ALWAYS);-
gnome_appbar_set_progress(GNOME_APPBAR(appbar),0.63);
gnome_appbar_set—prompt(GNOME_APPBAR(appbar), "Showing 63 Percent",TRUE);
return(appbar);
}
Рисунок 22.2.
Виджет GnomeAppBar с текстом и строкой отражения динамики процесса
GnomeCalculator
Виджет GnomeCalculator — это всплывающее окно, содержащее полнофункциональный научный калькулятор.
Иерархия
GnomeCalculator->GtkVBox~>GtkBox~>GtkContainer->GtkWidget->GtkObject
Функции
void gnome_calculator_clear(GnomeCalculator *gc, const gboolean reset) guint gnome_calculator_get_type(void)
GtkWidget *gnome_calculator_new(void)
void gnome_calculator_set(GnomeCalculator *gc, gdouble result)
Программируемый интерфейс к виджету GnomeCalculator очень прост, так как он управляет пользовательским вводом и выводом. Рис. 22.3 демонстрирует внешний вид калькулятора.
static GtkWidget *makeWidget()
GtkWidget *calculator;
calculator = gnome_calculator_new();
return(calculator);
ииGnomeGnome}
и
и
Gnome
Gnome
Рисунок 22.3.
Схема размещения виджета GnomeCalculator
GnomeCanvas
Виджет GnomeCanvas можно использовать для рисования фигур, показа графики, размещения виджетов и т.д.
Иерархия
GnomeCanvas->GtkLayout->GtkContainer->GtkWidget->GtkObject
Функции
void gnome_canvas_c2w(GnomeCanvas *canvas, int ex, int cy, double *wx, double *wy)
int gnome_canvas_get_color(GnomeCanvas *canvas, char *spec, GdkColor *color)
GnomeCanvasItem *gnome_canvas_get_item_at(
GnomeCanvas *canvas, double x, double y)
void gnome_canvas_get_scroll_offsets(GnomeCanvas ‘canvas, int *cx, int *cy) void gnome_canvas_get_scroll_region(GnomeCanvas *canvas, double *xl, double *yl, double *x2, double *y2)
GtkType gnome_canvas_get_type(void)
GtkWidget *gnome_canvas_new(void)
GtkWidget *gnome_canvas_new_aa(void)
void gnome_canvas_request_redraw(GnomeCanvas *canvas, int xl, int yl, int x2, int y2)
void gnome_canvas_request_redraw_uta(GnomeCanvas *canvas, ArtUta *uta)
GnomeCanvasGroup *gnome_canvas_root(GnomeCanvas *canvas)
void gnome_canvas_scroll_to(GnomeCanvas *canvas, int ex, int cy)
void gnome_canvas_set_pixels_per_unit(GnomeCanvas *canvas, double n)
void gnome_canvas_set_scroll_region(GnomeCanvas *canvas,
double xl, double yl, double x2, double y2)
void gnome_canvas_set_stipple_origin(GnomeCanvas *canvas, GdkGC *gc)
void gnome_canvas_update_now(GnomeCanvas *canvas)
void gnome_canvas_w2c(GnomeCanvas *canvas, double wx, double wy, int *cx, int *cy)
void gnome_canvas_w2c_affine(GnomeCanvas *canvas, double affine [ 6 ])
void gnome_canvas_w2c_d(GnomeCanvas *canvas, double wx, double wy, double *cx, double *cy)
void gnome_canvas_window_to_world(GnomeCanvas *canvas, double winx, double winy, double *worldx, double *worldy)
void gnome_canvas_world_to_window(GnomeCanvas *canvas,
double worldx, double worldy, double *winx, double *winy)
Глава 9 посвящена приемам работы с виджетом GnomeCanvas.
GnomeCanvasEllipse
Виджет GnomeCanvasEllipse — это GnomeCanvasItem (базовый класс), который рисует сам себя как эллипс в виджете GnomeCanvas.
Иерархия
GnomeCanvasEllipse->GnomeCanvasRE->GnomeCanvasItem->GtkObject
Функция
GtkType gnome_canvas_ellipse_get_type(void)
В главе 9 приведены примеры работы с виджетом GnomeCanvasEllipse.
GnomeCanvasGroup
Объекты этого класса создаются и управляются внутри виджета GnomeCanvas. Предназначение класса — содержать и управлять совокупностью объектов Canvas Item, которые отображаются виджетом GnomeCanvas. Единственный способ добавить GnomeCanvasItem к GnomeCanvas — это включить его в объект GnomeCanvasGroup. И так как GnomeCanvasGroup — это также GnomeCanvasItem, он может содержать другие GnomeCanvasGroup. Всегда есть один класс GnomeCanvasGroup объектов (группа root) в виджете GnomeCanvas.
Иерархия
GnomeCanvasGroup->GnomeCanvasItem->GtkObject
Функции
void gnome_canvas_group_child_bounds(GnomeCanvasGroup *group, GnomeCanvasItem *item)
GtkType gnome_canvas_group_get_type(void)
Глава 9 включает примеры использования GnomeCanvasGroup.
. GnomeCanvasImage
Выводит изображение в GnomeCanvas.
Иерархия
GnomeCanvasImage->GnomeCanvasItem->GtkObject
Функция■*
GtkType gnome_canvas_image_get_type(void)
В главе 9 можно увидеть примеры использования GnomeCanvasImage.
GnomeCanvasItem
Это базовый класс всех элементов, которые отображает GnomeCanvas.
Иерархия
GnomeCanvasItem->GtkObject
Функции
void gnome_canvas_item_affineabsolute(GnomeCanvasItem *item, const double affine [ 6 ])
void gnome_canvas_item_affine_relative(GnomeCanvasItem *item, const double affine [ 6 ])
void gnome_canvas_item_construet(GnomeCanvasItem *item, GnomeCanvasGroup *parent, const gchar *first_arg_name, valist args)
void gnome_canvas_item_constructv(GnomeCanvasItem *item, GnomeCanvasGroup *parent, guint nargs, GtkArg *args)
void gnome_canvas_item_get_bounds(GnomeCanvasItem *item, double *xl, double *yl, double *x2, double *y2)
GtkType gnome_canvas_item_get_type(void)
int gnome_canvas_item_grab(GnomeCanvasItem *item, guint event_mask, GdkCursor *cursor, guint32 etime) void gnome_canvas item grabfocus(GnomeCanvasItem *item) void gnome_canvas_item_hide(GnomeCanvasItem *item) void gnome_canvas_item_i2c_affine(GnomeCanvasItem *item, double affine [ 6 ])
void gnome_canvas_item i2w(GnomeCanvasItem *item, double *x, double *y) void gnome_canvas__item_i2w_affine(GnomeCanvasItem *item, double affine [ 6 ])
void gnomecanvasitem lower(GnomeCanvasItem *item, int positions)
void gnome_canvas_item_lower_to_bottom(GnomeCanvasItem *item)
void gnome_canvas_item_move(GnomeCanvasItem *item, double dx, double dy) GnomeCanvasItem *gnome_canvas_item_new(
GnomeCanvasGroup *parent, GtkType type, const gchar *first_arg_name, ...)
GnomeCanvasItem *gnome_canvas_item_newv(
GnomeCanvasGroup *parent, GtkType type, guint nargs, GtkArg *args) void gnome_canvas_item_raise(GnomeCanvasItem *item, int positions) void gnome_canvas_item_raise_to_top(GnomeCanvasItem *item) void gnome_canvas_item_reparent(GnomeCanvasItem *item, GnomeCanvasGroup *new_group)
void gnome_canvas_item_request_redraw_svp( GnomeCanvasItem *item, const ArtSVP *svp)
void gnome_canvas_item_request_update(GnomeCanvasItem *item)
void gnomecanvasitemreset bounds(GnomeCanvasItem *item)
void gnome_canvas item set(GnomeCanvasItem *item, const gchar *first_arg_name, ...)
void gnome_canvas_item_set_valist(GnomeCanvasItem *item, const gchar *first_arg_name, va_list args)
void gnome_canvas_item_setv(GnomeCanvasItem *item, guint nargs, GtkArg *args)
void gnome_canvas_item_show(GnomeCanvasItem *item)
void gnome_canvas_item_ungrab(GnomeCanvasItem *item, guint32 etime)
void gnome_canvas_item_update_svp(GnomeCanvasItem *item,
ArtSVP **p_svp, ArtSVP *new_svp)
void gnome_canvas_item_update_svp_clip(GnomeCanvasItem *item,
ArtSVP **p_svp, ArtSVP *new_svp, ArtSVP *clip_svp)
void gnome_canvas_item_w2i(GnomeCanvasItem *item, double *x, double *y)
Просмотрите главу 9, чтобы ознакомиться с примерами создания различных видов GnomeCanvasItem.
GnomeCanvasline
Виджет GnomeCanvasLine — это GnomeCanvasItem, рисующий линию в GnomeCanvas. Линия может содержать многочисленные сегменты.
Иерархия
GnomeCanvasLine->GnomeCanvasItem->GtkObject
Функция
GtkType gnome_canvas_line_get_type(void)
В главе 9 можно найти примеры использования GnomeCanvasLine.
GnomeCanvasPolygon
Виджет GnomeCanvasPolygon — это GnomeCanvasItem, рисующий заполненный полигон в GnomeCanvas.
Иерархия
GnomeCanvasPolygon->GnomeCanvasItem->GtkObject
Функции
GtkType gnomecanvaspolygongettype(void)
double gnome_canvas_polygon_to_point(double *poly, int num_points, double x, double y)
Обратитесь к главе 9 за примерами использования GnomeCanvasPolygon.
GnomeCanvasRE
Это базовый класс, который действует как родитель и Ana^GnomeCanvasRect, и для GnomeCanvasEllipse. Этот базовый класс включает информацию о цветах и размерах, а два упомянутых наследника содержат информацию о деталях рисования.
Иерархия
GnomeCanvasRE->GnomeCanvasItem->GtkObject
Функция
GtkType gnomecanvasregettype(void)
В главе 9 содержатся примеры использования GnomeCanvasEllipse и GnomeCanvasRect.
GnomeCanvasRect
Виджет GnomeCanvasRect — это GnomeCanvasItem, рисующий себя как прямоугольник в GnomeCanvas.
Иерархия
GnomeCanvasRect->GnomeCanvasRE->GnomeCanvasItem->GtkObject
Функция
GtkType gnome_canvas_rect_get_type(void)
В главе 9 можно увидеть примеры использования GnomeCanvasRect.
GnomeCanvasText
Виджет GnomeCanvasText — это GnomeCanvasItem, отображающий строку текста вGnomeCanvas.
Иерархия
GnomeCanvasText->GnomeCanvasItem->GtkObject
Функция
GtkType gnome_canvas_text_get_type(void)
Глава 9 содержит примеры использования GnomeCanvasText.
GnomeCanvasWidget .
GnomeCanvasWidget не является виджетом — это GnomeCanvasItem, способный содержать виджет. Можно использовать GnomeCanvasWidget для отображения любого виджета в GnomeCanvas, как если бы виджет был GnomeCanvasItem.
Иерархия
GnomeCanvasWidget->GnomeCanvasItem->GtkObject
Функция
GtkType gnome_canvas_widget_get_type(void)'
В главе 9 можно найти пример использования GnomeCanvasWidget.
GnomeClient
Объект GnomeClient позволяет вашему приложению сохранять информацию сеанса, когда пользователь выходит из системы. Если при выходе из системы пользователь выберет сохранение текущих установок, то каждому приложению посылается сигнал "save_yourself ". Поскольку приложение имеет возможность сохранить такую информацию, то она прилагается к командной строке всякий раз, когда при очередном входе пользователя в систему программа автоматически перезапускается.
Иерархия
GnomeClient->GtkObject
Функции
void gnome_client_add_static_arg(GnomeClient *clientf ...).
void gnome_Client_connect(GnomeClient *client) •
void gnome_client_disable_master connection(void)
void gnome_client_disconnect(GnomeClient *client)
void gnome_client_flush(GnomeClient *client)
gchar *gnome_client_get config_prefix(GnomeClient *client) GnomeClientFlags gnome_client_get_flags(GnomeClient *client) gchar *gnome_client_get_global_config_prefix(GnomeClient *client) gchar *gnome_client_get_id(GnomeClient *client)
gchar *gnome_client_get_previous_id(GnomeClient *client)
GtkType gnome_client_get_type(void)
void gnome_client_init(void)
GnomeClient *gnome_client_new(void)
GnomeClient *gnome_client_new_without_connection(void)
void gnome_client_request_interaction(GnomeClient *client, GnomeDialogType dialog_type, GnomelnteractFunction function, gpointer data)
void gnome_client_request_interaction_interp(
GnomeClient *client, GnomeDialogType dialog_type, GtkCallbackMarshal function, gpointer data, GtkDestroyNotify destroy)
void gnome_client_request_phase 2(GnomeClient *client)
void gnome_client_request_save(GnomeClient *client,
GnomeSaveStyle save_style, gboolean shutdown,
GnomelnteractStyle interact_style, gboolean fast, gboolean global) void gnome_client_save_any_dialog(GnomeClient *client,
GnomeDialog *dialog)
void gnome_client_save_error_dialog(GnomeClient *client, GnomeDialog *dialog)
void gnome_client_set_clone_command(GnomeClient *client, gint argc, gchar *argv[])
void gnome_client_set_current_directory(GnomeClient *client, const gchar *dir)
void gnome_client_set_discard_command(GnomeClient *client, gint argc, gchar *argv[])
void gnome client setenvironment(GnomeClient *client, const gchar *name, const gchar *value)
void gnome clientset globalconfigprefix(
GnomeClient *client, gchar *prefix)
void gnome client_set_id(GnomeClient *client, const gchar *id)
void gnome_client set priority(GnomeClient *client, guint priority)
void gnome_client_set_process_id(GnomeClient *client, pid_t pid)
void gnome_client_set_program(GnomeClient *client,»
const gchar *program)
void gnome client_set_resign_command(GnomeClient *client, gint argc, gchar *argv[J)
void gnome_client_set_restart_command(GnomeClient *client, gint argc, gchar *argv[])
void gnome client set_restart_style(GnomeClient *client, GnomeRestartStyle style)
void gnomeclient set_shutdown_command(GnomeClient *client, gint argc, gchar *argv[])
void gnome_client_set_user_id(GnomeClient *client, const gchar *id) GnomeClient *gnome clonedclient(void)
void gnome interaction_key_return(gint tag, gboolean cancelshutdown) GnomeClient *gnome_master_client(void)
Энумераторы
typedef enum {.
GNOMEINTERACTNONE, GNOME^INTERACTERRORS, GNOMEINTERACTANY
} GnomelnteractStyle;
typedef enum { GNOME _DIALOG_ERROR, GNOME_DIALOG_NORMAL } GnomeDialogType;
typedef enum { GNOME_SAVE_GLOBAL, GNOME_SAVE_LOCAL, GNOME_SAVE_BOTH } GnomeSaveStyle;
typedef enum { GNOME_RESTART_IF_RUNNING, GNOME_RESTART_ANYWAY, GNOME_RESTART_IMMEDIATELY, GNOME_RESTART_NEVER } GnomeRestartStyle;
typedef enum { GNOME_CLIENT_IDLE, GNOME_CLIENT_SAVING_PHASE_1, GNOME_CLIENT_WAITING_FOR_PHASE_2, GNOME_CLIENT_SAVING_PHASE_2, GNOME_CLIENT_FROZEN, GNOME_CLIENT_DISCONNECTED, GNOME_CLIENT_REGISTERING } GnomeClientState;
typedef enum { GNOME_CLIENT_IS_CONNECTED, •GNOME__CLIENT_RE STARTED,
GNOMECLIENTRESTORED'
} GnomeClientFlags;
В следующем примере при выходе пользователя из системы возникает реакция на сигнал "saveyour self" в GtkObject и вызывается функция eventSaveYourself (). Эта функция создает массив аргументов командной строки, которые используются для повторного запуска программы с контрольной точки, где она ранее остановилась.
/** gnomeclient.с **/
♦include <gnome.h>
gint eventDelete(GtkWidget *widget, GdkEvent ♦event,gpointer data);
gint eventDestroy(GtkWidget *widget, GdkEvent *event,gpointer data); gint eventSaveYourself(GnomeClient *client,gint phase, GnomeSaveStyle sStyle,gint isShutdown, GnomelnteractStyle iStyle,gint isFast,gpointer data);
int main(int argc,char *argv[J) int i;.
GtkWidget *app;
GnomeClient *client;
GtkWidget *label;
GtkWidget *box; gchar string!80];
gnome_init("gnomeclient","1.0",argc,argv);
арр = gnome_app_new("gnomeclient","GnomeCIient"); gtk_container_set_border_width(GTK_CONTAINER(app),20); gtk_signal_connect(GTK_OBJECT(app),"delete_event", GTK_SIGNAL_FUNC(eventDelete),NULL);
gtk_signal_connect(GTK_OBJECT(app),"destroy", GTK_SIGNAL_FUNC(eventDestroy),NULL);
client = gnome_master_client();
gtk_signal_connect(GTK_OBJECT(client),"save_yourself", GTK_SIGNAL_FUNC(eventSaveYourself),argv[0]);
box = gtk_vbox_new(FALSE, 0);
for(i=0; i<argc; i++) {
sprintf(string,"argv[%d]=%s",i,argv[i]);
label = gtk_label_new(string);
gtk_box_pack_start(GTKBOX(box),label,FALSE,FALSE, 0);
}
gnome_app_set_contents(GNOME_APP(app),box);
gtk_widget__show_all (app);
gtk_main();
exit(0);
}
gint eventDelete(GtkWidget *widget, GdkEvent *event,gpointer data) { return(FALSE);
}
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data) {
gtk_main_quit();
return(0);
}
gint eventSaveYourself(GnomeClient *client,gint phase, GnomeSaveStyle sStyle,gint isShutdown,
, GnomelnteractStyle iStyle,gint isFast,gpointer data)
<
guint argc;
gchar *argv[2];
argc = 2;
argv[0] = (gchar *)data;
argv[l] = "MyRestartValue";
gnome_client_set clone_command(client,argc,argv); gnome_client_set_restart_command(client,argc,argv);
return(TRUE);
}
Этот пример использует вертикальный ящик, содержащий столбец меток, каждая из которых демонстрирует один из аргументов командной строки. Когда программа запускается впервые, ее окно выглядит, как на рис. 22.4. Если пользователь закрывает программу (при помощи опции Close из меню или кнопки в верхнем правом углу), то информация о конфигурации не сохраняется. С другой стороны, если пользователь при выходе из программы выбрал сохранение конфигурации, то в программу посылается сигнал "save^yourself". Когда в следующий раз пользователь войдет в систему, програм-
ма стартует автоматически и ей передается сохраненная информация, что и определяет
вид окна, как на рис. 22.5.
argv(Ol«/home/stuff/book/gn/22/code/gnomeclientargv(Ol«/home/stuff/book/gn/22/code/gnomeclientРисунок 22.4. Командная строка без каких-либо аргументов клиентаРисунок 22.4. Командная строка без каких-либо аргументов клиентаargv(01«=/home/stu1bbook/gn/22/code/gnomeclientargv[1j=--sm-config-prefixargv(2]«/gnomecltent- а00974/
argv(Ol«/home/stuff/book/gn/22/code/gnomeclient
argv(Ol«/home/stuff/book/gn/22/code/gnomeclient
Рисунок 22.4. Командная строка без каких-либо аргументов клиента
Рисунок 22.4. Командная строка без каких-либо аргументов клиента
arg v[3)—-sm-client-id
argv[4]«11 c0a8010a000094279298200000008898003argv[5]*MyRestartValue
Рисунок 22.5. Командная строка с пред-варительно сохраненными аргументами
GnomeColorPicker.
Кнопка GnomeColorPicker вызывает виджет GtkColorSelectionDialog и позволяет выбрать цвет. Кнопка меняет свой цвет в соответствии с выбранным в настоящий момент цветом.
Иерархия
GnomeColorPicker->GtkButton->GtkBin->GtkContainer->GtkWidget->GtkObject
Функции
void gnome_color_picker_get_d(GnomeColorPicker *ср, gdouble *r, gdouble *g, gdouble *b, gdouble *a)
void gnome_color_picker_get_il6(GnomeColorPicker *cp, gushort *r, gushort *g, gushort *b, gushort *a)
void gnome_color_picker_get_i8(GnomeColorPicker *cpr guint8 *r, guint8 *g, guint8 *b, guint8 *a),'
GtkType gnome_color_picker_get_type(void)
GtkWidget *gnome_color_picker_new(void)
void gnome_color_picker_set_d(GnomeColorPicker *cp, gdouble r, gdouble g, gdouble b, gdouble a)
void gnome_color_picker_set_dither(GnomeColorPicker *cp, gboolean dither)
void gnome_color_picker_set_il6(GnomeColorPicker *cp, gushort r, gushort gr gushort b, gushort a)
void gnome_color_picker_set_i8(GnomeColorPicker *cp, guint8 r, guint8 g, guint8 b, guint8 a)
void gnome_color_picker_set_title(GnomeColorPicker *cp, const gchar *title) void gnome_color_picker_set_use_alpha(GnomeColorPicker *cpr
gboolean use_alpha)
По умолчанию начальным цветом для GnomeColorPicker является черный. Существуют функции, которые можно использовать для установки и выборки текущего цвета. Следующий пример создает виджет GnomeColorPicker, который сам себя отображает в виде кнопки. Будучи выбранной, кнопка вызывает диалоговое окно выбора цвета, как показано на рис. 22.6.
static GtkWidget *makeWidget()
{
GtkWidget *colorpicker;
colorpicker = gnome_color_picker_new();
return(colorpicker);
Рисунок 22.6.
Диалоговое окно выбора цвета, контролируемое виджетом GnomeColorPicker
GnomeDEntryEdit•
Объект GnomeDEntryEdit может быть вставлен в GtkNotebook в виде двух страниц. Эти две странички позволяют пользователю редактировать приложение и информацию о каталогах, появляющуюся в системном меню. Сюда включаются имя программы и команда ее запуска, а также местоположение справочной документации.
Иерархия
GnomeDEntryEdit->GtkObject;
Функции
void gnome_dentry_edit_clear(GnomeDEntryEdit *dee) gchar *gnome_dentry_edit_get_icon(GnomeDEntryEdit *dee) gchar *gnome_dentry_edit_get_name(GnomeDEntryEdit *dee) guint gnome_dentry_edit_get_type(void) void gnome_dentry_edit_load_file(GnomeDEntryEdit *dee, const gchar *path) GtkObject *gnome_dentry_edit_new(void) GtkObject *gnome_dentry_edit_new_notebook(GtkNotebook *notebook) void gnome_dentry_edit_set_dentry(GnomeDEntryEdit *deer GnomeDesktopEntry *dentry)
GtkWidget *gnome_dentry_get_comment_entry(GnomeDEntryEdit *dee) GnomeDesktopEntry *gnome_dentry_get_dentry(GnomeDEntryEdit *dee) GtkWidget *gnome_dentry_get_doc_entry(GnomeDEntryEdit *dee) GtkWidget *gnome_dentry_get_exec_entry(GnomeDEntryEdit *dee) GtkWidget *gnome_dentry_get_icon_entry(GnomeDEntryEdit *dee) GtkWidget *gnome_dentry_get_name_entry(GnomeDEntryEdit *dee) GtkWidget *gnome_dentry_get_tryexec_entry(GnomeDEntryEdit *dee)
Объект GnomeDEntryEdit не является виджетом, он содержит другие виджеты, организованные так, что они формируют две страницы, которые вставляются в GtkNotebook. Виджет GtkNotebook используется для отображения двух страниц, добавляемых объектом GnomeDEntryEdit. В следующем примере создается пустой объект GnomeDEntryEdit и вставляется в записную книжку, как показано на рис. 22.7.
static GtkWidget *makeWidget() { GtkObject *dentryedit; GtkWidget *notebook;
notebook = gtk_notebook_new();
dentryedit = gnome_dentry_edit_new_notebook(
GTK_NOTEBOOK(notebook));
return(notebook); }
Рисунок 22.7.
Двухстраничный объект GnomeDEntryEdit внутри GtkNotebook
GnomeDialog
Виджет GnomeDialog можно использовать для построения настраиваемого диалогового ящика, который создается в своем собственном окне верхнего уровня. Здесь вертикальный ящик используется как контейнер, что создает возможность включения горизонтального ряда стандартных кнопок в нижнюю часть ящика. Ваше приложение может упаковать другие виджеты в верхнюю часть ящика. GnomeMessageBox является оболочкой вокруг виджета GnomeDialog, что упрощает интерфейс. В главе 3 приводятся примеры и дается информация по установке предопределенных диалоговых ящиков.
Иерархия
GnomeDialog->GtkWindow->GtkBin->GtkContainer->GtkWidget->GtkObject
Функции
void gnome_dialog_append_button(GnomeDialog *dialog, const gchar *button_name)-
void gnome_dialog_append_button_with_pixmap( GnomeDialog *dialog, const gchar *button_name, const gchar *pixmap_name)
void gnome_dialog_append_buttons(GnomeDialog *dialog, const gchar *first, ...) void gnome_dialog_append_buttons_with_pixmaps( GnomeDialog *dialog, const gchar **names, const gchar **pixmaps)
void gnome_dialog_append_buttonsv(GnomeDialog *dialog, const gchar **buttons)
void gnome_dialog_button_connect(GnomeDialog *dialog, gint button, GtkSignalFunc callback, gpointer data) void gnome_dialog_button_connect_object(GnomeDialog *dialog, gint button, GtkSignalFunc callback, GtkObject *obj) void gnome_dialog_close(GnomeDialog *dialog) void gnome_dialog_close_hides(GnomeDialog *dialog, gboolean just_hide)
void gnome_dialog_close_real(GnomeDialog *dialog) void gnome_dialog_construct(GnomeDialog *dialog, const gchar *title, va_list ap)
void gnome_dialog__constructv(GnomeDialog *dialog, const gchar *title, const gchar **buttons) void gnome_dialog_editable_enters(GnomeDialog *dialog, GtkEditable *editable)
guint gnome_dialog_get_type() GtkWidget *gnome_dialog_new(const gchar *title, ...) GtkWidget *gnome_dialog_newv(const gchar *title, const gchar **buttons)
gint gnome_dialog_run(GnomeDialog *dialog)
gint gnome_dialog_run_and_close(GnomeDialog *dialog)
void gnome_dialog_set_accelerator(GnomeDialog *dialog,
gint button, const guchar accelerator_key, guint8 accelerator_mods) void gnome_dialog_set_close(GnomeDialog *dialog, gboolean click_closes) void gnome_dialog_set_default(GnomeDialog *dialog, gint button) void gnome_dialog_set_parent(GnomeDialog *dialog, GtkWindow *parent) void gnome_dialog_set-Sensitive(GnomeDialog *dialog,
gint button, gboolean setting)
Text of the dialog boxText of the dialog box^ ok | X Cancel | ^^ ok | X Cancel | ^В этом примере сверху отображается виджет GtkLabel, а снизу используются две стандартные кнопки, как показано на рис. 22.8.
Text of the dialog box
Text of the dialog box
^ ok | X Cancel | ^
^ ok | X Cancel | ^
Рисунок 22.8.
Диалоговый ящик с меткой (надписью) и двумя предусмотренными кнопками
Кнопки добавляются в диалоговое окно слева направо в том порядке, в котором вы их укажите в обращении к функции gnome_dialog_new(). Чтобы дождаться реакции от кнопок, ко всему диалоговому окну подключается обратный вызов "clicked”. Внутри функции обратного вызова выбранные кнопки указываются по их номерам: первая кнопка является нулевой, вторая — первой и т.д. Затем для уничтожения диалогового ящика в самой функции обратного вызова производится обращение к gtk_widget_destroy ().
/** gnomedialog.с **/
Iinclude <gnome.h>
static void dialogCallback(GtkWidget *widget, gint button,gpointer data);
int main(int argc,char *argv[]) {
GtkWidget *dialog;
GtkWidget *box;
GtkWidget *label;
gnome_init("gnomedialog","1.0",argc,argv);
dialog = gnome_dialog_new("GnomeDialog", GNOME_STOCK_BUTTON_OK, GNOME_STOCK_BUTTON_CANCEL, NULL);
label = gtk_label_new("Text of the dialog box");
box = GNOMEDIALOG(dialog)->vbox;
gnome_dialog_set_default(GNOME_DIALOG(dialog),0);
gtk—boX—pack—start(GTKBOX(box),label,TRUE,TRUE,0);
gtk-Signal_connect(GTK-OBJECT(dialog),"clicked", dialogcallback,NULL);
gtk-Widget_shoW-all(dialog);
gtk-main();
exit(0);
}
static void dialogcallback(GtkWidget *widget,
gint button,gpointer data) { switch(button) { case 0:
g_print("The OK Button\n");
break;
case 1:.
g_print("The CANCEL Button\n");
break;
}
gtk_widget_destroy(widget);
}
Далее приведен список возможных кнопок, которые вы можете включить в диалоговой ящик..
GNOME_STOCK_BUTTON_OK
GNOME_STOCK_BUTTON_CANCEL
GNOME_STOCK_BUTTON_YES
GNOME_STOCK_BUTTON_NO
GNOME_STOCK_BUTTON_CLOSE
GNOME_STOCK_BUTTON_APPLY
GNOME_STOCK_BUTTON_HELP
GNOME_STOCK_BUTTON_NEXT
GNOME_STOCK_BUTTON_PREV
GNOME_STOCK_BUTTON_UP
GNOME_STOCK_BUTTON_DOWN GNOME_STOCK_BUTTON_FONT
GnomeDock
Вы можете добавить в окно виджет GnomeDock для управления стыковкой и расстыковкой кнопок. Он действительно управляет набором контейнеров GnomeDockBand, каждый из которых может содержать один или несколько GnomeDockltem (контейнер с одним виджетом).
Иерархия
GnomeDock->GtkContainer->GtkWidget->GtkObject
Функции
void gnomedock addfloating_item(GnomeDock *dock, GnomeDockltem *item, gint x, gint y, GtkOrientation orientation) gboolean gnome dockaddfromlayout(GnomeDock *dock, GnomeDockLayout *layout),
void gnome_dock_add_item(GnomeDock *dock, GnomeDockltem *item, GnomeDockPlacement placement, guint band_num, gint position, guint offset, gboolean innewband)
void gnomedockallow floatingitems(GnomeDock *dock, gboolean enable) GtkWidget *gnome_dock_get_client_area(GnomeDock *dock) GnomeDockltem *gnome_dock_get_item_by_name(GnomeDock *dock, const gchar *name, GnomeDockPlacement *placementreturn, guint *num_band_return, guint *band_position_return, guint *offsetreturn)
GnomeDockLayout *gnome_dock_get layout(GnomeDock *dock)
GtkType gnome dock_get type(void)
GtkWidget *gnome_dock_new(void) void gnomedock set client area(GnomeDock *dock, GtkWidget *widget)
Энумератор typedef enum { GNOME_DOCK_TOP, GNOME_DOCK_RIGHT,.
GNOME_DOCK_BOTTOM, GNOME_DOCK_LEFT, GNOME_DOCK_FLOATING } GnomeDockPlacement;
Сигнал "layout_changed" void cb(GtkWidget *, gpointer)
В следующем примере создается виджет GnomeDock и добавляется к главному окну приложения. Функция makeWidget () создает виджет и устанавливает в него три панели инструментов. Когда впервые появляется окно, то одна панель в нем находится сверху, одна — справа и одна свободно перемещается, как показано на рис. 22.9.
/** gnomedock.с **/'
♦include <gnome.h>
gint eventDelete(GtkWidget *widget, GdkEvent *event,gpointer data); gint eventDestroy(GtkWidget *widget, GdkEvent *event,gpointer data);
static GtkWidget *makeWidget(); static GtkWidget *makeToolbar(); static void uib_signal(GnomeUIInfo *uiinfo,gchar *signal_name, GnomeUIBuilderData *uibdata);
static GnomeUIInfo toolbarDef[] = { { GNOME_APP_UI_ITEM,"New",
"Create a new file",NULL,NULL,NULL,
GNOME_APP_PIXMAP_STOCK,GNOME_STOCK_PIXMAP_NEW, 0,0,NULL }, { GNOME_APP_UI_ITEM,"Open", "Open an existing file",NULL,NULL,NULL, GNOME_APP_PIXMAP_STOCK,GNOME_STOCK_PIXMAP_OPEN, 0,0,NULL }, { GNOME_APP_UI_ITEM,"Save", "Save the current file",NULL,NULL,NULL, GNOME APP PIXMAP STOCK,GNOME STOCK PIXMAP SAVE, 0,0,NULL }, { GNOME_APP_UI_IТЕМ,"Save as", "Save to a new file",NULL,NULL,NULL, GNOME APP PIXMAP STOCK,GNOME STOCK PIXMAP SAVE AS, 0,0,NULL }, GNOMEUIINFO_END };’
int main(int argc,char *argv[]) {
GtkWidget *app; GtkWidget *widget;
gnome_init("gnomedock","1.0",argc,argv); app = gnome_app_new("gnomedock", "fanomeDock"); gtk_widget_set_usize(GTK_WIDGET(app),350,350); gtk_signal_connect(GTK_OBJECT(app),"delete_event", GTK_SIGNAL_FUNC(eventDelete),NULL);
gtk_signal_connect(GTK_OBJECT(app),"destroy", GTK_SIGNAL_FUNC(eventDestroy),NULL);
widget = makeWidget();
gnome_app_set_contents(GNOME_APP(app),widget); gtk_widget_show_all(app);
gtk_main(); exit(0);
},
gint eventDelete(GtkWidget *widget, GdkEvent *event,gp6inter data) { return(FALSE);..
}
gint eventDestroy(GtkWidget *widget, GdkEvent *event,gpointer data) { gtk_main_quit();
return(O);
}
static GtkWidget *makeWidget() {
GtkWidget *dock; GnomeDockLayout *layout; GtkWidget *item;
GtkWidget *toolbar;
dock = gnome_dock_new(); layout = gnome_dock_layout_new();
toolbar = makeToolbar(); item = gnome_dock_item_new("Itemi", GNOME_DOCK_ITEM_BEH_EXCLUSIVE); gtk_container_add(GTK_CONTAINER(item),toolbar); gnome_dock_layout_add_item(layout,GNOME_DOCK_ITEM(item), GNOMEDOCKTOP,0,0,0);
toolbar = makeToolbar(); item = gnome_dock_item_new("Item2", GNOME_DOCK_ITEM_BEH_NORMAL); gtk_container_add(GTK_CONTAINER(item),toolbar); gnome_dock_layout_add_item(layout,GNOME_DOCK_ITEM(item), GNOME_DOCK_RIGHT,0,0,0);
toolbar = makeToolbar(); item = gnome_dock_item_new("Item3", GNOMEDOCKITEMBEHNORMAL); gtk_container_add(GTK_CONTAINER(item),toolbar); gnome_dock_layout_add_item(layout,GNOME_DOCK_ITEM(item), GNOMEDOCKFLOATING,0,0,0);
gtk_widget_show(toolbar); gtk_widget_show(item);
gnome_dock_layout_add_to_dock(GNOME_DOCK_LAYOUT(layout), GNOMEDOCK(dock));
return(dock);
}
static GtkWidget *makeToolbar()
GtkWidget *toolbar;
GnomeUIBuilderData uibdata;
toolbar = gtk_toolbar_new(GTK_ORIENTATION_HORIZONTAL, GTK_TOOLBAR_ICONS);
gtk_container_set_border_width(GTK_CONTAINER(toolbar), 1);
uibdata.connect_func = uib_signal;
uibdata.data = NULL;
uibdata.is_interp = FALSE;
uibdata.relay_func = NULL;
uibdata.destroy_func = NULL;
gnome_app_f ill_toolbar_custom(GTK_TOOLBAR(toolbar), toolbarDef,&uibdata,NULL);
return(toolbar);
}
static void uib_signal(GnomeUIInfo *uiinfo,gchar *signal_name, GnomeUIBuilderData *uibdata)
{
}
Рисунок 22.9.
Окно стыковки с тремя панелями инструментов
Как только создается одна из панелей инструментов, она вставляется в GnomeDockltem при помощи обращения к функции gtk_container_add(). Затем GnomeDockltem, в свою очередь, добавляется к GnomeDockLayout. И, наконец, GnomeDockLayout добавляется к GnomeDock при помощи вызова функции gnome_dock_layout_add_to_dock().
Окно GnomeApp обеспечивает более простой способ создания панелей инструментов. Некоторые примеры применения этого виджета можно обнаружить в главе 8.
GnomeDockBand
Это виджет-контейнер, который специально используется, чтобы содержать группу виджетов для виджета GnomeDock.
Иерархия
GnomeDockBand->GtkContainer->GtkWidget~>GtkObject
Функции
gboolean gnome_dock_band_append(GnomeDockBand *band,
GtkWidget *child, guint offset)
void gnome_dock_band_drag begin(GnomeDockBand *band, GnomeDockltem *item) void gnome_dock_band_drag_end(GnomeDockBand *band, GnomeDockltem *item) gboolean gnome_dock_band_drag_to(GnomeDockBand *band, GnomeDockltem *item, gint x, gint y)
guint gnome_dock_band_get_child offset(GnomeDockBand *band, GtkWidget *child)'
GnomeDockltem *gnome_dock_band_get_item_by_name( GnomeDockBand *band, const char *name, guint *position_return, guint *offset_return) guint gnome_dock_band_get_num_children(GnomeDockBand *band) GtkOrientation gnome_dock_band_get_orientation(GnomeDockBand *band) GtkType gnome_dock_band_get_type(void) , gboolean gnome_dockband_insert(GnomeDockBand *band,.
GtkWidget *child, guint offset, gint position) void gnome_dock_band_layout_add(GnomeDockBand *band, GnomeDockLayout *layout, GnomeDockPlacement placement, guint band_num) void gnome_dock_band_move_child(GnomeDockBand *band, GList *old_child, guint new_num)
GtkWidget *gnome_dock_band_new(void)
gboolean gnome_dock_band_prepend(GnomeDockBand *band,
GtkWidget *child, guint offset),
void gnome_dock_band_set_child_offset(GnomeDockBand *band, GtkWidget *child, guint offset)-
void gnome_dock_band_set_orientation(GnomeDockBand *band,•
GtkOrientation orientation)
Энумераторы
typedef enum {
GTK_ORIENTATION_HORIZONTAL,
GTK_ORIENTATION_VERTICAL,,
} GtkOrientation;
typedef enum {"
GNOME_DOCK_TOP, GNOME_DOCK_RIGHT, GNOME_DOCK_BOTTOM, GNOME_DOCK_LEFT, GNOME_DOCK_FLOATING } GnomeDockPlacement;
За примером стыковки можно обратиться к ранее описанному в этой главе виджету GnomeDock.
GnomeDockltem
Это контейнер, способный содержать один виджет. GnomeDockltem содержится в виджете GnomeDockBand, который, в свою очередь, находится в виджете GnomeDock.
Иерархия
GnomeDockItem->GtkBin->GtkContainer->GtkWidget->GtkObject
Функции•
void gnome_dock_item_attach(GnomeDockltem *item,
GtkWidget *parent, gint x, gint y)'
gboolean gnome_dock_item_detach(GnomeDockltem *item, gint x, gint y)
void gnome_dock_item_drag_floating(GnomeDockltem *item, gint x, gint y)
GnomeDockltemBehavior gnome_dock_item_get_behavior(-
GnomeDockltem *dock_item)
GtkWidget *gnome_dock_item_get_child(GnomeDockltem *item)
void gnome_dock_item_get_floating_position( GnomeDockltem *item, gint *x, gint *y) gchar *gnome_dock_item__get_name(GnomeDockltem *item) GtkOrientation gnome_dock_item_get_orientation( GnomeDockltem *dock_item)
GtkShadowType gnome_dock_item_get_shadow_type( GnomeDockltem *dock_item)
guint gnome_dock_item_get_type(void)
void gnome_dock_item_grab_pointer(GnomeDockltem *item)
void gnome_dock_item_handle_size_request(GnomeDockltem *item, GtkRequisition *requisition)
GtkWidget *gnome_dock_item_new(const gchar *name, GnomeDockltemBehavior behavior)
gboolean gnome_dock_item_set_orientation(
GnomeDockltem *dock_item, GtkOrientation orientation) void gnome_dock_item_set_shadow_type(
GnomeDockltem *dock_item, GtkShadowType type)
Энумератор
typedef enum {-
GNOME_D0CK_ITEM_BEH2N0RMAL,-
GNOME_DOCK_ITEM_BEH_EXCLUSIVE, GNOME_DOCK_ITEM_BEH_NEVER_FLOATING, GNOME_DOCK_ITEM_BEH_NEVER_VERTICAL, GNOME_DOCK_ITEM_BEH_NEVER_HORIZONTAL, GNOME_DOCK_ITEM_BEH_LOCKED
} GnomeDockltemBehavior;
Сигналы
Mdock_detachMvoidcb(GtkWidget*,gpointer)
"dock_drag_begin"voidcb(GtkWidget*,gpointer)
"dock_drag_end"voidcb(GtkWidget*,gpointer)
"dock_drag_motion"voidcb(GtkWidget*,gint, gint, gpointer)
За примером стыковки можно обратиться к ранее описанному в этой главе виджету GnomeDock.
GnomeDockLayout
Объект GnomeDockLayout — это контейнер, держащий виджеты в определенном месте в виджете GnomeDock.
Иерархия
GnomeDockLayout->GtkObject
Функции
gboolean gnome_dock_layout_add_floating_item(
GnomeDockLayout *layout, GnomeDockltem *item,\gint x, gint у, GtkOrientation orientation)
gboolean gnome_dock_layout_add_item(GnomeDockLayout *layout, GnomeDockltem *item, GnomeDockPlacement placement, gint bandnum, gint band_position, gint offset)
gboolean gnome_dock_layout_add_to_dock(
GnomeDockLayout *layout, GnomeDock *dock)
gchar *gnome_dock_layout_create_string(GnomeDockLayout *layout) GnomeDockLayoutItern *gnome_dock_layout_get_item(
GnomeDockLayout *layout, GnomeDockltem *item)
GnomeDockLayoutltem *gnome_dock_layout_get_item_by_name( GnomeDockLayout *layout, const gchar *name)
guint gnome_dock_layout_get_type(void)
GnomeDockLayout *gnome_dock_layout_new(void) gboolean gnome_dock_layout_parse_string(
GnomeDockLayout *layout, const gchar *string) gboolean gnome_dock_layout_remove_item(
GnomeDockLayout *layout, GnomeDockltem *item) gboolean gnome_dock_layout_remove_item_by_name ( GnomeDockLayout *layout, const gchar *name)
Энумератор
typedef enum {
GNOME_DOCK_TOP,'
GNOME_DOCK_RIGHT,•
GNOME_DOCK_BOTTOM,
GNOME_DOCK_LEFT, GNOME_DOCK_FLOATING } GnomeDockPlacement;
За примером стыковки можно обратиться к ранее описанному в этой главе виджету GnomeDock.
GnomeEntry
Виджет GnomeEntry принимает ввод пользователя. Однажды принятый элемент включается в предысторию (журнал) ранее введенной информации (или добавляется к приложению). Информацию об этом можно сохранить, чтобы затем восстановить, когда виджет появится в следующий раз.
Иерархия
GnomeEntry->GtkCombo->GtkHBox->GtkBox->GtkContainer->GtkWidget->GtkObject
Функции
void gnome_entry_append_history(GnomeEntry *gentry, gboolean save, const gchar *text) guint gnome_entry_get_type(void)
GtkWidget *gnome_entry_gtk_entry(GnomeEntry *gentry) void gnome_entry_load_history(GnomeEntry *gentry) GtkWidget *gnome_entry_new(const gchar *history id) void gnomeentryprependhistory(GnomeEntry *gentry, gboolean save, const gchar *text)
void gnome_entry_save_history(GnomeEntry *gentry) void gnome_entry_set_history_id(GnomeEntry *gentry, const gchar *history_id)
void gnome_entry_set_max_saved(GnomeEntry *gentry, guint max saved)
|Thlrd Append | /|Thlrd Append | /u—I Second Append I First Appendu—I Second Append I First AppendРисунок 22.10.Виджет GnomeEntry с тремя элементами предысторииРисунок 22.10.Виджет GnomeEntry с тремя элементами предысторииСледующий пример демонстрирует окно GnomeEntry с тремя пунктами, добавленными в список предыстории, как показано на рис. 22.10. Сохраненная предыстория помечается строкой идентификации, которую можно использовать для возвращения ранее сохраненной предыстории.
|Thlrd Append | /
|Thlrd Append | /
u—I Second Append I First Append
u—I Second Append I First Append
Рисунок 22.10.
Виджет GnomeEntry с тремя элементами предыстории
Рисунок 22.10.
Виджет GnomeEntry с тремя элементами предыстории
static GtkWidget *makeWidget()
{
GtkWidget *entry;
entry = gnome_entry_new("idstring");
gnome_entry_append_history(GNOMEENTRY(entry), TRUE,"First Append");
gnomeentryappendhistory(GNOME_ENTRY(entry), TRUE,"Second Append");
gnome_entry_append_history(GNOME_ENTRY(entry), TRUE,"Third Append");
gnome_entry_save_history(GNOME_ENTRY(entry));
return(entry); }
GnomeFileEntry'
Виджет предоставляет пользователю возможность выбрать имя файла. Пользователь может ввести имя файла с клавиатуры, выбрать его из опускающегося списка предварительно отобранных имен файлов или найти путем просмотра файловой системы.
Иерархия
GnomeFileEntry->GtkHBox->GtkBox->GtkContainer->GtkWidget->GtkObject
Функции
char *gnome_file_entry_get_full_path(GnomeFileEntry *fentry, int file_must_exist)
guint gnomefileentrygettype(void)
GtkWidget *gnome_file_entry_gnome_entry(GnomeFileEntry *fentry) GtkWidget *gnome_fileentrygtkentry(GnomeFileEntry *fentry) GtkWidget *gnome_file_entry_new(char *history id, char *browse_dialog_title) void gnomefileentrysetdefault_path(
GnomeFileEntry *fentry, char *path) void gnomefileentrysetdirectory(GnomeFileEntry *fentry, int directoryentry)
void gnome_file_entry_set_modal(GnomeFileEntry *fentry, int is_modal) void gnome_file_entry_set_titie(GnomeFileEntry *fentry, char *browse_dialog_title)
|pk/gn/22/code/animator.xpn^ / k/gn/22/code/island.xpm k/gn/22/code/makefile k/an/22/code/anomecolorolcl|pk/gn/22/code/animator.xpn^ / k/gn/22/code/island.xpm k/gn/22/code/makefile k/an/22/code/anomecolorolclРисунок 22.11.Виджет GnomeFileEntry c четырьмя запомненными именами файловРисунок 22.11.Виджет GnomeFileEntry c четырьмя запомненными именами файловBrowse., jBrowse., jСледующий код создает окно виджета GnomeFileEntry, изображенное на рис. 22.11. Виджет имеет сменяющийся список предварительно выбранных файлов. Окно ввода и сменяющийся список — виджеты GnomeEntry, поэтому имена файлов сохраняются от одного обращения к другому. Кнопка Browse раскрывает виджет GtkFileSelection, описанный в главе 21, что дает возможность пользователю выбрать файл.
|pk/gn/22/code/animator.xpn^ / k/gn/22/code/island.xpm k/gn/22/code/makefile k/an/22/code/anomecolorolcl
|pk/gn/22/code/animator.xpn^ / k/gn/22/code/island.xpm k/gn/22/code/makefile k/an/22/code/anomecolorolcl
Рисунок 22.11.
Виджет GnomeFileEntry c четырьмя запомненными именами файлов
Рисунок 22.11.
Виджет GnomeFileEntry c четырьмя запомненными именами файлов
Browse., j
Browse., j
static GtkWidget *makeWidget()
{
GtkWidget *fileentry;
fileentry = gnome file_entry_new("fseekid","File Seeking");
return(fileentry);
}
Строка ”fseekid” — это идентификатор, который используется для сохранения списка ранее выбранных имен файлов. Вторая строка — это строка заголовка окна GtkFileSelection.
GnomeFontPicker
Виджет GnomeFontPicker — это кнопка, которая, будучи выбранной, представляет окно, позволяющее пользователю выбрать нужный среди многих доступных шрифтов.
Иерархия
GnomeFontPicker->GtkButton->GtkBin->GtkContainer->GtkWidget->GtkOb ject
Функции
GtkWidget *gnome_font_picker_create_inside(GnomeFontPicker *gfp)
void gnome_font_picker_dialog_destroy(GtkWidget *widget, gpointer data)
void gnome_font_picker_f i_set_show_size (GnomeFontPicker *gfpr gboolean showsize)
void gnomefont_picker_fi_set_use_font_in_label(
GnomeFontPicker *gfp, gboolean use_font_in_label, gint size)
void gnome_font_picker_font_extract_attr(gchar *font_name, gchar *attr, gint i)
void gnome_font_picker_font_set_attr(gchar **font_name, const gchar *attr, gint i)
GdkFont *gnome_font_picker_get_font(GnomeFontPicker *gfp)
gchar *gnome_font_picker_get_font_name(GnomeFontPicker *gfp)
GnomeFontPickerMode gnome_font_picker_get_mode(GnomeFontPicker *gfp)
gchar *gnome_font_picker_get_preview_text(GnomeFontPicker *gfp)
GtkType gnome_font_picker_get_type(void)
void gnome_font_picker_label_use_font_in_label (GnomeFontPicker *gfp)
GtkWidget *gnome_font_picker_new(void)
gboolean gnome_font_picker_set_font_name(
GnomeFontPicker *gfp, const gchar *fontname)
void gnome_font_picker_set_mode(GnomeFontPicker *gfp,
GnomeFontPickerMode mode)
void gnome_font_picker_set_preview_text(GnomeFontPicker *gfp, const gchar *text)
void gnome_font_picker_set_title(GnomeFontPicker *gfp, const gchar *title) void gnome_font_picker_update_font_info(GnomeFontPicker *gfp) void gnome font_picker_uw_set_widget(GnomeFontPicker *gfp, GtkWidget *widget)
Энумератор
typedef enum {
GNOME_FONT_PICKER_MODE_PIXMAPr
GNOME_FONT_PICKER_MODE_FONT_INFO,
GNOME_FONT_PICKER_MODE_USER_WIDGET,
GNOME_FONT_PICKER_MODE_UNKNOWN
} GnomeFontPickerMode;
В главе 13 приведены примеры использования виджета GnomeFontPicker.
GnomeFontSelector
Виджет GnomeFontSelector — это диалоговое окно, которое позволяет управлять всеми деталями возникновения, принятия ввода и возвращения имени выбранного шрифта.
Иерархия
GnomeFontSelector->GtkDialog->GtkWindow->GtkBin->GtkContainer->GtkWidget-*>
GtkObject
Функции'
gchar *gnome_font_select(void)
gchar *gnome_font_select_with_default(const gchar *default_font)
gchar *gnome_font_selector_get_selected(GnomeFontSelector *text_tool)
guint gnome_font_selector_get_type(void)
GtkWidget *gnome_font_selector_new(void)
Этот пример демонстрирует, как ваше приложение может выполнить единственный вызов функции, возвращающей выбранный шрифт. Можно вызвать функцию gnome_font_select() или gnome_font_select_with_default() с любого места вашей программы, появится диалоговое окно, изображенное на рис. 22.12. Обращение к функции содержит свой собственный цикл событий, поэтому возврата не происходит, пока пользователь не выберет шрифт или не закроет диалоговое окно.
/** gnomefontpicker.с **/
Iinclude <gnome.h>
int main(int argc,char *argv[]) { gchar *font;
gnome_init("gnomefontpicker"," 1.0 ",argc,argv);
font = gnomefontselect();
if(font == NULL) g print("No font selected\n");
else gprint("Selected: %s\n",font);
exit(O);
}
ireiveucdiidiruw lucida lucidabright lucidatypewnter new century scho palatine symbol terminalireiveucdiidiruw lucida lucidabright lucidatypewnter new century scho palatine symbol terminalWeight boldWeight boldutopiazapf chancery zapf dingbatsutopiazapf chancery zapf dingbatsRRFoundry adobeFoundry adobeSlantSlantSet width normal Spacing p J |Border pSet width normal Spacing p J |Border pРисунок 22.12.Диалоговое окно GnomeFontSelectorРисунок 22.12.Диалоговое окно GnomeFontSelector
ireiveucdiidiruw lucida lucidabright lucidatypewnter new century scho palatine symbol terminal
ireiveucdiidiruw lucida lucidabright lucidatypewnter new century scho palatine symbol terminal
Weight bold
Weight bold
utopia
zapf chancery zapf dingbats
utopia
zapf chancery zapf dingbats
R
R
Foundry adobe
Foundry adobe
Slant
Slant
Set width normal Spacing p J |
Border p
Set width normal Spacing p J |
Border p
Рисунок 22.12.
Диалоговое окно GnomeFontSelector
Рисунок 22.12.
Диалоговое окно GnomeFontSelector
!AaBbCcDdEeFfGg№
OKOKCancel
OK
OK
GnomeGuru
Это еще не завершенный виджет. Когда он будет закончен, то станет инструментом для построения мастера (список шагов, который изменяется в соответствии с тем, какую ветвь вы выбрали).
Иерархия
GnomeGuru->GtkVBox->GtkBox->GtkContainer->GtkWidget->GtkObject
Функции
void gnome_guru_append_page(GnomeGuru *guru, const gchar *name, GtkWidget *widget)
void gnome_guru_back_set_sensitive(GnomeGuru *guru, gboolean sensitivity) void gnome_guru_constract(GnomeGuru *guru, const gchar *name, GtkWidget *graphic, GnomeDialog *dialog)
GtkWidget *gnome_guru_current_page(GnomeGuru *guru) guint gnome_guru_get_type()
GtkWidget *gnome_guru_new(const gchar *name, GtkWidget *graphic, GnomeDialog *dialog) void gnome_guru_next_set_sensitive(GnomeGuru *guru, gboolean sensitivity)
GnomeHRef
Виджет отображает необрамленную кнопку, которая, будучи выбранной, выдает команду Web-браузеру подключиться к Web-сайту. Актуальная команда для браузера задается глобально как для принятого по умолчанию члена списка обработчика URL в Gnome Control Center (в центре управления Gnome).
Иерархия
GnomeHRef->GtkButton->GtkBin->GtkContainer->GtkWidget->GtkObject
Функции
gchar *gnome_href_get_label(GnomeHRef *self)
guint gnome_href_get_type(void)
gchar *gnome_href_get_url(GnomeHRef *self)
GtkWidget *gnome_href_new(const gchar *url, const gchar *label) void gnomehrefsetlabel(GnomeHRef *self, const gchar *label) void gnome_href_set_url(GnomeHRef *self, const gchar *url)
Ж- GnomeHRef ip а хЖ- GnomeHRef ip а хGnome's start pageGnome's start pageЭтот пример создает виджет с меткой (с надписью) Gnome's start page и присоединяет к нему URL. Виджет появляется как обычный текст, что показано на рис. 22.13, голубого цвета и подчеркнутый. Таким образом, можно включить его в текст среди других виджетов и он бу- Рисунок 22.13. дет распознаваться как ссылка. Вокруг виджета появляется Виджет GnomeHRef— рамка, когда указатель мыши проходит по нему.указатель на Web-сайт
Ж- GnomeHRef ip а х
Ж- GnomeHRef ip а х
Gnome's start page
Gnome's start page
static GtkWidget *makeWidget() <
GtkWidget *href;
href = gnome_href_new("http://www.gnome.org/start", "Gnome's start page");
return(href);
>
GnomelconEntry
Виджет GnomelconEntry — это кнопка, которая инициирует появление окна, выводящего список пиктограмм. Пользователь может выбрать одну из пиктограмм, содержащуюся в /usr/share/pixmaps, или просмотреть содержимое файловой системы для поиска пиктограмм в других каталогах. Опускающийся список имен каталогов поддерживает предысторию ранее открытых каталогов.
Иерархия
GnomeIconEntry->GtkVBox->GtkBox->GtkContainer->GtkWidget->GtkObject
Функции
char *gnome_icon_entry_get_filename(GnomelconEntry *ientry)
guint gnome_icon_entry_get_type(void)
GtkWidget *gnome_icon_entry_gnome_entry(GnomelconEntry *ientry)
GtkWidget *gnome_icon_entry_gnome_file_entry(GnomelconEntry *ientry)
GtkWidget *gnome_icon_entry_gtk_entry(GnomelconEntry *ientry)
GtkWidget *gnome_icon_entry_new(char *history_id, char *browse_dialog_title)
void gnome_icon_entry_set_icon(GnomelconEntry *ientry, const char *filename)
void gnome_icon_entry_set_pixmap_subdir(
GnomelconEntry *ientry, const char *subdir)
В следующем примере создается кнопка, которая при щелчке на ней показывает диалоговое окно, изображенный на рис. 22.14. Если пользователь выбрал пиктограмму, то кнопка меняется, чтобы отобразить эту пиктограмму, как показано на рис. 22.15.
static GtkWidget *makeWidget()
GtkWidget *iconentry;
GtkWidget *entry;
iconentry = gnome_icon_entry__new( "historyID",
"Select an Icon");
entry = gnome_icon_entry_gtk_entry(
GNOME_ICON_ENTRY(iconentry));
gtk_signal_connect(GTK_OBJECT(entry),"changed",
GTK_SIGNAL_FUNC(eventlconChanged),iconentry);
return(iconentry);
}
void eventlconChanged(GtkWidget *widget, GnomelconEntry *iconentry)
{
GtkWidget *dialog;
dialog = GNOME_ICON_ENTRY(iconentry)->pick_dialog;
if(dialog 1= NULL) {
gtk signal handlersdestroy(GTK OBJECT(dialog)); gtk_signal_connect(GTK OBJECT(dialog),"clicked", eventlconSelected,iconentry);
}
}
void eventlconSelected(GtkWidget *widget,gint button, GnomelconEntry *iconentry)
{
gchar *iconfile;
switch(button) {
case 0:
iconfile = gnome_icon_entry_get_filename(iconentry);
g_print("Icon file name: %s\n",iconfile);
break;
g_print("No icon selection was made\n“);
|/usr/share/pixmaps/Mailbox- Summer dir xpm|/usr/share/pixmaps/Mailbox- Summer dir xpm| ^ OK| ^ OKX Cancel |X Cancel |Рисунок 22.14. Диалоговое окно выбора пиктограммы виджета GnomelconEntryРисунок 22.14. Диалоговое окно выбора пиктограммы виджета GnomelconEntryРисунок 22.15. Задействованная кнопка виджета GnomelconEntryРисунок 22.15. Задействованная кнопка виджета GnomelconEntry
|/usr/share/pixmaps/Mailbox- Summer dir xpm
|/usr/share/pixmaps/Mailbox- Summer dir xpm
| ^ OK
| ^ OK
X Cancel |
X Cancel |
Рисунок 22.14. Диалоговое окно выбора пиктограммы виджета GnomelconEntry
Рисунок 22.14. Диалоговое окно выбора пиктограммы виджета GnomelconEntry
Рисунок 22.15. Задействованная кнопка виджета GnomelconEntry
Рисунок 22.15. Задействованная кнопка виджета GnomelconEntry
В действительности здесь присутствуют два виджета. Один — это кнопка, которая вызывает диалоговое окно выбора. Другой — это диалоговое окно выбора, которое построено как виджет GnomeDialog. Всякий раз, когда выбирается кнопка, возникает диалоговое окно, чтобы пользователь смог выбрать пиктограмму. Следующий пример присоединяет сигнал "changed” к виджету GnomeEntry внутри виджета GnomelconEntry; это вызывает функцию обратного вызова eventIconChanged() всякий раз, когда пользователь выбирает пиктограмму при помощи мыши или набирая ее название.
Можно извлечь название пиктограммы из функции обратного вызова event!conChanged(), но в действительности этого никогда не случится, пока не выбрана кнопка ОК. Чтобы дождаться щелчка на кнопке, необходимо добавить к виджету GnomeDialog обратный вызов ”clicked". Этот сигнал устанавливается для выполнения функции обратного вызова eventIconSelected() всякий раз, когда пользователь выбрал кнопку ОК или кнопку Cancel. Если пользователь выбрал кнопку ОК, то может быть получено имя выбранной пиктограммы. Кнопка освобождается от всех сигналов до присоединения нового, так как функция обратного вызова eventlconChanged( ) может вызываться несколько раз до поступления сигнала "clicked".
ПРИМЕЧАНИЕ
Эта двойная последовательность обратных вызовов необходима только потому, что функция обратного вызова eventlconChanged() вызывается всякий раз, когда пользователь щелкает на пиктограмме в окне просмотра. В то время, когда новое имя файла пиктограммы доступно в этой точке, необходима и другая функция обратного вызова для определения, была ли нажата пользователем кнопка ОК или кнопка Cancel.
GnomelconSelection
Загружает и выводит набор пиктограмм и предоставляет возможность пользователю выбрать одну из них. В приложении необходимо указать каталог или каталоги, содержащие пиктограммы, которые должны быть выведены. Этот виджет используется как окно выбора в виджете Gnome IconEntry.
Иерархия
GnomeIconSelection->GtkVBox->GtkBox->GtkContainer->GtkWidget->GtkObject
Функции
void gnome_icon_selection_add_defaults(GnomelconSelection *gis)
void gnome_icon_selection_add_directory(
GnomelconSelection *gis, const gchar *dir)
void gnome_icon_selection_clear(GnomelconSelection *gis, gboolean not_shown)
const gchar *gnome_icon_selection_get_icon(
GnomelconSelection *gis, gboolean full_path)
guint gnome_icon_selection_get_type()
GtkWidget *gnome_icon_selection_new(void)
void gnome_icon_selection_select_icon(
GnomelconSelection *gis, const gchar *filename)
void gnome_icon_selection_show_icons(GnomelconSelection *gis)
void gnome_icon_selection_stop_loading(GnomeIconSelection *gis)
В следующем примере принятый по умолчанию набор пиктограмм загружается в виджет GnomelconSelection и отображается, что и показано на рис. 22.16.
Рисунок 22.16.
Виджет GnomelconSelection с принятым по умолчанию набором пиктограмм
Этот пример не содержит кнопки или других механизмов, необходимых для распознавания момента, когда пользователь выбирает виджет. Это можно сделать путем добавления кнопки с функцией обратного вызова, что достигается при обращении к функции gnome_icon_selection_get_icon(), извлекающей имя файла пиктограммы.
GnomeLess
Отображает содержимое текстового файла.
Иерархия
GnomeLess->GtkVBox->GtkBox->GtkContainer->GtkWidget->GtkObject
Функции
void gnome_less_clear(GnomeLess *gl)
void gnome_less_fixed_font(GnomeLess *gl)
guint gnome_less_get_type()
GtkWidget *gnome_less_new(void)
void gnome_less_reshow(GnomeLess *gl)
void gnome_less_set_fixed_font(GnomeLess *gl, gboolean fixed)
void gnome_less_set_font(GnomeLess *glr GdkFont *font)
gboolean gnome_less_show_command(GnomeLess *glr const gchar *command_line)
gboolean gnome_less_show_fd(GnomeLess *gl, int file_descriptor) gboolean gnome_less_show_file(GnomeLess *gl, const gchar *path) gboolean gnome_less_show_filestream(GnomeLess *gl, FILE *f) void gnome_less_show_string(GnomeLess *gl, const gchar *s) gboolean gnome_less_write_fd(GnomeLess *gl, int fd)
gboolean gnome_less_write_file(GnomeLess *gl, const gchar *path)
В следующем примере программы используется виджет GnomeLess для вывода собственного исходного кода, как показано на рис. 22.17.
static GtkWidget *makeWidget()
GtkWidget *less;
less = gnome_less_new();
gnome_less_show_file(GNOME_LESS(less),"gnomeless.c");
return(less);
int main(int argc,char "argvD)int main(int argc,char "argvD)GtkWidget ‘app;JGtkWidget "widget,GtkWidget ‘app;JGtkWidget "widget,gnome Jnit("gnomele$$","1.0",argc,argv);app « gnome_app_new("gnomele$$VGnomeLe a$$"),gtk_container_set_border_width(GTK_CONTAIN 3gnome Jnit("gnomele$$","1.0",argc,argv);app « gnome_app_new("gnomele$$VGnomeLe a$$"),gtk_container_set_border_width(GTK_CONTAIN 3}
int main(int argc,char "argvD)
int main(int argc,char "argvD)
GtkWidget ‘app;J
GtkWidget "widget,
GtkWidget ‘app;J
GtkWidget "widget,
gnome Jnit("gnomele$$","1.0",argc,argv);
app « gnome_app_new("gnomele$$VGnomeLe a
$$"),
gtk_container_set_border_width(GTK_CONTAIN 3
gnome Jnit("gnomele$$","1.0",argc,argv);
app « gnome_app_new("gnomele$$VGnomeLe a
$$"),
gtk_container_set_border_width(GTK_CONTAIN 3
Рисунок 22.17.
Виджет GnomeLess отображает содержимое текстового файла
GnomeMDI
Объект GnomeMDI отслеживает составные виджеты, сравнивая различные окна интерфейса MDI.
Иерархия
GnomeMDI~>GtkObject
Функции
gint gnome_mdi_add_child(GnomeMDI *mdi, GnomeMDIChild *child)
gint gnome_mdi_add_toplevel_view(GnomeMDI *mdi, GnomeMDIChild *child)
gint gnome_mdi_add_view(GnomeMDI *mdi, GnomeMDIChild *child)
GnomeMDIChild *gnome_mdi_find_child(GnomeMDI *mdi, gchar *name)
GnomeMDIChild *gnome_mdi_get_active_child(GnomeMDI *mdi)
GtkWidget *gnome_mdi_get_active_view(GnomeMDI *mdi)
GnomeApp *gnome_mdi_get_active_window(GnomeMDI *mdi)
GnomeApp *gnome_mdi_get_app_from_view(GtkWidget *view)
GnomeMDIChild *gnome_mdi_get_child_from_view(GtkWidget *view)
GnomeUIInfo *gnome_mdi_get_child_menu_info(GnomeApp *арр)
GnomeUIInfo *gnome_mdi_get_menubar_info(GnomeApp *app) GnomeUIInfo *gnome_mdi get_toolbar_info(GnomeApp *app) guint gnome_mdi_get_type()
GtkWidget *gnome_mdi_get_view_from_window(GnomeMDI *mdi, GnomeApp *app) GtkObject *gnome_mdi_new(gchar *appname, gchar *title) void gnome_mdi_open_toplevel(GnomeMDI *mdi) void gnome_mdi_register(GnomeMDI *mdi, GtkObject *object) gint gnome_mdi_remove_all(GnomeMDI *mdi, gint force) gint gnome_mdi_remove_chiId(GnomeMDI *mdi, GnomeMDIChild *child, gint force)
gint gnome_mdi_remove_view(GnomeMDI *mdi, GtkWidget *view, gint force) void gnome_mdi_set_active_view(GnomeMDI *mdi, GtkWidget *view) void gnome_mdi_set_child_list_path(GnomeMDI *mdi, const gchar *path) void gnome_mdi_set_child_menu_path(GnomeMDI *mdi, const gchar *path) void gnome_mdi_set_menubar_template(GnomeMDI *mdi, GnomeUIInfo *menu_tmpl) void gnome_mdi_set_mode(GnomeMDI *mdi, GnomeMDIMode mode) void gnome_mdi_set toolbar_template(GnomeMDI *mdi, GnomeUIInfo *tbar_tmpl) void gnome_mdi_unregister(GnomeMDI *mdi, GtkObject *object) void gnome_mdi_update_child(GnomeMDI *mdi, GnomeMDIChild *child)
В главе 17 приведены примеры использования виджета GnomeMDI.
GnomeMDIChild
Объект GnomeMDIChild — это базовый класс, используемый для создания виджетов, которыми как окнами MDI может управлять GnomeMDI. Если только вы не имеете специальных требований, можно использовать GnomeMDIGenericChild, который базируется на GnomeMDIChild.
Иерархия
GnomeMDIChild->GtkObject*
Функции
GtkWidget *gnome_mdi_child_add_view(GnomeMDIChild *mdi child) guint gnome_mdi_child_get_type() void gnome_mdi_child_remove_view(GnomeMDIChild *mdi child, GtkWidget *view) void gnome_mdi_child_set_menu_template(
GnomeMDIChild *mdi_child, GnomeUIInfo *menu_tmpl) void gnome_mdi_child_set_name(GnomeMDIChild *mdi child, gchar *name)
GnomeMDIGenericChild
Виджет GnomeMDIGenericChild — это обобщенная форма дочернего окна, которое можно использовать в MD1.
Иерархия
GnomeMDIGenericChild->GnomeMDIChild->GtkObject
Функции
guint gnome_mdi_generic_child_get_type()
GnomeMDIGenericChild *gnome_mdi_generic_child_new(gchar *name) void gnome_mdi_generic_child_set_config_func(
GnomeMDIGenericChild *child, GnomeMDIChildConfigFunc func, gpointer data) void gnome_mdi_generic_child_set_config_func_full(
GnomeMDIGenericChild *child, GnomeMDIChildConfigFunc func, GtkCallbackMarshal marshal, gpointer data, GtkDestroyNotify notify)
void gnome_mdi_generic_child_set_label_func(
GnomeMDIGenericChild *child, GnomeMDIChildLabelFunc func, gpointer data)
void gnome_mdi_generic_child_set_label_func_full(
GnomeMDIGenericChild *child, GnomeMDIChildLabelFunc func, GtkCallbackMarshal marshal, gpointer data, GtkDestroyNotify notify)
void gnome_mdi_generic_child_set_menu_creator(
GnomeMDIGenericChild *child, GnomeMDIChildMenuCreator func, gpointer data)
void gnome_mdi_generic_child_set_menu_creator_full(
GnomeMDIGenericChild *child, GnomeMDIChildMenuCreator func, GtkCallbackMarshal marshal, gpointer data, GtkDestroyNotify notify) void gnome_mdi_generic_child_set_view_creator(
GnomeMDIGenericChild *child, GnomeMDIChildViewCreator func, gpointer data)
void gnome_mdi_generic_child_set_view_creator _full( GnomeMDIGenericChild *child, GnomeMDIChildViewCreator func, GtkCallbackMarshal marshal, gpointer data, GtkDestroyNotify notify)
В главе 17 приведены примеры использования виджета GnomeMDIGenericChild.
GnomeMessageBox
GnomeMessageBox — это диалоговый ящик, который можно использовать для показа простых сообщений и получения ответа. Диалоговый ящик создается как собственное окно верхнего уровня, в котором отображается стандартная пиктограмма, текстовое сообщение и ряд кнопок.
Иерархия .
GnomeMessageBox->GnomeDialog->GtkWindow->GtkBin->GtkContainer->GtkWidget-> GtkObject
Функции
guint gnome_message_box_get_type()
GtkWidget *gnome_message_box_new(const gchar *message, const gchar *message_box_type, ...)
GtkWidget *gnome_message_box_newv(const gchar *message, const gchar *message_box_type, const gchar **buttons) void gnome_message_box_set_default(
GnomeMessageBox *message_box, gint button)
void gnome_message_box_set_modal(GnomeMessageBox *message_box)
Виджет GnomeMessageBox — это "упаковка” виджета GnomeDialog для упрощения интерфейса. В него автоматически включаются текстовое сообщение и соответствующая пиктограмма. Отреагировав на мышь и обратный вызов, он сам себя закрывает. Глава 3 содержит примеры и информацию о наборе предопределенных диалоговых ящиков.
В следующем примере задается вопрос, и для ответа на него пользователю предлагаются три кнопки (см. рис. 22.18).
/** gnomemessagebox.с **/
♦include <gnome.h>
static void messageboxCallback(GtkWidget *widget, gint button,gpointer data);
int main(int argc,char *argv[]) {
GtkWidget *messagebox;
gnome_init("gnomemessagebox","1.0",argc,argv);
messagebox = gnome_message_box_new(
"Is this the question being displayed?", GNOME_MESSAGE_BOX_QUESTION, GNOME_STOCK_BUTTON_YES, GNOME_STOCK_BUTTON_NO, GNOME_STOCK_BUTTON_CLOSE, NULL);
gtk_signal_connect(GTK_OBJECT(messagebox),"clicked", messageboxCallback,NULL);
gtk_widget_show_al1(messagebox);
gtk_main();
exit(0);
}
static void messageboxCallback(GtkWidget *widget, gint button,gpointer data)
{
switch(button) { case 0:
g_print("The YES ButtonXn"); break;
case 1:
g_print("The NO ButtonXn");
break; -
g_print("The CLOSE ButtonXn"); break;
}
}
Ж]Ж]XX
Ж]
Ж]
X
X
te this the question being displayed?te this the question being displayed?Рисунок 22.18.Виджет GnomeMessageBoxРисунок 22.18.Виджет GnomeMessageBox
te this the question being displayed?
te this the question being displayed?
Рисунок 22.18.
Виджет GnomeMessageBox
Рисунок 22.18.
Виджет GnomeMessageBox
^ Yes |^ Yes |0 No |0 No |X Close |X Close |
^ Yes |
^ Yes |
0 No |
0 No |
X Close |
X Close |
Далее приведен список различных типов ящиков с сообщениями:
GNOME_MESSAGE_BOX_INFO
GNOME_MESSAGE_BOX_WARNING
GNOMEMESSAGEBOXERROR
GNOME_MESSAGE_BOX_QUESTION
GNOMEMESSAGE_BOX_GENERIC
Далее приведен список кнопок, которые можно включать как часть диалогового ящика.
GNOMESTOCKBUTTONOK
GNOME_STOCK_BUTTON_CANCEL
GNOMESTOCKBUTTONYES
GNOMESTOCKBUTTONNO
GNOME_STOCK_BUTTON_CLOSE GNOME_STOCK_BUTTON_APPLY GNOME_STOCK_BUTTON_HELP GNOME_STOCK_BUTTON_NEXT GNOME_STOCK_BUTTON_PREV GNOME_STOCK_BUTTON_UP GNOMESTOCKBUTTONDOWN GNOME_STOCK_BUTTON_FONT
GnomeNumberEntry
Виджет GnomeNumberEntry позволяет пользователю вводить числовые значения.
Иерархия
GnomeNumberEntry->GtkHBox->GtkBox->GtkContainer->GtkWidget->GtkObject
Функции
gdouble gnome_number_entry__get_number(GnomeNumberEntry *nentry)
guint gnome_number_entry_get_type(void)
GtkWidget *gnome_number_entry_gnome_entry(GnomeNumberEntry *nentry)
GtkWidget *gnome_number_entry_gtk_entry(GnomeNumberEntry *nentry)
GtkWidget *gnome_number_entry_new(char *history_id, char *calc_dialog_title)
void gnome number_entry_set_title(GnomeNumberEntry *nentry, . char *calc_dialog_title)
Следующая функция создает виджет GnomeNumberEntry, изображенный на рис. 22.19, который использует строку "histed" для заполнения его опускающегося списка с последними выбранными числами. Строка "Minimum Distance" используется в строке заголовка калькулятора: если он возникает на экране, то сохраняет результаты как текст в окне GnomeNumberEntry. Calculator (калькулятор) — это виджет GnomeCalculator, описанный в этой главе.
static GtkWidget *makeWidget() {
GtkWidget *numberentry;
numberentry = gnome_number_entry_new("histid", "Minimum Distance");
return(numberentry); }
Рисунок 22.19.
Виджет GnomeNumberEntry, демонстрирующий окно для вывода данных и кнопку Calculator
GnomePaperSelector
Виджет GnomePaperSelector приглашает пользователя ввести тип и размер бумаги для принтера.
Иерархия
GnomePaperSelector->GtkVBox->GtkBox->GtkContainer->GtkWidget->GtkObject
Функции
gfloat gnome_paper_selector_get_bottom_margin(GnomePaperSelector *gspaper)
gfloat gnome_paper_selector_get_height(GnomePaperSelector *gspaper)
gfloat gnome_paper_selector_get_left_margin(GnomePaperSelector *gspaper) gchar *gnome_paper_selector_get_name(GnomePaperSelector *gspaper) gfloat gnome_paper_selector_get_right_margin(GnomePaperSelector *gspaper) gfloat gnome_paper_selector_get_top_margin(GnomePaperSelector *gspaper) guint gnome_paper_selector_get_type(void)
gfloat gnome_paper_selector_get_width(GnomePaperSelector *gspaper)
GtkWidget *gnome_paper_selector_new(void)
void gnome_paper_selector_set_height(
GnomePaperSelector *gspaper, gfloat height)
void gnome_paper_selector_set_name(
GnomePaperSelector *gspaper, gchar *name)
void gnome_paper_selector_set_width(
GnomePaperSelector *gspaper, gfloat width)
Следующий код создает виджет GnomePaperSelector, изображенный на рис. 22.20. Кнопка снизу меняет в виджете принятые по умолчанию в системе размеры бумаги. По умолчанию поиск происходит в следующем порядке: переменная окружения PAPERCONF, содержимое файла, имя которого определяется переменной среды PAPERSIZE, файл /etc/conf и, наконец, размеры по умолчанию, встроенные в виджет.
static GtkWidget *makeWidget()
{
GtkWidget *paperselector;
paperselector = gnome_paper_selector_new();
return(paperselector); }
Рисунок 22.20.
Виджет GnomePaperSelector, показывающий установки размеров бумаги по умолчанию
GnomePixmap
Это цветное растровое изображение в виде окна. Так как это виджет, вы можете включить его прямо в контейнер; вы можете использовать примитивные функции рисования и раскрашивания, чтобы модифицировать его внешний вид.
Иерархия
GnomePixmap->GtkWidget->GtkObject
Функции
guint gnome pixmapgettype(void)
void gnome_pixmap_load_file(GnomePixmap *gpixmap, const char *filename)
void gnome_pixmap_load_file_at_size(GnomePixmap *gpixmap, const char *filename, int width, int height)
void gnome_pixmap_load_imlib(GnomePixmap *gpixmap, Gdklmliblmage *im) void gnomepixmap load_imlib_at_size(GnomePixmap *gpixmap,
Gdklmliblmage *im, int width, int height) void gnome_pixmap_load_rgb_d(GnomePixmap *gpixmap, unsigned char *data, unsigned char *alpha, int rgb_width, int rgb_height) void gnome_pixmap_load_rgb_d_at_size(GnomePixmap *gpixmap, unsigned char *data, unsigned char *alpha, int rgb_width, int rgb_height, int width, int height) void gnome_pixmap_load_rgb_d_shaped(GnomePixmap *gpixmap, unsigned char *data, unsigned char *alpha, int rgb_width, int rgb_height, GdklmlibColor *shape_color) void gnome_pixmap_load_rgb_d_shaped_at_size( GnomePixmap *gpixmap, unsigned char *data, unsigned char *alpha, int rgbwidth, int rgb_height, int width, int height, GdklmlibColor *shape_color) void gnome_pixmap_load_xpm_d(GnomePixmap *gpixmap, char **xpm_data) void gnome_pixmap_load_xpm_d_at_size(GnomePixmap *gpixmap, char **xpm_data, int width, int height) GtkWidget *gnome_pixmap_new_from_file(const char ♦ filename) GtkWidget *gnome_pixmap_new_from_file_at_size( const char *filename, int width, int height) GtkWidget *gnome_pixmap_new_from_gnome_pixmap (GnomePixmap *gpixmap old) GtkWidget *gnome_pixmap_new_from_imlib( Gdklmliblmage *im) GtkWidget *gnome_pixmap_newfrom_imlib_at_size( Gdklmliblmage *im, int width, int height) GtkWidget *gnome_pixmap_new fromrgb d(unsigned char *data, unsigned char *alpha, int rgb_width, int rgb_height) GtkWidget *gnome pixmapnewfromrgb_d_at size( unsigned char *data, unsigned char *alpha, int rgb_width, int rgb_height, int width, int height) GtkWidget *gnome_pixmap_new_from_rgb_d_shaped( unsigned char *data, unsigned char *alpha, int rgb_width, int rgb height, GdklmlibColor *shape_color) GtkWidget *gnome_pixmap_new_fromrgb ^shaped at size( unsigned char *data, unsigned char *alpha, int rgbwidth, int rgb_height, int width, int height, GdklmlibColor *shape_color) GtkWidget *gnome pixmap new from xpm dfchar **xpm_data) GtkWidget *gnome pixmap new from xpm d at size( char **xpm_data, int width, int height)
GnomePixmapGnomePixmapРисунок 22JВиджетGnomePixmaРисунок 22JВиджетGnomePixmaВ следующем примере создается виджет GnomePixmap из файла формата ХРМ. В главе 7 описывается такой формат файла. В этом примере данные формата ХРМ имеют ширину 64 пиксела и высоту 36 пикселов, а загруженная версия увеличивается в два раза, следовательно, устанавливается размер 128 на 72. В результате получаем виджет, изображенный на рис. 22.21.
GnomePixmap
GnomePixmap
Рисунок 22J
Виджет
GnomePixma
Рисунок 22J
Виджет
GnomePixma
static GtkWidget *makeWidget(). { GtkWidget *widget;
widget = gnome_pixmap_new_from_file_at_size("island, xpm", 128,72);
return(widget);
GnomePixmapEntry
Виджет GnomePixmapEntry — это окно, которое позволяет пользователю вводить имя файла цветного растрового изображения, выбирать имя из списка предыстории ранее выбранных имен или просматривать растровые файлы с целью выбора одного из них.
Иерархия
GnomePixmapEntry->GtkVBox->GtkBox->GtkContainer->GtkWidget->GtkObject
Функции
char *gnome_pixmap_entry_get_filename(GnomePixmapEntry *pentry) guint gnome_pixmap_entry_get_type(void)
GtkWidget *gnome_pixmap_entry_gnome_entry(GnomePixmapEntry *pentry) GtkWidget *gnome_pixmap_entry_gnome_file_entry( GnomePixmapEntry *pentry)
GtkWidget *gnome_pixmap_entry_gtk_entry(GnomePixmapEntry *pentry) GtkWidget *gnome_pixmap_entry_new(char *history_id, char *browse_dialog_title, int do_preview) void gnome_pixmap_entry_set_pixmap_subdir( GnomePixmapEntry *pentry, const char *subdir)
void gnome_pixmap_entry_set_preview(GnomePixmapEntry *pentry, int do_preview)
void gnome_pixmap_entry_set_preview_size( GnomePixmapEntry *pentry, int preview_w, int preview_h)
Следующий пример создает окно, изображенное на рис. 22.22. Текущее выбранное цветное растровое изображение отображается в окне виджета. При выборе кнопки Browse всплывает выбранное окно. Поскольку в обращении к функции gnome_pixmap_entry_new() в качестве последнего аргумента указывается TRUE, с правой стороны окна браузера появляется окно предварительного просмотра.
static GtkWidget *makeW%idget() {
GtkWidget *pixmapentry;
GtkWidget *entry;
pixmapentry = gnome_pixmap_entry_new("historyID", "Select a Pixmap"rTRUE); entry = gnome_pixmap_entry_gtk_entry( GNOME_PIXMAP_ENTRY(pixmapentry));
gtk_signal_connect(GTK_OBJECT(entry),"changed", GTK_SIGNAL_FUNC(eventPixmapChanged),pixmapentry);
return(pixmapentry); } void eventPixmapChanged(GtkWidget *widget, GnomePixmapEntry *pixmapentry) { char *filename;
filename = gnome_pixmap_entry_get_filename(pixmapentry); g_print("Selection: %s\n",filename);
}
Внутренний виджет GtkEntry используется для приема имени растрового файла. К нему подсоединяется сигнал "changed", поэтому обратный вызов срабатывает независимо от того, как выполнено изменение: посредством ввода данных, выбора предыстории или при помощи браузера.
Рисунок 22.22. Виджет GnomePixmapEntry, демонстрирующий предварительный просмотр выбора
GnomeProcBar
Виджет GnomeProcBar графически представляет процент выполнения одного или более процессов.
Иерархия
GnomeProcBar->GtkHBox->GtkBox->GtkContainer->GtkWidget~>GtkOb ject
Функции
GtkWidget *gnome_proc_bar_new(GtkWidget *label, gint n, GdkColor *colors, gint (*cb)())
guint gnome_proc_bar_get_type(void)
void gnome_proc_bar_set_orient(GnomeProcBar *pb, gboolean vertical)
void gnome_proc_bar_set_values(GnomeProcBar *pb, unsigned val[])
void gnome_proc_bar_start(GnomeProcBar *pb, gint gtime, gpointer data)
void gnome_proc_bar_stop(GnomeProcBar *pb)
void gnomeprocbarupdate(GnomeProcBar *pb, GdkColor *colors)
Обычно виджет GnomeProcBar используется как строка отражения динамики процесса в виде движущейся цветной строки, которая показывает процент выполнения. GnomeProcBar может делать это, но он также может одновременно показывать динамику нескольких задач. Следующий пример демонстрирует появление расширяющихся слева направо цветных полос, как показано на рис. 22.23. Для определения положения полос все значения суммируются и каждой выделяется пространство в соответствии с ее процентом от общего количества.
static GdkColor barColors[5] = { {О, 0x4fff, OxOfff, Oxffff},
{0, Oxffff, Oxffff, 0x4fff}, {О, Oxdfff, Oxdfff, Oxdfff}, {0, Oxafff, Oxafff, Oxafff}, {0, 0, 0, 0},
static GtkWidget *procbar;
static GtkWidget *makeWidget() {
GtkWidget *label;
label = gtk_label_new("Label Text");
procbar = gnome_proc_bar_new(
label,4,barColors,updateValue);
gtk_widget_set_usize(procbar,400,15);
gnome_proc_bar_start(GNOME_PROC_BAR(procbar),1000,NULL);
return(procbar);
}
static gint updateValue()
{ static gint values[4] = { 0, 0, 0, 0};
values[0]++;
values[l] += 2;
values[2] += 3;
values[3] = 200 - values[0] - values[l] - values[2];
if(values[3] < 0) { values[0] = 0; values[l] = 0; values[2] = 0; values[3] = 200;
}
return(TRUE);return(TRUE);}}gnomeprocbarsetvalues(GNOMEPROC BAR(procbar),values);
return(TRUE);
return(TRUE);
}
}
Рисунок 22.23.
Виджет GnomeProcBar, демонстрирующий движущиеся строки
Для каждого значения имеется уникальный цвет; и цвета, и значения задаются в форме массивов. Массиву объектов GdkColor, передаваемых функции gnome_proc_bar_new(), не будут выделяться ресурсы в карте цветности, так как это делает виджет GnomeProcBar.
Этот виджет генерирует свои собственные обратные вызовы в соответствии с таймером. В этом примере в обращении к функции gnome_proc_bar_start() указывается 1000 миллисекунд. Это означает, что функция updateValue () вызывается каждую секунду. Так как у функции updateValue () нет аргументов и ее предназначение только обновлять дисплей, то сам GnomeProcBar должен быть объявлен как глобальное значение. Этот пример просто прокручивает в цикле несколько значений, а затем возвращается к началу.
GnomePropertyBox
Это всплывающий диалоговый ящик, которое содержит несколько страниц виджетов для установки значений свойств. Страницы размещаются одна над другой (с использованием GtkNotebook) и могут выбираться при помощи кнопки сверху. Кнопки снизу позволяют пользователю обновлять значения свойств и/или закрывать окно.
Иерархия
GnomePropertyBox->GnomeDialog->GtkWindow->GtkBin->GtkContainer~>GtkWidget-> GtkObject
Функции
gint gnome_property_box_append_page(
GnomePropertyBox *property_box, GtkWidget *child, GtkWidget *tab_label) void gnome_property_box_changed(GnomePropertyBox *property_box) guint gnome_property boxgettype(void)
GtkWidget *gnome_property_box_new(void) void gnome_property_box_set_modified( GnomePropertyBox *property_box, gboolean state) void gnome_property_box setstate(
GnomePropertyBox *property_box, gboolean state)
Следующий пример программы создает виджет GnomePropertyBox с двумя страницами радиокнопок. Эти страницы могут содержать любой виджет, который способен удерживать вводимое значение, вроде текстового виджета или кнопки-переключателя. При первом появлении диалогового ящика кнопки ОК и Apply недоступны. Если сделано какое-либо изменение (в нашем случае переключение радиокнопок), кнопки ОК и Apply становятся доступными. Окно, произведенное в этом примере, изображено на рис. 22.24. Щелчок на кнопке Apply вызывает значения со всех страниц для обновления свойств. Щелчок на кнопке Close приводит к немедленному закрытию диалогового ящика независимо от того, сделаны изменения или нет. Щелчок на кнопке ОК приводит к тем же последствиям, что и щелчок на АРР1У.
/** gnomepropertybox.с **/
Iinclude <gnome.h>
static void propertyboxCallback(GtkWidget *widget, gint page,gpointer data);
static GtkWidget *makeRadioButtonBox();
void radioCallback(GtkWidget *widget, GnomePropertyBox *propertybox);
int main(int argc,char *argv[])
{
GtkWidget *propertybox;
GtkWidget *pageWidget;
GtkWidget *label;
gnome_init("gnomepropertybox","1.0",argc,argv);
propertybox = gnome property_box_new();
gtk_window_set_title(GTKWINDOW(propertybox), "GnomePropertyBox");
pageWidget = makeRadioButtonBox("Apples", "Oranges","Peaches",propertybox);
label = gtk_label_new("Radio Buttons");
gnome_property_box_append_page( GNOMEPROPERTYBOX(propertybox), pageWidget,label);
pageWidget = makeRadioButtonBox("Light Blue", "Dark Blue","Black",propertybox);
label = gtk_label_new("More Radio Buttons");
gnome_property_box_append_page( GNOME_PROPERTY_BOX(propertybox), pageWidget,label);
gtk_signal_connect(GTK_OBJECT(propertybox),"apply", propertyboxcallback,NULL);
gtk_widget_show_all(propertybox);
gtk_main();
exit(0);
}
static void propertyboxCallback(GtkWidget *widget, gint page,gpointer data)
{
switch(page) {
case 0:
g_print("Page 0 has changedXn"); break;
case 1:
g_print("Page 1 has changedXn"); break;
default:
g_print("Apply all pagesXn"); break;
}'
}
static GtkWidget *makeRadioButtonBox(
gchar *labell,gchar *label2,gchar *label3, GtkWidget *propertybox)
{
GtkWidget *box;
GSList *group;
GtkWidget *radiobutton;
box = gtk_vbox_new(FALSE,0);
radiobutton = gtk_radio_button_new_with_label(NULL, labell);
gtk_box_pack_start(GTK_BOX(box),radiobutton, FALSE,TRUE,0);
gtksignalconnect(GTK_OBJECT(radiobutton),"toggled", radioCallback,propertybox);
group = gtk_radio_button_group( GTK_RADIO_BUTTON(radiobutton));
radiobutton = gtk_radio_button_new_with_label(group, label2);
gtk_signal_connect(GTK_OBJECT(radiobutton),"toggled", radioCallback,propertybox);
gtk_box_pack_start(GTKBOX(box),radiobutton, FALSE,TRUE,0);
group = gtk_radio_button_group( GTK_RADIO_BUTTON(radiobutton));
radiobutton = gtk_radio_button_new_with_label(group, labels);
gtk_signal_connect(GTK_OBJECT(radiobutton),"toggled", radioCallback,propertybox);
gtkboxpackstart(GTK_BOX(box),radiobutton, FALSE,TRUE,0);
return(box); }
void radioCallback(GtkWidget *widget, GnomePropertyBox *propertybox)
<
Radio Buttons |More Radio Buttons|| v Light Bluev Dark Blue ~ BlackRadio Buttons |More Radio Buttons|| v Light Bluev Dark Blue ~ Blackgnome_property_box_changed(propertybox); }
Radio Buttons |More Radio Buttons|| v Light Blue
v Dark Blue ~ Black
Radio Buttons |More Radio Buttons|| v Light Blue
v Dark Blue ~ Black
Рисунок 22.24.
Виджет GnomePropertyBox c двумя страницами радиокнопок
Help |Help |^ OK|^ Apply | X Close |
Help |
Help |
Ящик свойств создается при вызове функции gnome_property_box_new(). Обращение к функции gnome_property_box_append_page () добавляет новую страницу с меткой, появляющейся как клавиша. Сигнал обратного вызова "apply" подсоединяется к виджету GnomePropertyBox, а функция propertyboxCallback() вызывается всякий раз при изменении одного или нескольких значений, их необходимо сохранить как новые значения свойств.
Функция propertyboxCallback() вызывается всякий раз при щелчке на ОК или Apply. В действительности, она вызывается более одного раза. Первый раз она вызывается с номером каждой меняющейся страницы, а затем повторно — со страницей под номером -1. Например, если изменения произошли на страницах 0 и 3, а страницы 1, 2 и 4 остались неизменными, то обратный вызов работает со страницей под номером 0, затем еще раз со страницей под номером 3, а в конце — под номером -1. В большинстве случаев вам необходимо побеспокоиться о странице под номером -1. Однако бывают обстоятельства, когда для отдельных страниц требуются специальные процедуры, и будет неудобно делать это каждый раз, когда работает функция обратного вызова.
Кнопки ОК и Apply остаются неактивными, пока не произойдут какие-либо изменения на одной из страниц. Это дает возможность приложению сообщать виджету GnomePropertyBox, когда происходит изменение. В этом примере все радиокнопки инициируют выполнение функции обратного вызова radioCallback(), которая, в свою очередь, обращается к функции gnome_property_box_changed (), чтобы зарегистрировать сам факт, что нечто изменилось. И так как виджет GnomePropertyBox знает, какая страница текущая, он записывает эту информацию так, что ее можно передать сигналу обратного вызова "abply".
GnomeScores
Показывает игрокам список имен и счет игры.
Иерархия
GnomeScores->GnomeDialog->GtkWindow~>GtkBin->GtkContainer->GtkWidget-> GtkObject
Функции
void gnome_scores_display(gchar *title, gchar *app_name, gchar *level, int pos)
guint gnome_scores_get_type()
GtkWidget *gnome_scores_new(guint n_scores, gchar **names,
gfloat *scores, time_t *times, guint clear)
void gnome_scores_set_color(GnomeScores *gs, guint n, GdkColor *col)
void gnome_scores_set_colors(GnomeScores *gs, GdkColor *col)
void gnome_scores_set_current_player(GnomeScores *gs, gint i)
void gnome_scores_set_def_color(GnomeScores *gs, GdkColor *col)
void gnome_scores_set_logo_label(GnomeScores *gs, gchar *txt, gchar *font, GdkColor *col)
void gnome_scores_set_logo_label_titie(GnomeScores *gs, gchar *txt) void gnome_scores_set_logo_pixmap(GnomeScores *gs, gchar *pix_name) void gnome_scores_set_logo_widget(GnomeScores *gs, GtkWidget *w)
В следующем примере создается всплывающий диалоговый ящик GnomeScores, отображающий три имени, даты и очки, как показано на рис. 22.25.
/** gnomescores.с **/
Iinclude <gnome.h>
static gchar *names[3] = { "Peter","Laura","Norton" }; static gfloat values[3] = { 93781.0,99751.0,4429.0 };
static time_t times[3);
int main(int argc,char *argv[]) {
GtkWidget *scores;
gnome_init("gnomescores","1.0",argc,argv);
times[0] = time(NULL);
times[l] = times[0] - 100000;
times[2] = times[l] - 100000;
scores = gnomescores_new(3,names,values,times,FALSE);
gtk_widget_show_all(scores);
User PeterUser Peter93781.0099751.004429.0093781.0099751.004429.00LauraNortonLauraNortonDateFri NOV 19 17:01:45 1999Thu NOV 10 13.15:05 1999Wed Nov 17 09'28:25 1999DateFri NOV 19 17:01:45 1999Thu NOV 10 13.15:05 1999Wed Nov 17 09'28:25 1999gtk_main(); exit(0);
User Peter
User Peter
93781.00
99751.00
4429.00
93781.00
99751.00
4429.00
Laura
Norton
Laura
Norton
Date
Fri NOV 19 17:01:45 1999
Thu NOV 10 13.15:05 1999
Wed Nov 17 09'28:25 1999
Date
Fri NOV 19 17:01:45 1999
Thu NOV 10 13.15:05 1999
Wed Nov 17 09'28:25 1999
Рисунок 22.25.
Диалоговый ящик GnomeScores, показывающий верхние три элемента
■ GnomeSpell
Это незавершенный виджет. Когда он будет завершен, то будет использовать программу ispell из Linux для сканирования текста с целью нахождения слов, которых нет в словаре, затем показывает эти слова, возможно, с некоторыми предполагаемыми альтернативами — следовательно, пользователь может корректировать орфографию.
Иерархия
GnomeSpell->GtkVBox->GtkBox->GtkContainer->GtkWidget->GtkObject
Функции
void gdk_child_register(pidt pid, GChildFunc func, gpointer user_data) void gnome_spell_accept(GnomeSpell *spell, gchar *word) gint gnome_spell_check(GnomeSpell *spell, gchar *str) guint gnome_spell_get_type()
void gnome spellinsert(GnomeSpell *spell, gchar *word, gint lowercase) void gnome_spell_kill(GnomeSpell *spell) GtkWidget *gnome_spell_new() int gnome_spell_next(GnomeSpell *spell)
GnomeStock
Виджет используется для создания кнопок, растровых изображений и других объектов, а затем их регистрации при помощи набора предопределенных объектов. Приложение также может использовать этот виджет для добавления новых цветных растровых изображений в ваших собственных целях.
Иерархия
GnomeStock->GnomePixmap->GtkWidget->GtkObject
Функции.
void gnomebutton candefault(GtkButton *button, gboolean can default) GtkWidget *gnome_pixmap_button(GtkWidget *pixmap, const char *text) GtkWidget *gnome_stock_button(const char *type) guint gnomestockgettype(void) gboolean gnomestockmenuaccel(const char *type, guchar *key, guint8 *mod) void gnomestockmenuaccel dig(char *section) void gnome stock_menu_accel_parse(const char *section) GtkWidget *gnome_stock_menu_item(const char *type, const char *text) GtkWidget *gnome_stock_new(void) GtkWidget *gnome_stock_new_with_icon(const char *icon) GtkWidget *gnome_stock_or_ordinary_button(const char *type) gint gnomestockpixmap change(const char *icon, const char *subtype, GnomeStockPixmapEntry *entry)
GnomeStockPixmapEntry *gnome_stock_pixmap_checkfor( const char *icon, const char *subtype) void gnome_stock_pixmap_gdk(const char *icon, const char *subtype, GdkPixmap **pixmap, GdkPixmap **mask) gint gnomestock pixmap register(const char *icon, const char *subtype, GnomeStockPixmapEntry *entry) gboolean gnome_stock_set_icon(GnomeStock *stock, const char *icon) GtkWidget *gnome_stock_transparent_window(const char *icon, const char *subtype)
В следующем примере создаются кнопки и другие виджеты с использованием возможностей виджета GnomeStock. Затем он упаковывает их в вертикальный ящик, как показано на рис. 22.26.
static GtkWidget *makeWidget() {
GtkWidget *box;
GtkWidget *widget;
box = gtk_vbox_new(FALSE, 0);
widget = gnome_stock_button(GNOME_STOCKJPIXMAP_REVERT); gtk_box packstart(GTK_BOX(box),widget,FALSE,FALSE, 0);
widget = gnome_stock_menu_item(GNOME_STOCK_PIXMAP_REVERT, "Menu Revert");
gtk_box_pack_start(GTK_BOX(box),widget,FALSE,FALSE, 0);
widget = gnome_stock_or_ordinary_button("Scores"); gtkboxpackstart(GTK_BOX(box),widget,FALSE,FALSE,0);
widget = gnomestock_or_ordinary_button("High Scores"); gtkboxpackstart(GTKBOX(box),widget,FALSE,FALSE,0);
widget = gnome_stock_new_with_icon(
GNOME_STOCK_PIXMAP_OPEN);
gtkboxpackstart(GTK_BOX(box),widget,FALSE,FALSE,0);
return(box);
}
^ Revert I ^ Menu Revert^Scores | High Scores |^ Revert I ^ Menu Revert^Scores | High Scores |Вызовы функций не требуют создания вашей собственной версии виджета GnomeStock, так как он создается внутри. В действительности, единственная причина, по которой может потребоваться создание в вашем приложении виджета GnomeStock, — это желание добавить дополнения к списку допустимого набора виджетов.
^ Revert I ^ Menu Revert
^Scores | High Scores |
^ Revert I ^ Menu Revert
^Scores | High Scores |
Рисунок 22.26.Набор виджетов, создаваемый виджетомGnomeStockРисунок 22.26.Набор виджетов, создаваемый виджетомGnomeStockПервый созданный виджет — это кнопка, содержащая текст и цветное растровое изображение. Виджет GnomeStock выполняет работу по созданию двух цветных растровых изображений: для обычного появления кнопки и для ее показа после выбора мышью. Это приводит к использованию различных цветов фона и к изменению цветов рамки для того, чтобы кнопка перемещалась (выходила) на передний план или делала отступ.
Рисунок 22.26.
Набор виджетов, создаваемый виджетом
GnomeStock
Рисунок 22.26.
Набор виджетов, создаваемый виджетом
GnomeStock
Наименования наборов цветных растровых изображений — это строки. Например, имя GNOME_STOCK_PIXMAP_REVERT задается как ’’Revert”. Обращение к функции gnome_stock_or_ordinary_button () co ’’Scores" — это то же самое, как если бы аргументом был GNOME_STOCK_PIXMAP_SCORES, и создает кнопку с поименованным цветным растровым изображением и строкой. Однако в результате вызова той же функции с аргументом "High Scores" возникает только текст.
Последний элемент в ящике — сам виджет GnomeStock. Он может отображаться таким же образом, так как это виджет, а его только выводимое содержимое — это цветной растр.
GnomeStockPixmapWidget
Это вспомогательный виджет, который используется для операций с виджетом GnomeStock.
Иерархия
GnomeStockPixmapWidget->GtkVBox->GtkBox->GtkContainer->GtkWidget->GtkObject
Функции
GtkWidget *gnome_stock_pixmap_widget(GtkWidget *window, const char *icon) GtkWidget *gnome_stock_pixmap_widget_at_size(
GtkWidget *window, const char *icon, guint width, guint height) guint gnome_stock_pixmap_widget_get_type(void) GtkWidget *gnome_stock_pixmap_widget_new(GtkWidget *window, const char *icon) void gnome_stock_pixmap_widget_set_icon(GnomeStock *widget, const char *icon)
Рисунок 22.27. Изображение набора цветных растров в GNOMEРисунок 22.27. Изображение набора цветных растров в GNOMEВиджет GnomeStockPixmapWidget может быть использован вашим приложением для демонстрации любого из набора цветных растровых изображений. Следующий пример показывает окно, изображенное на рис. 22.27 и содержащее набор цветных растров по имени GNOME__STOCK_PIXMAP_REVERT.
Рисунок 22.27. Изображение набора цветных растров в GNOME
Рисунок 22.27. Изображение набора цветных растров в GNOME
static GtkWidget *makeWidget()
<
GtkWidget *widget;
widget = gnome_stock_pixmap_widget_new(NULL, GNOME_STOCK_PIXMAP_REVERT);
return(widget); }
Выводы
В этой главе приведен список всех виджетов Gnome в алфавитном порядке и ряда других объектов Gnome, которые можно использовать для построения приложения. Каждый класс перечисляется вместе с:
Сигналами, перечислимыми типами и функциями, определенными для объекта
Иерархией каждого объекта, чтобы вы могли отследить все сигналы и функции, задаваемые для указанного виджета
z Примерами демонстрируемых виджетов и виджетов-контейнеров, а также ссылками на другие главы книги, в которых приведены примеры использования этих виджетов.
Даже Gnome-приложению приходится использовать некоторые особенности операционной системы. В следующей главе будут рассмотрены некоторые из наиболее необходимых особенностей, которые встроены в Linux.
главаНекоторые механизмы
23Linux
■ ■ ■В этой главе
# Расшифровка состояния и кодов ошибок в Linux
О Порождение из некоторого процесса новых процессов
е Выполнение командной строкой из процесса
Связь при помощи конвейеров
Работа с текущими системными датой и временем
Обработка файлов
Большая часть работы при написании приложений делается путем управления окнами и данными, которые окна отображают и принимают. Эта глава не об окнах и интерфейсах GUI: в ней, скорее, описываются некоторые из вызовов функций, обеспечивающих доступ к операционной системе и к некоторым специальным возможностям. Здесь немного говорится о стандартной библиотеке языка С. Так как С был создан для среды Unix, то некоторые стандартные элементы библиотеки С произошли от системных вызовов Unix.
Функции, описанные в этой главе, представляют лишь небольшой процент от всех используемых функций. Здесь в основном описаны наиболее используемые программистами и апробированные временем функции. Пояснения к функциям в этой главе довольно краткие, но основная цель, которая здесь преследуется, — дать программисту понять, какие вообще существуют функции и как с ними работать. Для более детальной информации по каждой из них смотрите страницы руководства man pages.
Коды ошибок в Linux
Всякий раз, когда системный вызов приводит к ошибке, ее номер сохраняется в глобальной переменной errno. Каждый системный вызов может модифицировать это значение; если необходим именно номер, то его надо прочитать сразу же после ошибки. Существуют три вещи, которые вы можете сделать. Самая простая из них — это зарегистрировать или вывести номер, хотя некоторые функции транслируют его в строку описания.
/* error.с ♦/\
Iinclude <sys/types.h>\
♦include <sys/stat.h>\
♦include <stdio.h>
♦include <fcntl.h>
♦include <errno.h>
int main(int argc,char *argv[])
{
int fd;
char *filename = "/invalid/path/name";
fd = creat(filename,SIRWXU | S_IRWXG);
if(fd < 0) {
fprintf(stderr,"Error code: %d\n",errno);
perror("Unable to create file");
fprintf(stderr,"Unable to create %s: %s\n", filename,strerror(errno));
}
}
При обращении к функции creat () была сделана попытка создания нового файла (пользователю и группе гарантируются все полномочия), но попытка не удается, так как неправильно указан путь (маршрут). Код ошибки выводится в стандартный файл ошибок тремя различными способами:
Error code: 2
Unable to create file: No such file or directory
Unable tox create /invalid/path/name: No such file or directory
Функция fprintf () комбинирует строку, которую вы предлагаете, с текущим значением errno для создания описания ошибки. Затем она записывает строку в stderr. Функция strerror() просто транслирует код ошибки в строку. Функция реггог() ’’стремится” к упрощению, а функция strerror () обеспечивает максимальную гибкость.
Порождение процессов
Способ, которым в Linux один процесс порождается из другого, представляет из себя двухшаговую процедуру, получившую название разветвление и выполнение (fork and exec).
Первым шагом вашей программы является разветвление для создания собственного дубликата. Обращение к функции fork() создает две отдельные копии одной и той же рабочей программы, каждая со своим уникальным идентификатором процесса. Так как исполняемый код может совместно использоваться несколькими программами, разветвление дает результат только в одной единственной копии, если она сохраняется в памяти. Специфические для каждого процесса элементы, такие, как данные, текущее местоположение программы, точные регистрируемые значения CPU (ЦП), а также стек, дублируются. Разветвление процесса — это фундаментальная методика операционной системы Linux, которая даже в сложной процедуре выполняется очень быстро. Как только происходит разветвление процесса, оригинал вызывается родительским (parent) процессом, а новая копия — дочерним (child?) процессом.
Второй шаг предназначен для дочернего процесса: замещение самого себя новым процессом, то есть йрвая программа загружается с диска и запускается как дочерний процесс. Вы можете достичь этого путем вызова одной из функций семейства ехес(). Все функции семейства\ехес () выполняют одну и ту же роль, единственное различие за-
ключается в организации аргументов, передаваемых новой программе через командную строку.
В следующей программе происходит разветвление, затем дочерний процесс, полученный при разветвлении, выполняет новую программу:
/* forkexec.c */
linclude <unistd.h> 3
int main(int argc,char *argv[J)
{
intpid;
intchildpid;
intstatus;
9
- if((pid = fork()) == 0) {
printf("Child: pid=%d parentpid=%d\n",
getpid(),getppid());
execlp("showargs","first","second","third",NULL);
printf("Child: This should never printXn");
}
printf("Parent: pid=%d childpid=%d\n",
getpid(),pid);
childpid = wait(&status);
printf("Parent: child %d diedXn",childpid);.
exit(0);
}
Разветвление происходит при обращении к fork() в строке 10. Во время выполнения функции работающая программа разветвляется на две, поэтому, в действительности, от этой функции происходит два возврата: один для родительского процесса и один для дочернего. Возвращенный идентификатор процесса используется для установления того, какой процесс является дочерним, а какой — родительским; родительскому процессу возвращается идентификатор дочернего процесса, а дочернему — нулевой идентификатор процесса. Это означает, что операторы в строках с И по 14 выполняются только дочерним процессом. Так как при обращении к execlp() в строке 13 никогда не выполняется возврат, только родительский процесс выполняет строки с 1/6 по 20.
В строке 11 дочерний процесс выводит собственный идентификатор, а также идентификатор своего родительского процесса. Ни один из этих идентификаторов не возвращается из обращения к функции fork(), поэтому для их получения необходимо вызвать getpid() и getppid().
В строке 13 выполняется вызов execlp(), чтобы запустить новый процесс, который занимает место текущего (дочернего процесса) и принимает тот же самый идентификатор процесса. Эта программа немедленно прекращает работу и стартует новая программа. Если выполняет возврат функция execlp (), то она завершилась аварийно. Первый аргумент execlp () — это имя программы для запуска. Другие аргументы — это элементы, которые вы могли бы включить в командную строку дочерней программы. Существует несколько версий функции ехес () с различными способами передачи аргументов, а детально с этим можно ознакомиться, набрав команду man exec.
В строке 16 родительский процесс выводит свой собственный идентификатор, а также идентификатор нового дочернего процесса. Обращение к функции getpid () позволяет родительскому процессу получить свой собственный идентификатор, но идентификатор дочернего процесса возвращается функцией fork().
В строке 18 вызывается функция wait(). Эта функция блокируется и не выполняет возврата до тех пор, пока "не умрет" дочерний процесс. Если отсутствуют дочерние процессы, то немедленно выполняется возврат. Если имеется несколько дочерних процессов, то для каждого из них вам следует вызвать функцию wait (). Существует несколько способов, позволяющих дождаться завершения дочерних процессов, но в любом случае вы узнаете об этом из функции wait(). Дело в том, что каждый процесс продолжает существовать, пока он не сообщит о своем состоянии родительскому процессу. Если вы оказались в ситуации, когда порождено множество дочерних процессов, то требуется установка некоторых процедур, при помощи которых вы можете проверить, какие дочерние процессы завершились. Для ожидания и возврата различных значений всего разработано четыре функции, их можно увидеть, введя команды man wait и man wait3. Значение статуса, возвращаемое этими функциями, содержит код возврата от программы вместе с некоторыми флагами, объясняющими, как "умер" процесс.
Следующая программа порождена разветвлением и выполнением:
/* showargs */
int main(int argc,char *argv[])
< int i;
for(i=0; i<argc; i++)
printf(" %d %s\n",i,argv[i]);
return(66);
}'
Цель этой программы — отображение каждого аргумента, найденного в командной строке. Ее вывод может выглядеть следующим образом:
Parent: pid=23018 childpid=23019
Child: pid=23019 parentpid=23018
0 first
second
third I
Parent: child 230,19 died
После этого немедленно следует разветвление, родительский процесс выводит свой идентификатор и идентификатор дочернего процесса, а затем вызовы wait() обнаруживают прекращенные дочерние процессы. Дочерний процесс одновременно показывает свою информацию и разветвляется на другой процесс, который также отображает несколько строк. Приведенный порядок операторов может разниться, так как два процесса асинхронны: например, если дочерний процесс быстрее родительского, обе строки родительского процесса могут появиться снизу.
ПРИМЕЧАНИЕ
Первый аргумент, переданный showargs, не является, как вы могли бы ожидать, именем программы. Это первая строка аргументов, которую вы передали функции execlp(). Для исправления ситуации вы можете передать имя программы или использовать одну из других функций ехес().
Выполнение командной строки
Используя функцию system(), можно вводить тот же вид команд, который вы вводите в командной строке, изнутри программы. Следующий пример демонстрирует ряд вещей, которые вы можете делать:
/* system.с */
Iinclude <unistd.h>
int main(int argc,char *argv[J) {
int pidl;
int pid2;
pidl = system("grep print *.c\nH);
pid2 = system("grep include *.c >inclist &\n");
wait(pid2);
exit(0);
}
Функция system () осуществляет ветвление и выполнение для получения командного процессора, или оболочки, которая запускает команду. Первый вызов инструктирует grep работать в приоритетном режиме (на переднем плане) и направляет результаты, как обычно, на стандартный вывод. Второе обращение к system() перенаправляет вывод и, благодаря амперсанду, запускает команду как дочерний процесс. Вызов system() ожидает, пока выполнится команда, в противном случае запускает ее как дочерний процесс.
Возвращаемое значение -1 указывает, что в переданной команде обнаружена ошибка. Возвращаемое значение 127 указывает, что оболочка из командной строки не может быть запущена. Если нет ошибок и команда не работает в фоновом режиме, то возвращается результат выполнения команды. Однако если программа запускается в фоновом режиме, как вторая функция system() в этом примере,\о возвращается идентификатор дочернего процесса и вам нужно вызвать функцию wait(), как при разветвлении и выполнении.'
Ьрймечаниг .
Можно кое-что добавить о возвращаемом от функции system() значении. Она возвращает код ошибки, равный 127. Но и возвращаемое от команды значение также может быть равно 127. Если это создает проблемы, то используйте разветвление и выполнение.
Конвейеры
Конвейер (pipe), или канал, — это односторонняя связь между двумя процессами. Функция рореп() порождает дочерний процесс и создает присоединенный к нему конвейер. В зависимости от направления конвейера дочерний процесс может или считывать с конвейера, фактически считывая при этом свой собственный стандартный ввод, или записывать на него путем выполнения записи на свой собственный стандартный вывод. Например, команда 1s выполняет запись на ее стандартный вывод. Следовательно, можно создать конвейер, чтобы вы могли "поймать” вывод команды 1s внутри вашей программы.
/* pipein.с */
tinclude <stdio.h>
int main(int argc,char *argv[])
<
FILE *pd;
char instring[100];
if((pd = popen("ls\n","r")) == NULL) {
perror("Cannot open pipe");
exit(1);
}
while(fgets(instring,sizeof(instring),pd) 1= NULL) { printf("%s",instring);
}
pclose(pd);
exit(0);,
}
Функция popen () требует командную строку и спецификацию, указывающую, для чего предназначен конвейер — для чтения или записи. Следует выбрать одну из опций — ”г” или ”w”, так как конвейеры односторонние.
Значение, возвращаемое функцией popen() — это структура FILE, представляющая поток; его можно использовать, как если бы открыли при помощи функции fopen(). Любую функцию, которую вы можете использовать для чтения файла, можно применять для считывания прямо с конвейера. Единственная разница — когда закрывается конвейер, то надо использовать функцию pclose() вместо f close ().
В предыдущем примере показано, как можно считывать и демонстрировать имена файлов, найденные с помощью команды 1s. Заметьте, что здесь отсутствует символ newline (новой строки), который требуется оператору printf (). Это происходит потому, что f gets () работает с конвейером так же, как и с файлом, и включает newline в каждую входящую строку.
Следующий прийерпоказывает контейнер, который открывается в противоположном направлении. Команда cat, стартующая без аргументов, считывает стандартный ввод и записывает на стандартный вывод. Эта программа открывает конвейер, по которому команде cat пересылаются символы так же, как если бы вы набирали их на терминале:
/* pipeout.c */
♦include <stdio.h>
int main(int argc,char *argv[])
{
FILE *pd;
char instring[100];
if((pd = popen("cat\n","w")) == NULL) {
perror("Cannot open pipe");
exit(1);
}
fputs("The first string to cat\n",pd);
fflush(pd);
sleep(5);
fputs("The second string to cat\n",pd);
fflush(pd);
pclose(pd);
exit(0);
i
Так как конвейер открывается в режиме "w”, то эта программа позволяет в него записывать. Обращение к функции f puts () посылает строки команде cat, которая записывает их на стандартный вывод, так они возникают на экране. Необходимость в обращении к функции fflush() существует потому, что буфера конвейеров полностью заполняются и реальные выходные данные отсылаются только тогда, когда заполняется буфер или закрывается конвейер. Буферизация конвейерных данных не имеет ограничений по размерам, так как данные в этом случае сохраняются на диске, поэтому поблочная запись никогда не используется для конвейера. Это означает, что можно поставить в очередь все команды и данные, какие хотите, и дочерний процесс будет считывать их в его собственном темпе.
Время
Linux хранит время как счетчик количества секунд, прошедших с полуночи 1 января 1970 года. В следующем примере восстанавливается и отображается текущее время:
/* showtime.с */
♦include ctime.h>
♦include <limits.h>
int main(int argc,char *argv[])
{
time_t binarytime; struct tm *nowtm;
binarytime = time(NULL);
printf("now=%d\n",binarytime);
printf("ctime=%s",ctime(&binarytime));
nowtm = localtime(&biriarytime);
printf("asctime=%s",asctime(nowtm));
printf("\n");\
printf(" HHMMSS %d:<02d:%02d\n", nowtm->tm_hour,nowtm->tm_min,nowtm->tm_sec);
printf(" MMDDYY %d/%d/%d\n",
nowtm->tm_mon + 1,nowtm->tm_mday, nowtm->tm_year + 1900);
printf(" Weekday=%d\n", nowtm->tm_wday);
printf(" Yearday=%d\n", nowtm->tm_yday); printf(" Daylight time=%d\n", nowtm->tm_isdst);
printf(" Offset from GMT=%d\n", nowtm->tm_gmtoff / 3600);
printf(* Time zone=%s\n", nowtm->tm_zone);
printf("\n");
binarytime = INT_MIN;
printf("minimum=% s",ctime(&binarytime));
binarytime = INT_MAX;
printf("maximum=%s",ctime(fcbinarytime));
Обращение к функции time () возвращает 32-битное целое число, представляющее текущее время. Это довольно удобная форма представления, так как время можно легко исправлять путем сложения и вычитания, а для его хранения всего лишь требуется четыре байт. Вызов ctime() конвертирует время в строку, которая всегда имеет длину 25 символов: 24 видимых символа и символ newline в конце.
Другим форматом хранения времени является структура tm. В этом примере обращение к функции localtime () переводит двоичное время в структуру tm. Эта структура имеет одно поле для каждого куска информации:
struct tm {
int tm_sec;
/* Seconds [0-60] (1 leap second) */
int tm_min; int tm_hour int tm_mday; int tm_mon; int tm_year; int tm_wday;
/* Minutes [0-59] */
/* Hours [0-23] */
/♦ Day [1-31] */
/* Month [0-11] */
/* Year - 1900. */
/* Day of week [0-6] */
int tm_yday;
/* Days in year.[0-365] */
int tm_isdst;
/♦ Daylight time [-1/0/1]*/
long int tm_gmtoff; /* Seconds east of UTC. */ const char *tm_zone; /* Timezone abbreviation. */
};
Месяцы года пронумерованы от 0 до 11, где январь — месяц 0. Год сохраняется после вычитания значения 1900 из реального значения года (это осталось от ранней версии структуры tm, в которой каждое поле имело размер один байт). Дни недели пронумерованы, начиная с воскресенья как 0, понедельника как 1 и т.д. Индикатор daylight (перевод в летний период часовой стрелки на час вперед) принимает значение 1, если установлен, значение 0, если не установлен, и -1, если не может быть определен. Отклонение от UTC (Universal Time Coordinate — универсальное скоординированное время) или GMT (Greenwich Mean Time — время по Гринвичу) измеряется в секундах, так как есть районы, в которых локальное время корректируется значением меньшим, чем один час. Часовая зона указывается как строка формата ASCII.
Далее приведен образец вывода вышеуказанной программы:
now=942345478
ctime=Thu Nov 11 09:37:58 1999
asctime=Thu Nov 11 09:37:58 1999
HHMMSS 9:37:58
MMDDYY 11/11/1999
Weekday=4
Yearday=314
Daylight time=0
Offset from GMT=-9 Time zone=AKST
minimum=Fri Dec 13 10:45:52 1901
maximum=Mon Jan 18 18:14:07 2038
Последние две строки показывают экстремальные значения, которые может представить 32-битное число. Как видно из этого примера, год 2038 создаст серьезные проблемы.
Есть вызов функции, который не только возвращает количество секунд с 1 января 1970 года, но и количество микросекунд, которые переданы во время текущей секунды. Это очень полезно при проставлении отметок времени, потому что почти невозможно возвратить дважды одно и то же значение — промежуток времени, требуемый функцией, достаточен для изменения значения. Значения возвращаются как два члена структуры, что показано ниже:
/* microtime.с */
Iinclude <sys/time.h>
Iinclude <unistd.h>
int main(int argc,char *argv[])
{ struct timeval tv;
gettimeofday(&tv,NULL);
printf(”Seconds: %d\n",tv.tv_sec);
printf(-Microseconds: %d\n",tv.tv_usec);
}
Функция gettimeof day () вставляет текущее время в структуру timeval. Второй аргумент функции gettimeof day () — это всегда NULL (образец оригинальной версии). Обращение к gettimeof day () возвращает тот же счетчик секунд, что и при обращении к функции time(), но в то же время ведется счетчик микросекунд. Вывод выглядит следующим образом:
Seconds: 942369385
Microseconds: 127905
Количество микросекунд показывает, что время продвинулось на 12,7 процента промежутка (временного интервала) до следующей секунды.
Если только вы не используете специальную версию Linux для работы в режиме реального времени, количество микросекунд требуется лишь для сравнения. При использовании структуры timeval для присоединения временной метки к каким-либо объектам быстрое сравнение всегда укажет, какой из них возник первым (или, по крайней мере, первым получил временную метку). Для сравнения двух структур имеется макрос:
if(timercmp(tvl,tv2,<)) {
printf(“tvl is less than tv2\n");
else
printf(Mtvl is not less than tv2\n“);
if(timercmp(tvl,tv2,>)) {
printf(”tvl is greater than tv2\n");
else
printf(Mtvl is not greater than tv2\n");
Третий аргумент выглядит несколько необычно, но это макрос, и оператор сравнения просто замещается расширенным выражением.
Информация о файлах
Можно не только получать список имен файлов и каталогов, но и полную информацию о них. В следующей программе выводится список имен всех файлов и подкаталогов каталога, а также печатается некоторая информация о них.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575812345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
/* showdir.с */
♦include <sys/types.h>
♦include <sys/stat.h>
♦include <errno.h>
♦include <unistd.h>
♦include <dirent.h>
♦include <stdio.h>
int main(int argc,char *argv[J) <
DIR *dir;
struct dirent *dent;
struct stat st;
char *directory_name = ".";
char file_name[120];
if(argc > 1) directory_name * argv[l];
if((dir = opendir(directory_name)) == NULL) { perror("Cannot open directory-);
exit(1);
}
while(dent = readdir(dir)) { printf("%s\n",dent->d_name);
sprintf(file_namef"%s/%s"f directory_name,dent->d_name);
if(stat(file_name,&st) < 0) { perror("Cannot get file status"); errno = 0;
continue; } printf("A");
if(S_ISLNK(st.st_mode)) printf(" symbolic link");
if(SISREG(st.st mode)) printf(" regular file");
if(S_ISDIR(st.st_mode)) printf(" directory");
i f(SISCHR(st.s tjnode)) printf(" character device");
if(S_ISBLK(st.st_mode)) printf(" block device");
if(S_ISFIFO(st.stmode))printf(" fifo");
if(SISSOCK(st.st mode)) printf(" socket");
printf("\n");
printf(" Owner group: %d user: %d\n", st.st_gid,st.st_uid);
printf(" File size in bytes: %d\n"fst.st_size);
printf(" Accessed; %s"fctime(&st.st_atime));
printf(" Modified; %s",ctime(&st.st_mtime)); errno = 0;
}
if(errno 1= 0) perror("Cannot read directory entry");
closedir(dir);
59 exit(0);
60 }
Когда-то каталогом назывался обычный файл на диске, который содержал список имен файлов и расположение их на диске. Вы можете открывать и считывать каталог, как и любой другой файл. В целях оперативности и поскольку существует много разных файловых систем, разработчики создали специальные функции для открытия, чтения и закрытия каталога.
Каталог открывается в строке 20 путем вызова opendir (). Тип данных DIR возвращается, чтобы поддержать операции с каталогами. В начале цикла в строке 24 вызывается readdir (), чтобы считывать каждый член каталога (первые два члена всегда "." и ”..”). После того как вся информация о файле считана и выведена, функция closedir () в строке 58 закрывает каталог.
Для вывода информации о файле внутри цикла в строке 28 вызывается функция stat (). Возвращенная информация сохраняется в структуре stat из строки 13. В строках с 33 по 53 форматируются и отображаются данные.
showdir
A regular file
Owner group: 39 user: 500
File size in bytes: 8793
Accessed: Fri Nov 12 11:54:45 1999
Modified; Fri Nov 12 11:52:26 1999
За именем файла следует некоторая описательная информация. Это вовсе не означает, что в структуре stat приведена вся доступная информация. Чтобы получить дополнительную информацию и другие способы вызова этой функции, введите:
man 2\stat
В строках с 30 по 54 errno получает нулевое значение. Это происходит потому, что readdiv() не меняет значения errno, если только не возникнет реальная ошибочная ситуация, и поэтому в ней может оставаться старый код ошибки. А поскольку readdir () возвращает NULL и в случае ошибки, и по концу файла, необходимо убедиться, что errno установлена в нулевое значение: это был бы единственный правильный способ обнаружения конца файла.
Системная информация
Следующая программа выделяет и показывает информацию о системе. Если вашей программе требуется информация об ее окружении, то, несомненно, существует функция, которую можно вызвать для получения этой информации.
/* systeminfo.с ♦/ linclude <stdio.h> linclude <stdlib.h> linclude <unistd.h> linclude <sys/utsname.h> linclude <sys/time.h> linclude <sys/resource.h> linclude <linux/kernel.h>
int main(int argc,char *argv[])
struct utsname uts;
char cwd[120J;
char *env;
struct rlimit rlim;
struct sysinfo s_info;
System name: %s\n", Release: %s\n", Version: %s\nH, Hardware: %s\nM, Node name: %s\n",Domain name: %s\n",Domain name: %s\n",System name: %s\n", Release: %s\n", Version: %s\nH, Hardware: %s\nM, Node name: %s\n",Domain name: %s\n",Domain name: %s\n",uts.sysname); uts.release); uts.version); uts.machine);uts.nodename);uts.domainname);uts.domainname);uts.sysname); uts.release); uts.version); uts.machine);uts.nodename);uts.domainname);uts.domainname);if(uname(&uts) >= 0){ printf(" printf(" printf("
System name: %s\n", Release: %s\n", Version: %s\nH, Hardware: %s\nM, Node name: %s\n",
Domain name: %s\n",
Domain name: %s\n",
System name: %s\n", Release: %s\n", Version: %s\nH, Hardware: %s\nM, Node name: %s\n",
Domain name: %s\n",
Domain name: %s\n",
uts.sysname); uts.release); uts.version); uts.machine);
uts.nodename);
uts.domainname);
uts.domainname);
uts.sysname); uts.release); uts.version); uts.machine);
uts.nodename);
uts.domainname);
uts.domainname);
printf(" printf("
#ifdef USE_GNU
printf(" felse
printf(" fendif
}
Current directory: %s\n", cwd);Current directory: %s\n", cwd);printf("printf("if(getcwd(cwd,sizeof(cwd)))
Current directory: %s\n", cwd);
Current directory: %s\n", cwd);
printf("
printf("
if((env = getenv("SHELL")) != NULL) printf(4 Environment variable SHELL: %s\n", env);
printf(”UserID:%d\n",getuid());
printf("GroupID;%d\n",getgid());
printf("ProcessID:%d\n",getpid());
printf("Parent process ID: %d\n", getppid());
printf("Login: %s\n", getlogin());
printf("User shell: %s\n", getusershell());
printf(" Maximum arg length for exec(): %ld\n", sysconf(_SC_ARG_MAX));
printf(" Maximum processes per user: %ld\n",
sysconf(_SC_CHILD_MAX));
printf("Clock ticks per second: %ld\n",
sysconf(SCCLKTCK));
printf(" Maximum streams per process: %ld\n", sysconf (_SC_STREAM_MAX));
printf("Maximum open files per process: %ld\n", sysconf(_SC_OPEN_MAX));
printf("Maximum chars in timezone name: %ld\n", sysconf(_SC_TZNAME_MAX));
printf(" Maximum command line length: %ld\n", sysconf(_SC_LINE_MAX));
printf(" POSIX job control supported: %s\n", sysconf(_SC_CHILD_MAX) ? "true" : "false");
printf(" POSIX.1 compliance (YYYYMM): %ld\n", sysconf(SCVERSION));
printf(" POSIX.2 compliance (YYYYMM): %ld\n", sysconf(_SC_2_VERSION));
printf(" POSIX.2 locale by localdef: %s\n",
sysconf(_SC_2_LOCALEDEF) ? "true" : "false"); printf(" POSIX.2 software development: %s\n", sysconf(_SC_2_SW_DEV) ? "true" : "false");
sysinfo(&s_info);
printf("Uptime in seconds: %d\n", s_info.uptime);
printf("Load for past 1 minute: %d\n", s_info.loads[0]);
printf(*
Load for past 5 minutes: %d\n", s_info.loads[1]);
printf("
Load for past 15 minutes: %d\n", s_info.loads[2]);
printf("
Total amount of RAM: %d\n", s_infо.totalram);
printf(и
Amount of free RAM: %d\n”, sinfо.freeram);
printf("
Amount of shared RAM: %d\n”, s_info.sharedram)
printf(и
Amount of RAM in buffers: %d\n”, s_info.bufferram)
printf(*
Total swap space: %d\n”, sinfo.totalswap)
printf("
Free swap space; %d\n", s_infо.freeswap);
printf("
Total number of processes; %d\n", s_infо.procs);
exit(0);
Эта программа сама себя комментирует: для возврата значений выполняются системные вызовы, а сами значения отображаются. Далее следует образец вывода, осуществленный этой программой:
System name: Linux Release: 2.0.36 Version: 11 Tue Oct 13 22:17:11 EDT 1998 \ Hardware: i586 \ Node name: arlin.athome.com Domain name:
Current directory: /home/stuff/book/gn/23/code Environment variable SHELL: /bin/bash User ID: 0 Group ID; 0 Process ID: 18859 Parent process ID: 17091 Login: root User shell: /bin/bash Maximum arg length for exec(); 131072 Maximum processes per user: 999 Clock ticks per second: 100 Maximum streams per process: 256 Maximum open files per process: 256 Maximum chars in timezone name: 4 Maximum command line length: 2048 POSIX job control supported: true POSIX.l compliance (YYYYMM): 199309 POSIX.2 compliance (YYYYMM): 199912 POSIX.2 locale by localdef; true POSIX.2 software development: true Uptime in seconds: 618899 Load for past 1 minute: 178656 Load for past 5 minutes: 146560 Load for past 15 minutes: 139680 Total amount of RAM: 64655360 Amount of free RAM: 1880064 Amount of shared RAM: 23175168 Amount of RAM in buffers: 23179264 Total swap space: 98664448 Free swap space: 59662336 Total number of processes: 77
Эта программа не демонстрирует всех возможностей получения системной информации. Если не найдете в этом примере того, что ищете, можно использовать утилиту man для получения другой информации о функциях, которые вам необходимы. Например, стра-
ница man для функции getenv (), получающей значение переменной окружения, приводит к функции setenv(), которая может определять переменную окружения, и к функции unsetenv(), удаляющей переменную окружения. Помимо включенных в этот пример имеются также другие системные вызовы. Чтобы получить их список, введите:
man 2 syscalls
Выводы
Эта книга почти полностью посвящена интерфейсу пользователя. В этой главе описаны некоторые технологии, которые может использовать ваша программа для установления интерфейса с операционной системой:
О Все системные вызовы (и некоторые вызовы сервисных функций) используют глобальную переменную errno для сохранения значения кода ошибки. Нулевое значение errno означает, что ошибки нет. Имеются специальные функции для форматирования кодов ошибки в вид, удобный для восприятия.
^ Любой процесс может использовать fork и ехес (разветвление и выполнение) для запуска другого процесса. В действительности, каждый процесс Linux начинается с использования этой технологии. Системный процесс init стартует во время загрузки; в его обязанности входит запуск других процессов. Идентификатор процесса init всегда равен 1.
# Любая команда, которую вы можете набрать с терминала, может быть запущена из программы.
§ Родительский и дочерний процессы могут связываться друг с другом через конвейер, который переадресовывает (перенаправляет) стандартные ввод и вывод.
^ Можно выделить и отобразить значение времени с большей точностью, чем может обеспечить большинство аппаратных средств.
& В дополнение можно открывать каталог и считывать всю информацию о нем, включая все его файлы и подкаталоги.
S Большое семейство системных вызовов может дать вам информацию о текущем пользователе, состоянии компьютера, загрузке CPU и многом другом.
В следующей главе проведено сравнение небольшого приложения, написанного для GNOME, и такого же приложения, написанного для Windows. Приложение предназначено служить в качестве benchmark (эталонного теста) "Rosetta Stone" для программиста в Windows, который хочет начать программировать в GNOME.
2^ваСравнительная анатомия:
ЭДLUin32 и GNOME
-■■ -В этой главе ?
е Написание в GNOME простой программы, рисующей прямоугольники в окне
S Написание в Win32 простой программы, рисующей прямоугольники в окне
® Пошаговое сравнение двух программ
Если вы знакомы с программированием с использованием Win32 API, то эта глава поможет понять структуру приложения GNOME/GTK+. На нижних уровнях две модели программирования очень похожи. Они обе работают, используя основной цикл, ожидающий поступления событий; когда поступило событие, то вызывается функция для уведомления приложения.
Для максимального упрощения сравнения эта глава "работает” с одной и той же коротенькой программой в Win32 и в GNOME/GTK+.
ПРИМЕЧАНИЕ
Сравнение, проводимое в этой главе, не преследует цель установить, какая оконная система лучше, и здесь также не делается попытка использования каких-либо стандартных технологий оптимизации программирования. Эти две программы задуманы таким образом, чтобы быть похожими друг на друга насколько это возможно, поэтому человек, который понимает одну из этих программ, может легко ориентироваться в структуре другой.
Программа в Win32
Следующий пример — это программа в Windows, заполняющая окно концентрическими прямоугольниками. Всякий раз, когда окно меняет размеры, прямоугольники также меняют свой размер, приспосабливаясь к нему. Результат работы этой программы выглядит примерно так, как на рис. 24.1.
/* boxbox.с (Win32) */
Iinclude <windows.h>
3
Idefine STEP 3
5
static char name[] = "BoxBox";
static int xBoxl;
static int yBoxl;
static int xBox2;
static int yBox2;
11
LRESULT CALLBACK callback(HWND,UINT,WPARAM,LPARAM);
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
, 34
I 35
' 36
37
38
39
40
41
42
43
44
int
{
WINAPI WinMain(HINSTANCE instance, HINSTANCE prev,PSTR commandLine,int showCommand)
HWND window;
MSG message;
WNDCLASSEX winclass;
winclass.cbSize = sizeof (winclass);
winclass.style = CSHREDRAW I CSVREDRAW;
winclass.IpfnWndProc = callback;
winclass.cbClsExtra = 0;
winclass.cbWndExtra = 0;
winclass.hlnstance = instance;
winclass.hlcon = Loadicon(NULL,IDI_APPLICATION);
winclass.hCursor = LoadCursor(NULL,IDC_ARROW);
winclass.IpszMenuName = NULL;
winclass.IpszClassName = name;
winclass.hlconSm = Loadlcon(NULL,IDI_APPLICATION) winclass.hbrBackground =
(HBRUSH)GetStockObj ect(WHITE_BRUSH);
RegisterClassEx(&winclass);
window = CreateWindow (name,"Boxes in Boxes" WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,CW_USEDEFAULT, CW_USEDEFAULT,CWUSEDEFAULT, NULL,NULL,instance,NULL);
ShowWindow(window,showCommand);
UpdateWindow (window);
45
TranslateMessage(&message);
46
DispatchMessage(&message);
47
}
48
return(message.wParam);
49 }
50
51 LRESOLT CALLBACK callback(BWND window
52
WPARAM wParam,LPARAM iParam)
53 {
54
int xl;
55
int yl;
56
int x2;
57
int y2;
58
HDC hdc;
while(GetMessage(&message,NULL,0,0)) {
PAINTSTRUCT ps
UINT messageType
59
60
61
62
63
64
65
66
67
68
69
70
switch (messageType) { case WMSIZE;
xBoxl = 10;
yBoxl = 10;
xBox2 = LOWORD(lParam) - 10;
yBox2 = HIWORD(lParam) - 10;
return(0);
case WMPAINT:
hdc = BeginPaint(window,&ps);
SetViewportOrgEx(hdc,0,0,NULL);
71xl=xBoxl;
72х2=хВох2;
73yl=yBoxl;
74у2=уВох2;
75while((xl < х2) && (yl < у2)) {
76MoveToEx(hdc,xl,yl,NULL);
77LineTo(hdc,x2,yl);
78LineTo(hdc,x2,y2);
LineTo(hdc,xl,у2);
LineTo(hdc,xl,yl);
xl+=STEP;
yl+=STEP;
x2-=STEP;
84y2-=STEP;
85}
86EndPaint(window,&ps);
87return(O);
88case WM_DESTROY:
89PostQuitMessage(O);
90return(O);
91}
92return(DefWindowProc(window,messageType,
/ wParam,lParam));
}/
Только две функции встречаются в этой программе. Функция WinMain (), начинающаяся со строки 14, — это оригинальная функция, вызываемая операционной системой для запуска программы. Функция callback() из строки 51 вызывается операционной системой всякий раз, когда возникают события.
Рисунок 24.1.
Главное окно программы в Win32
Программа в GNOME
Следующий пример — это программа в GNOME/GTK+, заполняющая окно концентрическими прямоугольниками. При изменении размеров окна размер прямоугольников также меняется. Окно выглядит, как на рис. 24.2.
/** boxbox.с (Gnome) **/
Iinclude <gnome.h> 3
gint eventDelete(GtkWidget *widget,
GdkEvent *event,gpointer data);
gint eventDestroy(GtkWidget *widget,
GdkEvent *event,gpointer data);
gboolean eventExpose(GtkWidget *widget,
GdkEvent ♦event,gpointer data);
gint eventConfigure(GtkWidget *widget,
GdkEventConfigure *event,gpointer data);
1213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686912131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
♦define STEP 3
static char name[] =* "BoxBox";
static int xBoxl;
static int yBoxl;
static int xBox2;
static int yBox2;
int main(int argc,char *argv[]) {
GtkWidget *app;
GtkWidget *area;
gnome init(name,"1.0",argc,argv);
app = gnome app new(name,"Boxes in Boxes");
gtk_signal_connect(GTK_OBJECT(app),"deleteevent", GTKSIGNALFUNC(eventDelete),NULL);
gtk_signal_connect(GTK_OBJECT(app),"destroy", GTKSIGNALFUNC(eventDestroy),NULL);
area = gtk_drawing_area_new();
gnome app_set_contents(GNOME_APP(app),area);
gtk_signal_connect(GTK_OBJECT(area),"expose_event", GTK_SIGNAL_FUNC(eventExpose),NULL);
gtk_signal_connect(GTK_OBJECT(area),"configureevent",GTK_SIGNAL_FUNC(eventConfigure),NULL);
gtkwidgetshowall(app);
gtk_main();
exit(0);
}
gboolean eventExpose(GtkWidget *widget, GdkEvent *event,gpointer data) {
int xl;
int yl;
int x2;
int y2;
xl = xBoxl;
yl = yBoxl;
x2 = xBox2;
y2 = yBox2;
while((xl < x2) && (yl < y2)) { gdk_draw_line(widget->window, widget->style->black_gc, xl,yl,x2,yl);
gdk_draw_line(widget->window, widget->style->black_gc, x2,yl,x2,y2);
gdk_draw_line(widget->window, widget->style->black_gc, x2,y2,xl,y2);
gdk_draw_line(widget->window, widget->style->black_gc, xl,y2,xl,yl);
xl += STEP;
yl+=STEP;
х2-=STEP;
у2-=STEP;
73}
74return(TRUE);
75 }
76 gint eventConfigure(GtkWidget *widget,
77GdkEventConfigure *event,gpointer data)
78 {
79xBoxl=10;
80yBoxl=10;
81xBox2=event->width- 10;
82yBox2=event->height - 10;
83return(TRUE);
84 }
85 gint eventDelete(GtkWidget *widget,
86GdkEvent *event,gpointer data) {
87return(FALSE);
88 }
89 gint eventDestroy(GtkWidget *widget,
90GdkEvent *event,gpointer data) {
91gtk_main_quit();
92return(O);
93 }
Эта программа содержит функцию main (), которая используется для инициализации GNOME, создает окно, которое будет отображаться, указывает обратные вызовы и переходит в цикл выполнения. Существует четыре других функции, каждая из которых выполняется при наступлении определенного события.
Рисунок 24.2.Главное окно программы в GNOMEРисунок 24.2.Главное окно программы в GNOME
Рисунок 24.2.
Главное окно программы в GNOME
Рисунок 24.2.
Главное окно программы в GNOME
Пошаговое сравнение
Это описание показывает сходство и различие между программами в GNOME и в Win32 путем детализации некоторых особенностей. Как можно видеть, основные различия заключаются в деталях, а не в базовой технологии.
Инициализация
В строке 26 программы для GNOME выполняется обращение к функции gnome_init () для инициализации GUI-интерфейса и других частей базового графического программного обеспечения. Прототип этой функции в Win32 отсутствует, так как Win32 API — это часть операционной системы, которая всегда уже проинициализирова- на. Однако GNOME не является частью операционной системы, поэтому оконное программное обеспечение необходимо инициализировать.
Главное окно
В строке 27 программы для среды GNOME при обращении к функции gnome__app_new() осуществляется создание нового высокоуровневого окна приложения. Вызов этой функции назначает имя программе и добавляет заголовок, который появляется в верхней части окна. Подобное действие в версии для Win32 выполняется при обращении к CreateWindow() в строке 36. В строках с 21 по 35 версии для Win32 задается главное окно, а в строке 35 обращение к RegisterClassEx() регистрирует его в операционной системе. Как вы видите, в программе для Win32 при создании окна верхнего уровня требуется выполнить намного больше предварительных установок, чем в программе для GNOME. Это происходит потому, что в Win32 все установки должны указываться заранее. А в GNOME для всего используется стандартный набор установок по умолчанию и также существуют доступные функции, при помощи которых ваша программа может изменять установки после построения окна.
Реакция на события
Обе программы для GNOME и Win32 управляются прерываниями (событиями). Другими словами, когда обе программы запущены и их окна отображаются на экране дисплея, GNOME и Win32 ожидают, пока произойдет событие (мышь, клавиатура или что- либо еще). Когда происходит событие, вызывается функция для передачи информации от системы к приложению. В строках с 36 по 39 программы для GNOME выполняется обращение к функции gtk_signal_connect (), чтобы сообщить системе, какие функции для каких событий будут вызываться. Этот шаг не обязателен для программы из Win32, потому что функция обратного вызова, перехватывающая все события, назначается в строке 23 окну верхнего уровня.
Обе программы должны реагировать на два события: изменение размеров окна и выход на передний план части или всего окна, в результате чего его можно прорисовать.
В строке 38 программа для GNOME приписывает сигнал "conf igure_event" функции обратного вызова eventConf igure(). Эта функция использует размер окна для подсчета координат внешнего ящика. Такой же эффект достигается с оператором case из строки 62 в функции callback() программы для Win32.
В строке 36 программы для GNOME функции обратного вызова eventExpose() назначается сигнал "expose__event". Эта функция рисует набор вложенных окон, используя значения размера и расположения, которые выделены из самого последнего сконфигурированного события. Программа для Win32 делает то же самое, применяя оператор case в строке 68.
ПРИМЕЧАНИЕ ....... ......... ....... .
Эти два метода обработки событий имеют больше сходств, нежели различий. Приложение GNOME указывает функцию обратного вызова для всех своих событий, а затем сортирует их при помощи операторов case. В программе для Win32 функцию обратного вызова можно использовать как диспетчер, который содержит только вызовы функций для каждого события — поэтому и требуется отдельная функция для каждого события.
Главный цикл
Версия для GNOME в строке 42 вызывает функцию gtk_main(). Эта функция не выполняет возврата, пока не приходит время завершения программы. Задача функции — ожидание событий, а затем вызов соответствующей функции. Функция
gtk_signal_connect () связывает окно, функцию обратного вызова и соответствующее событие. Это означает, что в цикле функция gtk_main() имеет полномочия решать вопрос о том, какое окно является источником события.
Главный цикл программы для Win32 располагается в строках с 44 по 47. Функция GetMessage() ожидает получения события, а затем производит возврат. Вызов функции TranslateMessage ( ) переводит коды клавиатуры в символы, а функция DispatchMessage() передает событие надлежащему окну.
Закрытие программы
Когда закрывается программа для Win32, то вызывается функция обратного вызова с сообщением WM_DESTROY. В строке 89 выполняется обращение к функции PostQuitMessage(). Этот вызов размещает сообщение quit во входной очереди, и, когда оно считывается, программа завершается. Это дает вам возможность выполнять очистку перед закрытием или (в случае ошибки при отправке сообщения quit) отказаться от закрытия.
В строках с 28 по 31 приложения GNOME указываются две функции как функции обратного вызова для закрытия программы. Сигнал ”delete_event" инициирует вызов функции eventDelete () непосредственно перед закрытием программы. Если от этой функции возвращается FALSE, то процесс закрытия может продолжаться, возникает событие ’’destroy”, вызывающее функцию обратного вызова eventDestroy(). Эта функция, в свою очередь, вызывает функцию gtk_main_quit () для закрытия программы. Если от функции eventDelete () возвращается TRUE, то закрытия не происходит.
ПРИМЕЧАНИЕ
В GNOME эти функции обратного вызова очень важны. Без них приложение не может быть остановлено с помощью кнопки с правой стороны строки заголовка или меню слева.
Глобальные данные
Оба этих примера используют декларируемые глобально данные для сохранения информации из одного обратного вызова в другой. В них обоих также приводятся альтернативы этому, но различными способами.
В программе для Win32 можно просто объявлять данные как статические внутри функции обратного вызова. Таким образом, каждая функция обратного вызова имеет доступ к данным. Даже если вы вызвали другие функции для выполнения актуальной работы, то необходимые данные могут быть переданы как аргументы.
В GNOME применяется другой подход. Обратите внимание на последний аргумент — всегда NULL в этом примере — в обращениях к функции gtk_signal_connect(). Можно использовать этот аргумент, чтобы передать функции обратного вызова указатель. Другими словами, каждый раз, когда выполняется функция обратного вызова, последний передаваемый ей аргумент — это указатель, который вы задали в обращении к функции gtk_signal_connect(). Общий принцип — создание структуры, содержащей все глобальные данные, и передача ее адреса в необходимые программисту места.
Выводы
Базовые архитектуры приложений GNOME и Win32 одинаковы, и обе они основываются на работе с событиями. В этой главе в результате их сравнения показано:
8 И в GNOME, и в Win32 используется концепция бесконечного цикла, ожидающего поступления событий.
• Программы в общем случае могут быть примерно одинакового размера, хотя в специфических случаях одна из них может требовать более глубокой детализации.
в GNOME и Win32 разделяют концепцию окна верхнего уровня как главного изображения, и оба эти окна верхнего уровня способны принимать события.
S В обоих случаях используется метод, гарантирующий ’’чистое” закрытие приложения.
Эта глава — окончание третьей, последней части книги. Идущие далее приложения предназначены для двух целей. В приложениях А и В объяснено, откуда загрузить и как установить программное обеспечение. В последующих приложениях (C~G) находятся листинги и таблицы перекрестных ссылок, которыми очень удобно пользоваться при программировании в GNOME.
ПРИЛОЖЕНИЕПРИЛОЖЕНИЕЧто на компактдискеЧто на компактдиске
ПРИЛОЖЕНИЕ
ПРИЛОЖЕНИЕ
Что на компактдиске
Что на компактдиске
Это приложение описывает содержимое прилагаемого к книге компакт-диска. На диске находится полный комплект библиотек и утилит, которые могут понадобиться при создании приложений GNOME. Кроме того, на компакт-диск помещены все примеры из книги.
ПРИМЕЧАНИЕ . .
Все содержимое компакт-диска — открытое программное обеспечение, которое постоянно обновляется. Уже существуют более новые версии того, что имеется на диске. Однако, если вы еще мало работали с GNOME и GTK+, проще и безопаснее использовать программы, имеющиеся на компакт-диске. При переходе от одной версии программного обеспечения к другой иногда приходится сталкиваться с несовместимостью, но все версии программ, содержащихся на прилагаемом диске, полностью совместимы.
Если вы предпочитаете иметь самые последние версии всех программ, их можно найти по адресам, приведенным в приложении В. Кроме того, если вы будете использовать программы с компакт-диска, то в приложении В приведена информация, необходимая для их обновления.
Содержимое компакт-диска
Все файлы на компакт-диске хранятся в трех каталогах, приведенных в табл. А. 1.
Таблица А.1. Содержимое компакт-диска
Каталог
Содержимое
examples
Исходный код примеров, приведенных в книге. Примеры из каждой главы хранятся в отдельном каталоге.
gnome/base gnome/core
Исходный код базовых библиотек для разработки в GNOME/GTK+.
Исходный код загружвамого в оперативную память программного обеспечения библиотек для разработки в GNOME/GTK4-.■
tools
Содержит компилятор, autoconf и automake.
Примеры
Примеры, представленные в книге и содержащиеся на компакт-диске в каталоге examples, организованы в соответствии с той главой, в которой они приведены. Выполняемые файлы на диске отсутствуют, поскольку разные платформы Linux требуют различный формат выполняемых файлов. Каждый каталог можно скопировать на жесткий диск и откомпилировать его содержимое. Кроме того, если вы хотите откомпилировать
все примеры, просто скопируйте все дерево каталогов на жесткий диск и используйте make-файл в корневом каталоге.
ПРИМЕЧАНИЕ
Данная книга имеет свой Web-сайт, на котором также имеются исходные коды образцов программ. Если вы найдете где-нибудь ошибки или что-то, что следовало бы изменить в одном из примеров, пожалуйста, проверьте этот Web-сайт на наличие обновленных версий:
http;//www.belugalake.com/book/gnomebible
GNOME
Файлы, хранящиеся в каталогах gnome и tools, принадлежат к типу, который часто называют tarball. Они представляют собой заархивированные с помощью программы tar и сжатые с помощью утилиты gzip файлы. Все файлы содержат исходные коды и make- файлы, которые используются для компиляции и инсталляции файлов в вашу систему. Файлы GNOME могут быть инсталлированы в любое место, куда вы пожелаете. Обычно для их установки создается каталог в /usr/local:
mkdir /usr/local/gnome
Сделайте вновь созданный каталог вашим текущим каталогом:
cd /usr/local/gnome
Далее, если предположить, что точка монтирования вашего устройства CD-ROM — это каталог /mnt/cdrom, то можно установить каждый файл в его собственный подкаталог. Например, для инсталляции библиотеки GTK+ введите следующую команду:
tar -xvzf /mnt/cdrom/gnome/base/gtk+-1.2.6.tar.gz
Команда tar извлечет (x) файлы из архива и сохранит их в текущем каталоге под именем gtk+-1.2.6. Опция (у) указывает, что в процессе инсталляции должно выдаваться имя каждого файла и каталога. Сначала файл будет подвергнут обработке (z) утилитой gunzip, а затем извлечен из архива. Опция (f) сообщает, что имя входного файла указано в командной строке.
Компиляция и инсталляция каждого пакета проводится в три этапа. Первый этап — установка конфигурации для вашей системы. Этот этап большей частью автоматизирован, поскольку имеется основной сценарий, который находит необходимую информацию и создает make-файлы. Уже после создания make-файлов будет еще необходимо откомпилировать и инсталлировать само программное обеспечение. Все это производится с помощью трех команд:
configure
make
make install
Первая команда создает make-файлы, вторая — компилирует исходный код в объектный, а третья — сохраняет двоичные файлы в требуемых местах.
ПРИМЕЧАНИЕ .
Лучше всего, если вы ознакомитесь с этим процессом. Прочтите файлы README и INSTALL, которые имеются в каждом каталоге с исходным кодом. Особенно это полезно при инсталляции специального программного обеспечения. После прочтения двух-трех таких файлов, процесс будет более понятен.
Инструментарий
Инструментарий, поставляемый на компакт-диске, включая исходный код, также хранится в виде tarball. Его инсталляция аналогична инсталляции GNOME, но, может быть, на этот раз вы решите уделить больше внимания файлам README и INSTALL. В частности, дсс имеет целый ряд опций, которые позволяют вам сконфигурировать его по своему усмотрению.
' Настройка системы приложение дПЯ разработки Rпрограммного
^обеспечения
Существует ряд программных компонентов, которые необходимо инсталлировать до того, как вы сможете писать приложения GNOME/GTK+. Если у вас имеется довольно свежий компакт-диск с операционной системой Linux, то у вас наверняка есть большая часть всего необходимого, а может быть, и все необходимое.
ПРИМЕЧАНИЕ .
Все меняется в мире открытого программного обеспечения. Имена и все URL, приведенные здесь, могут поменяться. Кроме того, новые версии некоторых программ могут работать по-другому и к ним могут предъявляться несколько иные требования, нежели описанные здесь. •
Linux
Если у вас нет Linux, вам следует приобрести компакт-диск (CD-ROM). Коммерческий CD-ROM обладает тем достоинством, что он содержит большинство из того программного обеспечения, что вам будет необходимо, программы с него устанавливаются легче, чем загруженные с дистанционного компьютера (с Internet), и у вас будет телефонная поддержка.
Однако, если вы хотите получить Linux через Internet, необходимо тщательно выбирать версию. Не используйте экспериментальные версии. Номер версии Linux отражает, является ли версия стабильной или разрабатываемой. Если только вы сами не работаете над ядром Linux, используйте стабильную версию. Если вторая цифра в номере версии четная (2.0, 2.2 и т.д.), то это стабильная версия. В номере версии может быть и третья цифра (например, 2.2.8), которая указывает на устранение ошибок. Самая последняя версия ядра — это версия с максимальным четным номером (по крайней мере, это было бы желательно).
Наиболее популярные дистрибутивы Linux можно найти по следующим адресам:
Caldera Corel Debian LinuxPro Red Hat Slackware StormLinux SuSE TurboLinuxCaldera Corel Debian LinuxPro Red Hat Slackware StormLinux SuSE TurboLinuxhttp://www.caldera.com http://linux.corel.com http://www.debian.org/ http://www.wgs.com http://www.redhat.com http://www.slackware.com http://stormlinux.com http://www.suse.com http://www.turbolinux.com
Caldera Corel Debian LinuxPro Red Hat Slackware StormLinux SuSE TurboLinux
Caldera Corel Debian LinuxPro Red Hat Slackware StormLinux SuSE TurboLinux
Хотя в любом из них можно успешно запустить GNOME и использовать в качестве платформы для разработки, тем не менее, Red Hat Linux наиболее соответствует среде GNOME.
gcc (egcs)
Это компилятор языка С, который необходим для компиляции программ. В апреле 1999 года в соответствии с планами на будущее Free Software Foundation (FSF — Фонд свободно распространяемого программного обеспечения) назначил egcs Steering Committee (комитет регулирования egcs) по поддержке gcc. Тогда же было изменено имя с gcc на egcs. Но, тем не менее, выполняемый модуль до сих пор называется gcc, поскольку он должен работать со всеми существующими make-файлами.
Несомненно в ваш дистрибутив Linux будет входить и компилятор gcc. Но время от времени он наделяется новыми возможностями, поэтому необходимо, чтобы версия gcc соответствовала текущей версии GNOME. Последнюю версию компилятора можно найти в Internet в ряде мест. Домашняя страница компилятора:
http:/Zwww.gnu.ai.mit.edu/software/gcc/gcc.html
XFree86
Это низкоуровневое оконное программное обеспечение, которое используется GTK+ и GDK. Все дистрибутивы Linux содержат это программное обеспечение, которое устанавливается при обычной инсталляции. Это очень стабильное программное обеспечение, но иногда и оно обновляется (во время написания книги последней была версия X11R6 • 4). Если выяснится, что вам необходима более новая версия (или необходимо найти больше информации по этой версии), то посетите домашнюю страницу XFree86:
http: //ww. xf ree86. org
autoconf и automake
Вам понадобятся эти утилиты для компиляции исходных кодов из дистрибутивов GNOME. Они используются для автоматического создания make-файлов и последующей компиляции программ. Если в процессе компиляции у вас возникли сложности, убедитесь, что имеете самые последние версии. Если в вашем дистрибутиве Linux они недоступны, вы можете переписать их с:
ftp://ftp.gnu.org/pub/gnu/automake/
ftp://ftp.gnu.org/pub/gnu/autoconf/
Эти утилиты можно использовать и для компиляции ваших собственных программ, что особенно актуально при написании большого приложения. Процесс компиляции описан в главе 20.
GNOME, glib, GDK и GTK+
Вам понадобится исходный код. При написании приложения наступает момент, когда необходимо посмотреть, что же происходит на самом деле. Если вы не хотите иметь проблемы при компиляции и инсталляции GNOME, можно сдублировать и двоичные файлы. Все, что может вам понадобиться, можно найти на Web-сайте GNOME:
http://ют.gnome.org
Информацию и последние версии других компонентов можно найти отдельно на их собственных Web-сайтах:
http://www.glib.org
http://www.gdk.org
http://www.gtk.org
Существует множество опций. Некоторое программное обеспечение предназначено только для одного дистрибутива Linux, и в то же время каждый из них предназначен для конкретного CPU (центрального процессора). Если вам не удается найти программное обеспечение для вашей системы, сдублируйте исходный код и откомпилируйте его. Какие именно части копировать и инсталлировать зависит от того, что вы собираетесь делать:
Если вы хотите просто инсталлировать и использовать интерфейс GNOME и не собираетесь программировать, загрузите и установите только базовую систему.
Если вы намерены писать приложения GTK+, не используя GNOME, загрузите только библиотеки GTK+.
9 Если вы хотите писать приложения GNOME, необходимо скопировать GTK+, базовую систему GNOME и системы для разработки приложений. GTK+ не распространяется отдельно, она входит в пакет GNOME как средство разработки.
Если вы хотите испытать в работе самые н^вые версии GNOME и GTK+, необходимо получить текущую версию исходных кодов из архива CVS (Concurrent Version System) и откомпилировать их.
Если вы хотите участвовать в проекте GNOME и самостоятельно модифицировать систему, вам необходимо получить из архива CVS исходный код для разработки и предпринимать усилия по его обновлению.
Если вы используете Red Hat Linux, то, возможно, у вас уже установлены с компактдиска некоторые (или все) описанные компоненты. К счастью, во время процедуры инсталляции автоматически определяется наличие уже установленных компонентов. Если вы используете систему rpm, то уже установленная часть не инсталлируется заново. С другой стороны, если у вас установлена более старая версия, то процедура инсталляции обновляет ее до новой.
ПРИМЕЧАНИЕ НАУЧНОГО РЕДАКТОРА
CVS — Concurrent Version System — система параллельно действующих версий программ.
RPM — Red Hat Package Manager — менеджер пакетов Red Hat Linux. Система для упаковки всех необходимых файлов программного продукта в так называемый RPM- файл.
Начните с посещения сайта:
http://www.gnome.org/start
Помимо всего прочего, на этой Web-страничке можно найти самую новую информацию по установке GNOME и узнать, какие файлы необходимо скопировать.
Инсталляция GTK+ на основе исходных кодов
Если вы хотите писать программы с использованием GTK+, не добавляя GNOME, вам необходимо загрузить только ту часть программного обеспечения, которая имеет отношение к GTK+. Вы можете получить копию GTK+ на FTP-сайте:
ftp.gtk.org/pub/gtk
Можно списать библиотеки в двоичном виде или в виде исходного кода. Если вы выберете последнее, то придется компилировать библиотеки. Эта простая процедура выполняется с помощью следующих команд:
configure
make
Получение файлов GTK+ и GNOME с исходным кодом
Файлы GTK+ и GNOME можно получить с целого ряда мест. Основное местоположение:
ftp://ftp.gnome.org/pub/GNOME
В этом каталоге в файле MIRRORS перечислены все места, где также хранятся файлы GNOME.
Это необязательный шаг. Вы можете получать последние версии исходного кода GTK+ и GNOME и обновлять вашу систему, когда угодно. Эти файлы с исходным кодом постоянно обновляются разработчиками. Но частое обновление необходимо только тогда, когда вы решите участвовать в проекте GNOME.
ПРИМЕЧАНИЕ
Самые последние версии исходного кода могут плохо компилироваться. Это происходит потому, что код постоянно находится в процессе разработки и при участии многих программистов, которые одновременно модифицируют ряд файлов, текущая моментальная копия исходного кода может быть неполной или несовместимой с предыдущими версиями. Поэтому, если вы сами хотите построить библиотеки GNOME и GTK+, то вам, может быть, придется обновлять исходный код несколько раз до получения рабочей версии.
Если вы получили библиотеки в двоичном формате, то наличие их исходного кода для разработки приложений вовсе не обязательно. Однако иногда полезно иметь и исходные файлы, с помощью которых вы можете получить ответы на возникшие вопросы. Реальность открытого кода такова, что программное обеспечение обновляется намного быстрее и чаще, чем его документация. Код информативен не только сам по себе: в нем и в некоторых текстовых файлах имеются комментарии, которые могут быть очень полезны.
Исходный код хранится в архивах CVS. Эта система предназначена для разработки программного обеспечения и используется для отслеживания изменений в исходном коде. Она позволяет каждому программисту отслеживать файлы исходного кода, изменять их и класть обратно в архив. Если два программиста изменяют один и тот же файл с исходным кодом, CVS объединяет изменения. Если изменения накладываются, то приходится вручную выполнять объединение. Если вы не работаете с кодом GNOME, то вам понадобится только текущая версия кода.
Для получения копии исходного кода необходимо выполнить следующее:
В вашей системе имеется программное обеспечение CVS. Используйте его для получения исходного кода и напишите сценарий со следующими инструкциями:
export CVSROOT=':pserver:anonymous@anoncvs.gnome.org:/cvs/gnome' cvs login•
cvs -z3 checkout glib gtk+ imlib ORBit gnome-libs gnome-core
Перейдите в каталог, который будет корневым каталогом для всех содержащихся в нем файлов исходного кода
Установите Internet-соединение.
Выполните сценарий.
Первая строка сценария определяет переменную окружения CVSROOT, которая содержит адрес архива CVS с файлами исходного кода. Программа cvs требует, чтобы эта переменная была установлена.
Программа cvs пригласит вас ввести пароль. При отсутствии пароля нажмите Enter.
Файлы загружены. Несколько каталогов — по одному для каждой библиотеки — будет создано в текущем каталоге, для всех их будет получен исходный код.
Обновление исходного кода
После того как вы сдублировали файлы исходного кода, можно их постоянно поддерживать на уровне с последними версиями, написав сценарий, который будет обновлять ваши файлы исходного кода. Этот сценарий очень похож на приведенный ранее в шаге 1:
export CVSROOT=':pserver:anonymous@anoncvs.gnome.org:/cvs/gnome' cvs login
cvs -z3 update -Pd glib gtk+ imlib ORBit gnome-libs gnome-core
В данном сценарии cvs вместо checkout использует команду update. Опция -Р заставляет cvs удалять любые каталоги, которые остались пустыми после обновления. Процесс обновления занимает некоторое время, поскольку необходимо проверить версию каждого файла, но все равно это выполняется гораздо быстрее, чем полная загрузка исходного кода.
Отслеживание изменений
Вы можете подписаться на рассылку сообщений об обновлениях. Для этого необходимо отослать сообщение, состоящее из одного слова subscribe, по адресу:
cvs-commits-list-request@gnome.org
После подписки вы будете получать электронную почту при каждом обновлении одного или нескольких модулей.
Просмотр исходного кода в оперативном режиме
Если вы предпочитаете не дублировать исходный код, а проводить поиск архивов CVS в режиме online, зайдите на Web-сайт:
http://cvs.gnome.org
На этом сайте вы можете вести поиск в архивах, используя несколько параметров поиска.
ПРИЛ0ЖВ4ИЕ
|^ж Наследование
Каждый виджет наследует функции и возможности базового класса GtkWidget. В свою очередь, GtkWidget наследует функции и возможности GtkOb ject. Все, что образовано из GtkOb ject, является объектом. Все, что образовано из GtkWidget, является и объектом, и виджетом.
Для каждого определенного объекта определен свой класс, и для каждого класса параллельно существует дерево иерархии, аналогичное иерархическому дереву объектов. Оба эти дерева имеют подобные имена и маршрут наследования, но все имена иерархического дерева классов заканчиваются на Class. Например, следующей иерархии виджетов:
GnomePixmap->GtkWidget->GtkObject
соответствует следующая иерархия классов:
GnomePixmapClass->GtkWidgetClass->GtkObjectClass
Существует макрос, с помощью которого можно преобразовать объект к одному из типов в его иерархической цепочке. Например, виджет GnomeAbout ведет родословную от GnomeDialog, следовательно, с помощью макроса GNOME_DIALOG(виджет) вы можете трактовать указатель на виджет GnomeAbout подобно указателю на GnomeDialog. Этот же указатель с помощью макроса GTK_WINDOW(виджет) может указать на виджет GtkWindow. Для каждого типа виджетов обязательно существует макрос, включая GTK_OBJECT (виджет). Использование этих макросов позволяет получить доступ к функциям любого виджета, входящего в иерархическое дерево.
В этом приложении приведен перечень всех виджетов GNOME и GTK+ с показом их происхождения (наследования), возвращаясь вплоть до GtkOb ject.
GnomeAbout->GnomeDialog->GtkWindow->GtkBin->GtkContainer->GtkWidget-> GtkObject
GnomeAnimator->GtkWidget->GtkObject
GnomeApp->GtkWindow->GtkBin->GtkContainer->GtkWidget->GtkObject
GnomeAppBar->GtkHBox->GtkBox->GtkContainer->GtkWidget->GtkObject
GnomeCalculator->GtkVBox->GtkBox->GtkContainer->GtkWidget->GtkOb ject GnomeCanvas->GtkLayout->GtkContainer->GtkWidget->GtkObject
GnomeCanvasEllipse->GnomeCanvasRE->GnomeCanvasItem->GtkObject
GnomeCanvasGroup->GnomeCanvasItem->GtkObject
GnomeCanvasImage->GnomeCanvasItem->GtkObject
GnomeCanvasItem->GtkObject
GnomeCanvasLine->GnomeCanvasItem->GtkObject GnomeCanvasPolygon->GnomeCanvasItem->GtkObject GnomeCanvasRE->GnomeCanvasItem->GtkObject GnomeCanvasRect->GnomeCanvasRE->GnomeCanvasItem->GtkObject GnomeCanvasText->GnomeCanvasItem->GtkObject GnomeCanvasWidget->GnomeCanvasItem->GtkObject GnomeClient->GtkObject
GnomeColorPicker->GtkButton->GtkBin->GtkContainer~>GtkWidget->GtkOb ject GnomeDEntryEdit->GtkObject
GnomeDialog->GtkWindow->GtkBin->GtkCor+ainer->GtkWidget->GtkObject GnomeDock->GtkContainer->GtkWidget->GtkObject
GnomeDockBand->GtkContainer->GtkWidget->GtkObject
GnomeDockItem->GtkBin->GtkContainer->GtkWidget->GtkObject GnomeDockLayout->GtkObject
GnomeEntry->GtkCombo->GtkHBox->GtkBox->GtkContainer-> GtkWidget->GtkObject GnomeFileEntry->GtkHBox->GtkBox->GtkContainer->GtkWidget->GtkObject GnomeFontPicker->GtkButton->GtkBin->GtkContainer->GtkWidget->GtkObject GnomeFontSelector->GtkDialog->GtkWindow->GtkBin->GtkContainer-> GtkWidget-> GtkObject
GnomeGuru->GtkVBox->GtkBox->GtkContainer->GtkWidget->GtkObject GnomeHRef->GtkButton->GtkBin->GtkContainer->GtkWidget->GtkObject GnomeIconEntry->GtkVBox->GtkBox->GtkContainer->GtkWidget-> GtkObject GnomeIconSelection->GtkVBox->GtkBox->GtkContainer->GtkWidget->GtkObject GnomeLess->GtkVBox->GtkBox->GtkContainer->GtkWidget->GtkObject GnomeMDI->GtkObject
GnomeMDIChild->GtkObject
GnomeMDIGenericChild->GnomeMDIChild->GtkObject
GnomeMessageBox->GnomeDialog->GtkWindow->GtkBin->GtkContainer->GtkWidget-> GtkObject
GnomeNumberEntry->GtkHBox->GtkBox->GtkContainer->GtkWidget->GtkObject GnomePaperSelector->GtkVBox->GtkBox->GtkContainer->GtkWidget->GtkObject GnomePixmap->GtkWidget->GtkObject
GnomePixmapEntry->GtkVBox->GtkBox->GtkContainer->GtkWidget->GtkOb ject GnomeProcBar->GtkHBox->GtkBox->GtkContainer->GtkWidget->GtkObject GnomePropertyBox->GnomeDialog->GtkWindow->GtkBin->GtkContainer->GtkWidget->
GtkObject.
GnomeScores->GnomeDialog->GtkWindow->GtkBin->GtkContainer->GtkWidget-> GtkObject
GnomeSpell->GtkVBox->GtkBox->GtkContainer->GtkWidget->GtkObject GnomeStock->GnomePixmap->GtkWidget->GtkObject
GnomeStockPixmapWidget->GtkVBox->GtkBox->GtkContainer->GtkWidget->GtkObject GtkAccelLabel->GtkLabel->GtkMisc->GtkW'dget->GtkObject
GtkAdjustment->GtkData->GtkObject
GtkAlignment->GtkBin->GtkContainer->GtkWidget->GtkObject GtkArrow->GtkMisc->GtkWidget->GtkObject
GtkAspectFrame->GtkFrame->GtkBin->GtkContainer->GtkWidget->GtkObject GtkBin->GtkContainer->GtkWidget->GtkObject
GtkBox->GtkContainer->GtkWidget->GtkObject
GtkButton->GtkBin->GtkContainer->GtkWidget->GtkObject GtkButtonBox->GtkBox->GtkContainer->GtkWidget->GtkObject GtkCList->GtkContainer->GtkWidget->GtkObject GtkCTree->GtkCList->GtkContainer->GtkWidget->GtkObject GtkCalendar->GtkWidget->GtkObject
GtkCheckButton->GtkToggleButton->GtkButton->GtkBin->GtkContainer-> GtkWidget->GtkObject
GtkCheckMenuItem->GtkMenuItem->GtkItem->GtkBin->GtkContainer->GtkWidget-> GtkObject
GtkClock->GtkLabel->GtkMisc->GtkWidget->GtkObject
GtkColorSelection->GtkVBox->GtkBox->GtkContainer->GtkWidget->GtkObject
GtkColorSelectionDialog->GtkWindow->GtkBin->GtkContainer->GtkWidget-> GtkObject
GtkCombo->GtkHBox->GtkBox->GtkContainer->GtkWidget->GtkObject GtkContainer->GtkWidget->GtkObject
GtkCurve->GtkDrawingArea->GtkWidget->GtkObject
GtkData->GtkObject
GtkDial->GtkWidget->GtkObject
GtkDialog->GtkWindow->GtkBin->GtkContainer->GtkWidget->GtkObject GtkDrawingArea->GtkWidget->GtkObject
GtkEditable->GtkWidget->GtkObject
GtkEntry->GtkEditable->GtkWidget->GtkObject
GtkEventBox->GtkBin->GtkContainer->GtkWidget->GtkObject
GtkFileSelection->GtkWindow->GtkBin->GtkContainer->GtkWidget->GtkObject GtkFixed->GtkContainer->GtkWidget->GtkObject GtkFontSelection->GtkNotebook->GtkContainer->GtkWidget->GtkObject GtkFontSelectionDialog->GtkWindow->GtkBin->GtkContainer->GtkWidget-> GtkObject
GtkFrame->GtkBin->GtkContainer->GtkWidget->GtkObject
GtkGammaCurve->GtkVBox->GtkBox->GtkContainer->GtkWidget->GtkObject GtkHBox->GtkBox->GtkContainer->GtkWidget->GtkObject GtkHButtonBox->GtkButtonBox->GtkBox->GtkContainer->GtkWidget->GtkOb ject GtkHPaned->GtkPaned->GtkContainer->GtkWidget->GtkObject GtkHRuler->GtkRuler->GtkWidget->GtkObject GtkHScale->GtkScale->GtkRange->GtkWidget->GtkObject GtkHScrollbar->GtkScrollbar->GtkRange->GtkWidget->GtkObject
GtkHSeparator->GtkSeparator->GtkWidget->GtkObject GtkHandleBox->GtkBin->GtkContainer->GtkWidget->GtkObject GtkImage->GtkMisc->GtkWidget->GtkObject
GtkInputDialog->GtkDialog->GtkWindow->GtkBin->GtkContainer->GtkWidget-> GtkObject
GtkInvisible->GtkBin->GtkContainer->GtkWidget->GtkObject GtkItem->GtkBin->GtkContainer->GtkWidget->GtkObject GtkItemFactory->GtkObject
GtkLabel->GtkMisc->GtkWidget->GtkObject GtkLayout->GtkContainer->GtkWidget->GtkObject GtkList->GtkContainer->GtkWidget->GtkObject GtkListItem->GtkItem->GtkBin->GtkContainer->GtkWidget->GtkObject GtkMenu->GtkMenuShell->GtkContainer->GtkWidget->GtkObject GtkMenuBar->GtkMenuShell->GtkContainer->GtkWidget->GtkObject GtkMenuItem->GtkItem->GtkBin->GtkContainer->GtkWidget->GtkObject GtkMenuShell->GtkContainer->GtkWidget->GtkObject GtkMisc->GtkWidget->GtkObject GtkNotebook->GtkContainer->GtkWidget->GtkObject GtkObject
GtkOptionMenu->GtkButton->GtkBin->GtkContainer->GtkWidget~>GtkObject GtkPacker->GtkContainer->GtkWidget->GtkObject GtkPaned->GtkContainer->GtkWidget->GtkObject GtkPixmap->GtkMisc->GtkWidget->GtkObject GtkPixmapMenuItem->GtkMenuItem->GtkItem->GtkBin->GtkContainer->GtkWidget-> GtkObject
GtkPlug->GtkWindow->GtkBin->GtkContainer->GtkWidget-> GtkObject GtkPreview->GtkWidget->GtkObject GtkProgress->GtkWidget->GtkObject GtkProgressBar->GtkProgress->GtkWidget->GtkObject
GtkRadioButton->GtkCheckButton->GtkToggleButton->GtkButton->GtkBin-> GtkContainer->GtkWidget->GtkObject
GtkRadioMenuItem->GtkCheckMenuItem->GtkMenuItem->GtkItem->GtkBin-> GtkContainer->GtkWidget->GtkObject
GtkRange->GtkWidget->GtkObject GtkRuler->GtkWidget->GtkObject GtkScale->GtkRange->GtkWidget->GtkObject GtkScrollbar->GtkRange->GtkWidget->GtkObject GtkScrolledWindow->GtkBin->GtkContainer->GtkWidget->GtkObject GtkSeparator->GtkWidget->GtkObject
GtkSocket->GtkContainer->GtkWidget->GtkObject GtkSpinButton->GtkEntry->GtkEditable->GtkWidget->GtkObject GtkStatusbar->GtkHBox->GtkBox->GtkContainer->GtkWidget->GtkObject
GtkTable->GtkContainer->GtkWidget->GtkObject
GtkTearof fMenuItem->GtkMenuItem->GtkItem->GtkBin->GtkContainer->GtkWidget-> GtkObject
GtkTed->GtkTable->GtkContainer->GtkWidget->GtkObject GtkText->GtkEditable->GtkWidget->GtkObject GtkTipsQuery->GtkLabel->GtkMisc->GtkWidget->GtkObject GtkToggleButton->GtkButton->GtkBin->GtkContainer->GtkWidget->GtkObject GtkToolbar->GtkContainer->GtkWidget->GtkObject
GtkTooltips->GtkData->GtkObject
GtkTree->GtkContainer->GtkWidget->GtkObject
GtkTreeItem->GtkItem->GtkBin~>GtkContainer->GtkWidget-> GtkObject GtkVBox->GtkBox->GtkContainer->GtkWidget->GtkObject GtkVButtonBox->GtkButtonBox->GtkBox->GtkContainer->GtkWidget->GtkObject GtkVPaned->GtkPaned->GtkContainer->GtkWidget->GtkObject
GtkVRuler->GtkRuler->GtkWidget->GtkObject
GtkVScale->GtkScale->GtkRange->GtkWidget->GtkObject
GtkVScrollbar->GtkScrollbar->GtkRange->GtkWidget->GtkObject GtkVSeparator->GtkSeparator->GtkWidget->GtkObject GtkViewport->GtkBin->GtkContainer->GtkWidget->GtkObject GtkWidget->GtkObject
GtkWindow->GtkBin->GtkContainer->GtkWidget->GtkObject GtkXmHTML->GtkContainer->GtkWidget->GtkObject
GtkXmHTMLParser->GtkObject
Установка u получение arg
arg — это значение внутри объекта, к которому можно обратиться по его имени. Каждый виджет имеет одно или несколько значений arg (аргументов) и имеет функцию для считывания значения, записи значения или для того и другого. Например, объект GtkWidget имеет следующую функцию, которую можно использовать для установки значения arg:
gtk_widget_set_arg(GtkObject *object,GtkArg *arg,guint id);
Объект GtkWidget также имеет функцию, позволяющую вам считывать значения аргументов:
gtk_widget_get_arg(GtkObject *object,GtkArg *arg,guint id);
В табл. D. 1 приведен список имен arg (аргументов), типов, операций, которые могут проводиться над каждым из них. Приняты следующие обозначения операций:
read/write чтение/запись
write-only только запись.
Таблица D.1. Аргументы
Имя arg
Тип данных
Операция
GnomeCanvasGroup::х
gdouble
read/write
GnomeCanvasGroup::у
gdouble
read/write
GnomeCanvasImage::anchor
GtkAnchorType
read/write
GnomeCanvasImage::height
gdouble
read/write
GnomeCanvasImage::image
Gdklmliblmage
read/write
GnomeCanvasImage::width
gdouble
read/write
GnomeCanvasImage::x
gdouble
read/write
GnomeCanvasImage::y
gdouble
read/write
GnomeCanvasLine::arrow_shape_a
gdouble
read/write
GnomeCanvasLine::arrowshapeb
gdouble
read/write
GnomeCanvasLine::arrow_shape_c
gdouble
read/write
GnomeCanvasLine::cap_style
GdkCapStyle
read/write
GnomeCanvasLine;:fill_color
gchar*
write-only
GnomeCanvasLine::fill_color_gdk
GdkColor
read/write
GnomeCanvasLine::fill_color_rgba
guint
read/write
Имя arg
Тип данных
Операция
GnomeCanvasLine::fill_stipple
Gdkwindow
read/write
GnomeCanvasLine::first_arrowhead
gboolean
read/write
GnomeCanvasLine::join_style
GdkJoinStyle
read/write
GnomeCanvasLine::last_arrowhead
gboolean
read/write
GnomeCanvasLine::line style
GdkLineStyle
read/write
, VA A V AAAAAAA A SSVVAVA,VA AA S V SV. A- S AV. -A A.
,VAWA, AASVSS SVSV-AAA
GnomeCanvasLine::points
GnomeCanvasPoints
read/write
SVAAVAAAAAAAAAAAA.SA,,,. VAAA-AAVAVVAASS SVAAAAA , AV ,A A S ASS AVA A ASVAAAAAASS AV A AVAVA V-V^V AA ASV V,A , AVA.AAAVAA
^AVAS-AVAa-a.-S-A-A-AS-A-A'As^^^^* A A A A S .AA . - V. • A A A A AS A A ,A ,AA . , AA SV, A W.S
GnomeCanvasLine::smooth
gboolean
read/write
GnomeCanvasLine::spline_steps
guint
read/write
GnomeCanvasLine::width_pixels
guint
write-only
GnomeCanvasLine::width_units
gdouble
write-only
GnomeCanvasPolygon::fill_color
gchar*
write-only
GnomeCanvasPolygon::fill_color_gdk
GdkColor
read/write
GnomeCanvasPolygon::fill_color rgba
guint
read/write
GnomeCanvasPolygon;:fill stipple
GdkWindow
read/write
GnomeCanvasPolygon::outline color
gchar*
write-only
GnomeCanvasPolygon::outlinecolorgdk
GdkColor
read/write
GnomeCanvasPolygon::outline_color_rgba
guint
read/write
GnomeCanvasPolygon::outline_stipple
GdkWindow
read/write
GnomeCanvasPolygon::points
GnomeCanvasPoints
read/write
VAAV.A AVAVAWAAA,A AAAAA VAASVA ,,AASSVA A AA ,AA AHAA-WA , AAA S AAAAA A.SV,,. :W V MAVSMA AA AA SV VAV.S.S . ASSSVA V. SV.V A A'AA . . .SV. • . A
.A.-.....,-SSVAA -A,.SW,™w,..«s..V A,.,AASVA A..A. . V V. V AA. .■
.A......A.AS-V.....A..VA..A.AV,...,.....A.A SSSV A VV.A..A
GnomeCanvasPolygon::width_pixels
guint
write-only
GnomeCanvasPolygon::width_units
gdouble
write-only
GnomeCanvasRE::fill_color
gchar*
write-only
GnomeCanvasRE::fill_color_gdk
GdkColor
read/write
GnomeCanvasRE::fill_color_rgba
guint
read/write
GnomeCanvasRE::fill stipple
GdkWindow
read/write
.. .. .. .—.. .. . .
GnomeCanvasRE::outline_color
gchar*
write-only
GnomeCanvasRE::outlinecolorgdk
GdkColor
read/write
GnomeCanvasRE::outline color rgba
guint
read/write
VAAVAaAA,A,ASVV,ASVAA.A SS AVA VV.SVAVAA.ASS AAA A SSW-.v . . AA.S-. . . AAAA.S . .SSV.V.A AAA. S AAA, VAVAVS A AVA A.A-s A.
AV^.-,.^^.-.:-.:VA..AA.S AS,A A , ASSSV.A .-AV. A A- S , SV. A .V A A
SV, A ,v
GnomeCanvasRE::outline_stipple
Gdkwindow
read/write
GnomeCanvasRE::width_pixels
guint
write-only
GnomeCanvasRE::width_units
gdouble
write-only
GnomeCanvasRE::xl
gdouble
read/write
' •• ‘ - ' -— ''
GnomeCanvasRE::x2
GnomeCanvasRE::yl
gdouble gdouble
read/write read/write
ZAVS^AAA ,AA A AV A A.-. AAV. AS. ASS A -A AA.VA „™.„„„VAAA SSS S A. A-A AA V VAA AA AA AA ,„ A VW A A VAA. AAVA A A S AA AA AA AAAA. - A.
-.SV. -AV V... -A..S-AVA. A AAA • V AA -SSSSS -S . ,A-A.s - • V ■ - • AA AA. . AA .—. A -. . - AA AAA-VA A AAA. A V
SSA.SS ,ASS.SV. AA. A.-.......A,...a...s-,. ASA.. . VAV AVA SSS ,
GnomeCanvasRE::y2
gdouble
read/write
A. .ААААА-А V AS,V AW V, AAA AAA. VAV.VAA A - A,AV, A AAV, A A A A V A SV AAA AASVA A V A A „А AA A AA- -A A AVA V V SV .V. VAA-S W—A.VA A ■ , AA AAAA SS .
AAAV.-AA.VA--.S.-A.S-AAAAA..-A.VASVAV. AA A-. AS . .— A AV. VA. - A-AA V. V.V . ,-SS - A A- A, AA.S.V A A A - A-.
.aa.va.-a..aa.vavava..a,.va.v.-.v-a.s..-.s.-v., AAV-.A-.V,
GnomeCanvasText::anchor
GtkAnchorType
read/write
GnomeCanvasText::clip •
gboolean
read/write
GnomeCanvasText::clip_height
gdouble
read/write
GnomeCanvasText::clip_width
gdouble
read/write
GnomeCanvasText::fill_color
gchar*
write-only
Имя arg
Тип данных
Операция
GnomeCanvasText::fill_color_gdk
GdkColor
read/write
GnomeCanvasText::fill_color_rgba
guint
read/write
GnomeCanvasText::fill_stipple
GdkWindow
read/write
GnomeCanvasText::font
gchar*
write-only
GnomeCanvasText::fontgdk
GdkFont
read/write
GnomeCanvasText::fontset
gchar*
write-only
GnomeCanvasText::justification
GtkJustification
read/write
GnomeCanvasText::text
gchar*
read/write
GnomeCanvasText::text_height
gdouble
read-only
GnomeCanvasText::text_width
gdouble
read-only
GnomeCanvasText::x
gdouble
read/write
GnomeCanvasText::x_offset
gdouble
read/write
GnomeCanvasText::y
gdouble
read/write
GnomeCanvasText::y_offset
gdouble
read/write
GnomeCanvasWidget::anchor
GtkAnchorType
read/write
GnomeCanvasWidget::height
gdouble
read/write
GnomeCanvasWidget::size_pixels
gboolean
read/write
GnomeCanvasWidget::widget
GtkObject
read/write
GnomeCanvasWidget::width
gdouble
read/write
GnomeCanvasWidget::x
gdouble
read/write
GnomeCanvasWidget::y
gdouble
read/write
GnomeDockltem::orientation
GtkOrientation
read/write
GnomeDockltem::shadow
GtkShadowType
read/write
GnomelconList::hadjustment
GtkAdjustment
read/write
GnomelconList:svadjustment
GtkAdjustment
read/write
GtkAccelLabel::accel_widget
GtkWidget
read/write
GtkAlignment::xalign
gfloat
read/write
GtkAlignment::xscale
gfloat
read/write
GtkAlignment::yalign
gfloat
read/write
GtkAlignment::yscale
gfloat
read/write
GtkArrow::arrow_type
GtkArrowType
read/write
GtkArrow::shadow_type
GtkShadowType
read/write
GtkBox::expand
gboolean
read/write
GtkBox::f ill
gboolean
read/write
GtkBox::homogeneous
gboolean
read/write
GtkBox::pack_type
GtkPackType
read/write
GtkBox::padding
gulong
read/write
GtkBox::position
glong
read/write
GtkBox::spacing
gint
read/write
GtkButton::label
gchar*
read/write
Имя arg
Тип данных
Операция
GtkButton::relief
GtkReliefStyle
read/write
GtkCList::n_columns
guint
read/write
GtkCList::reorderable
gboolean
read/write
GtkCList::row_height
guint
read/write
GtkCList::selection_mode
GtkSelectionMode
read/write
GtkCList::shadow_type
GtkShadowType
read/write
GtkCList::titles_active
gboolean
read/write
GtkCList::use_drag_icons
gboolean
read/write
GtkCTree::expander_style
. GtkCtreeExpander-Style
read/write
GtkCTree::indent
guint
read/write
GtkCTree::line_style
GtkCtreeLineStyle
read/write
GtkCTree::n columnsguintread/write
GtkCTree::show_stubgbooleanread/write
GtkCTree::spacing
guint
read/write
GtkCTree::tree_column
guint
read/write
GtkContainer::border_width
gulong
read/write
GtkContainer::child
GtkWidget
write-only
GtkContainer::resize_mode
GtkResizeMode
read/write
GtkEditable::editable
gboolean
read/write
GtkEditable::text_position
gint
read/write
GtkEntry::max_length
guint
read/write
GtkEntry:visibility
gboolean
read/write
GtkFrame::label
gchar*
read/write
GtkFrame::label_xalign
gfloat
read/write
GtkFrame::labelyalign
gfloat
read/write
GtkFrame::shadow
GtkShadowType
read/write
GtkHScale;:adjustment
GtkAdjustment
read/write
GtkHScrollbar::adjustment
GtkAdjustment
read/write
GtkHandleBox::shadow
GtkShadowType
read/write
GtkLabel::justify
GtkJustification
read/write
GtkLabel::label
gchar*
read/write
GtkLabel::pattern
gchar*
read/write
GtkMenuBar::shadow
GtkShadowType
read/write
GtkMisc:;xalign
gfloat
read/write
GtkMisc::xpad
gint
read/write
GtkMisc::yalign
gfloat
read/write
GtkMisc::ypad
gint
read/write
GtkNotebook::enable popup
gboolean
read/write
GtkNotebook::menu_label
gchar*
read/write
GtkNotebook::page
gint
read/write
Имя arg
Тип данных
Операция
GtkNotebook::position
gint
read/write
GtkNotebook::scrollable
gboolean
read/write
GtkNotebook::show_border
gboolean
read/write
GtkNotebook::show_tabs
gboolean
read/write
GtkNotebook::tab_border
guint
write-only
GtkNotebook::tab_fill
gboolean
read/write
GtkNotebook::tab_hborder
guint
read/write
GtkNotebook::tab_label
gchar*
read/write
GtkNotebook::tab_pack
gboolean
read/write
GtkNotebook::tab_pos
GtkPositionType
read/write
GtkNotebook::tab_vborder
guint
read/write
GtkObject::object_signal
GtkSignal
write-only
GtkObject::object_signal_after
GtkSignal
write-only
GtkObject::signal
GtkSignal
write-only
GtkObject::signal_after
GtkSignal
write-only
GtkObject::user_data
gpointer
read/write
GtkPacker::anchor
GtkAnchorType
read/write
GtkPacker::border_width
guint
read/write
GtkPacker::default_border_width
guint
read/write
GtkPacker::default_ipad_x
guint
read/write
GtkPacker::default_ipad_y
guint
read/write
GtkPacker::default_pad_x
guint
read/write
GtkPacker::default_pad_y
guint
read/write
GtkPacker::expand
gboolean
read/write
GtkPacker::fill_x
gboolean
read/write
GtkPacker::fill_y
gboolean
read/write
GtkPacker::ipad_x
guint
read/write
GtkPacker::ipad_y
guint
read/write
GtkPacker::pad_x
guint
read/write
GtkPacker;:pad_y
guint
read/write
GtkPacker::position
glong
read/write
GtkPacker::side
GtkSideType
read/write
GtkPacker::spacing
guint
read/write
GtkPacker::use_default
gboolean
read/write
GtkProgress::activity_mode
gboolean
read/write
GtkProgress::show_text
gboolean
read/write
GtkProgress::text_xalign
gfloat
read/write
GtkProgress::text_yalign
gfloat
read/write
GtkProgressBar::activity_blocks
guint
read/write
GtkProgressBar::activity_step
guint
read/write
Имя argТип данных
Операция
GtkProgressBar::adjustmentGtkAdjustment
GtkProgressBar::bar_styleGtkProgressBar-Style
GtkProgressBar::discrete_blocksguint
GtkProgressBar::orientationGtkProgressBar-Orientation
GtkRadioButton::groupGtkRadioButton
GtkRange::update_policyGtkUpdateType
GtkScale::digitsgint
GtkScale::draw_valuegboolean
GtkScale::value_posGtkPositionType
GtkScrolledWindow::hadjustmentGtkAdjustment
GtkScrolledWindow::hscrollbar_policy GtkPolicyType GtkScrolledWindow::vadjustmentGtkAdjustment
GtkScrolledWindow::vscrollbar_policy GtkPolicyType GtkScrolledWindow::window_placementGtkCornerType
GtkSpinButton::adjustmentGtkAdjustment
GtkSpinButton::climb_rategfloat
GtkSpinButton::digitsguint
GtkSpinButton::numericgboolean
GtkSpinButton::shadow_typeGtkShadowType
GtkSpinButton::snap_to_ticksgboolean
GtkSpinButton::update_policyGtkSpinButtonUpdate-Policy
GtkSpinButton::valuegfloat
GtkSpinButton::wrapgboolean
GtkTable::bottom_attachguint
GtkTable::column_spacingguint
GtkTable::homogeneousgboolean
GtkTable::left_attachguint
GtkTable::n_columnsguint
GtkTable::n_rowsguint
GtkTable::right_attachguint
GtkTable::row_spacingguint
GtkTable::top_attachguint
GtkTable::x_optionsGtkAttachOptions
GtkTable::x_paddingguint
GtkTable::y_optionsGtkAttachOptions
GtkTable::y_paddingguint
GtkText::hadjustmentGtkAdjustment
GtkText::line_wrapgboolean
GtkText::vadjustmentGtkAdjustment
GtkText::word_wrapgboolean
read/write read/write read/write read/write write-only read/write read/write read/write read/write read/write read/write read/write read/write read/write read/write read/write read/write read/write read/write read/write read/write read/write read/write read/write read/write read/write read/write read/write read/write read/write read/write read/write read/write read/write read/write read/write read/write read/write read/write read/write
Имя arg
Тип данных
Операция
GtkTipsQuery:scalierGtkWidgetread/write
GtkTipsQuery::emit_alwaysgbooleanread/write
GtkTipsQuery::label_inactivegchar*read/write
GtkTipsQuery::label_no_tip
gchar*
read/write
GtkToggleButton::active
gboolean
read/write
GtkToggleButton::draw_indicator
gboolean
read/write
GtkVScale::adjustment
GtkAdjustment
read/write
GtkVScrollbar::adjustment
GtkAdjustment
read/write
GtkViewport::hadjustment
GtkAdjustment
read/write
GtkViewport::shadow_type
GtkShadowType
read/write
GtkViewport::vadjustment
GtkAdjustment
read/write
GtkWidget::app_paintable
gboolean
read/write
GtkWidget::can_default
gboolean
,read/write
GtkWidget::can_focus
gboolean
read/write
GtkWidget::composite_child
gboolean
read/write
GtkWidget::events
GdkEventMask
read/write
GtkWidget::extension_events
GdkEventMask
read/write
GtkWidget::has default
gboolean
read/write
GtkWidget::has_focus
gboolean
read/write
GtkWidget::height
gint
read/write
GtkWidget::name
gchar*
read/write
GtkWidget::parent
GtkContainer
read/write
GtkWidget::receives_default
gboolean
read/write
GtkWidget::sensitive
gboolean
read/write
GtkWidget::style
GtkStyle
read/write
GtkWidget::visible
gboolean
read/write
GtkWidget::widthgintread/write
GtkWidget::xgintread/write
GtkWidget::y
gint
read/write
GtkWindow::allow_grow
gboolean
read/write
GtkWindow::allow_shrink
gboolean
read/write
GtkWindow::auto_shrink
gboolean
read/write
GtkWindow::modal
gboolean
read/write
GtkWindow::title
gchar*
read/write
GtkWindow::type
GtkWindow
read/write
GtkWindow::window_position
GtkWindowPosition
read/write
□нумераторы□нумераторы
□нумераторы
□нумераторы
Многие функции при обращении к ним принимают одно или несколько значений типа int (целое), каждое из которых является флагом или индикатором режима. Каждая константа объявляется как enum (энумератор — перечислимый тип данных), который задает тип каждой константы и присваивает имя каждому из ее возможных значений. В табл. Е. 1 приведены все наименования возможных значений для каждого из перечислимых типов.
Таблица Е.1. Энумератор и имена его возможных значений
Имя типа
Имена возможных значений
GdkAxisUse
GDK_AXIS_IGNORE, GDKAXISX, GDKJXISJ, GDK_AXIS_PRESSURE, GDK_AXIS_XTILT, GDK_AXIS_YTILT, GDKAXISLAST
GdkByteOrder
GDK_LSB_FIRST, GDK_MSB_FIRST
GdkCapStyle
GDK_CAP_NOT_LAST, GDK_CAP_BUTT, GDKCAPROUND, GDK CAP PROJECTING
GdkColorContextMode GDK_CC_MODE_UNDEFINED, GDKCC_MODE_BW,
GDK_CC_MODE_STD_CMAP, GDKCC_MODE_TRUE, GDKCCMODE MYGRAY, GDK_CC_MODE_PALETTE
GdkColorlnfoFlags
GdkCrossingMode
GDK_COLOR_WRITEABLE
GDK_CROSSING_NORMAL, GDKCROSSINGGRAB, GDK_CROSSING_UNGRAB
GdkCursorType GdkDebugFlag
GDKLASTCURSOR, GDK_CURSOR_IS_PIXMAP
GDK_DEBUG_MISC, GDK_DEBUG_EVENTS, GDKDEBUGDND, GDK_DEBUG_COLOR_CONTEXT, GDKDEBUGXIM
GdkDragAction
GDK_ACTION_DEFAULT, GDK_ACTION_COPY, GDKACTIONMOVE, GDKACTION LINK, GDKACTIONPRIVATE, GDKACTIONASK
GdkDragProtocol
GDKDRAG PROTOMOTIF, GDKDRAGPROTOXDND, GDK_DRAG_PROTO_ROOTWIN, GDK_DRAG_PROTO_NONE, GDK_DRAG_PROTO_WIN32_DROPFILES, GDKDRAGPROTOOLE2
GdkEventMask
GDK_EXPOSURE_MASK, GDK_POINTER_MOTION_MASK, GDK_POINTER_MOTION_HINT_MASK, GDK_BUTTON_MOTION_MASK, GDK_BUTTON1_MOTION_MASK, GDK_BUTTON2_MOTION_MASK, GDK_BUTTON3_MOTION_MASK, GDK_BUTTON_PRESS_MASK, GDK_BUTTON_RELEASE_MASK, GDKKEYPRESSMASK, GDK_KEY_RELE EMASK, GDKENTERNOTIFYMASK, GDK_LEAVE_NOTIFY_MASK, GDKFOCUS CHANGEMASK, GDK_STRUCTURE MASK, GDKPROPERTYCHANGEMASK, GDK_VISIBILITY_NOTIFY_MASK, GDKPROXIMITYINMASK, GDKPROXIMITYOUTMASK, GDKSUBSTRUCTUREMASK, GDK ALL EVENTS MASK
Имя типа
Имена возможных значений
GdkEventType
GDKNOTHING, GDK_DELETE, GDKDESTROY, GDKEXPOSE, GDK_MOTION_NOTIFY, GDK_BUTTON_PRESS, GDK2BUTTONPRESS, GDK3BUTTONPRESS, GDK_BUTTON_RELEASE, GDKKEYPRESS, GDK_KEY_RELEASE, GDK_ENTER_NOTIFY, GDKLEAVENOTIFY, GDK_FOCUS_CHANGE, GDK_CONFIGURE, GDKMAP, GDK_UNMAP, GDK_PROPERTY_NOTIFY, GDK_SELECTION_CLEAR, GDKSELECTIONREQUEST, GDK_SELECTION_NOTIFY, GDK_PROXIMITY_IN, GDK_PROXIMITY_OUT, GDK_DRAG_ENTER, GDK_DRAG_LEAVE, GDKDRAGMOTION, GDKDRAGSTATUS, GDKDROPSTART, GDK_DROP_FINISHED, GDK_CLIENT_EVENT, GDKVISIBILITYNOTIFY, GDK_NO_EXPOSE
GdkExtensionMode
' GDK_EXTENSION_EVENTS_NONE, GDK_EXTENSION_EVENTS_ALL,
GDK_EXTENSION_EVENTS_CURSOR
GdkFill
GDK_SOLID, GDK_TILED, GDK_STIPPLED, GDKOPAQUESTIPPLED
VVAVA.VAAA.A VAVWXAAAAVAAAAVAWA^AAAVArA- WW. VAAXXX VV а~аааааах.иа-ааа.а.аа
GdkFillRule
GDK_EVEN_ODD_RULE, GDK_WINDING_RULE
GdkFilterReturn
GDK_FILTER_CONTINUE, GDK_FILTER_TRANSLATE, GDK_FILTER_REMOVE
GdkFontType
GDKFONTFONT, GDK_FONT_FONTSET
GdkFunction
GDK_COPY, GDKINVERT, GDKXOR, GDKCLEAR, GDKAND, GDK_AND_REVERSE, GDK_AND_INVERT, GDKNOOP, GDKOR, GDKEQUIV, GDKORREVERSE, GDKCOPYINVERT, GDKORINVERT, GDKNAND, GDKSET'
GdkGCValuesMask
GDKGCFOREGROUND, GDKGCBACKGROUND, GDKGCFONT, GDK_GC_FUNCTION, GDKGCFILL, GDK_GC_TILE, GDK_GC_STIPPLE, GDKGCCLIPMASK, GDKGCSUBWINDOW, GDK_GC_TS_X_ORIGIN, GDKGCTSYORIGIN, GDKGCCLIPXORIGIN, GDKGCCLIPYORIGIN, GDKGCEXPOSURES, GDKGCLINEWIDTH, GDK_GC__LINE_STYLE, GDK GC CAP STYLE, GDK_GC_JOIN_STYLE
GdkICAttributesType
GDK_IC_STYLE, GDKICCLIENTWINDOW,
GDKICFOCUSWINDOW, GDKIC_FILTEREVENTS, GDK_IC_SPOT_LOCATION, GDKICLINESPACING, GDKICCURSOR, GDKICPREEDITFONTSET,
GDK_IC^PREEDIT_AREA, GDK_IC_PREEDIT_AREA_NEEDED, GDK_IC^PREEDIT_FOREGROUND, GDK_IC_PREEDIT_BACKGROUND, GDK_IC_PREEDIT_PIXMAP, GDK IC PREEDIT COLORMAP, GDK_IC_STATUS_FONTSET, GDK_IC_STATUS_AREA, GDK_IC_STATUS_AREA_NEEDED, GDK_IC_STATUS_FOREGROUND, GDK_IC_STATUS_BACKGROUND, GDK_IC_STATUS_PIXMAP, GDKICSTATUSCOLORMAP, GDKICALLREQ, GDK_IC_PREEDIT_AREA_REQ, GDK_IC_PREEDIT_POSITION_REQ, GDK_IC_STATUS_AREA_REQ
»W...V WM« WW-AMFM» • AWWAAM* -A WAW*x . «А.А .A• • ♦ MX♦ •
GdkIMStyle
GDK_IM_PREEDIT_AREA, GDK_IM_PREEDIT_CALLBACKS, GDK_IM_PREEDIT_POSITION, GDK_IM_PREEDIT_NOTHING, GDK_IM_PREEDIT_NONE, GDK_IM_PREEDIT_MASK, GDK_IM_STATUS_AREA, GDK_IM_STATUS_CALLBACKS, GDK_IM_STATUS_NOTHING, GDK_IM_STATUS_NONE, GDK IM STATUS MASK
A AA A AAWAV.XX AAAV VAVX A*. WAAAA**4W.W*V. v »WAV. AA XWA AA VAAAXWA XVA A VAX WW.V.V
VAAV ..-..V. AAA..A. A • • V. AV-V A V. V.V.AA . A s :• S A- A- : . . „X A. V. . A*. . . - A-S V ..V A A X A- • AASAVAaVAXA X VAA A. A . . Av A V ,X A. -AV,. A . • AAX A
GdklmageType
GDK_IMAGE_NORMAL, GDK_IMAGE_SHARED, GDK_IMAGE_FASTEST, GDK IMAGE SHARED PIXMAP
Имя типаИмена возможных значений
GdklnputConditionGDK
INPUTREAD, GDK_INPUT_WRITE, GDK_INPUT_EXCEPTION
GdklnputModeGDK
MODE DISABLED, GDK_MODE_S.CREEN, GDK_MODE_WINDOW
GdklnputSourceGDK
GDK^
GdkJoinStyleGDK
GdkLineStyleGDK
GDK^
GdkModifierTypeGDK
gdk" gdk" gdk" GDK^
GdkNotifyTypeGDK
GDK^ GDK*
SOURCE—MOUSE, GDKSOURCEPEN, GDK_SOURCE_ERASER, "sourcecursor
JOINMITER, GDK_JOIN_ROUND, GDK_JOIN_BEVEL
LINE_SOLID, GDK_LINE_ON_OFF_DASH, ”line_double_dash
SHIFTMASK, GDKLOCKMASK, GDK_CONTROL_MASK, ’MOD1MASK, GDK_M0D2_MASK, GDK_MOD3_MASK, "M0D4MASK, GDKMOD5MASK, GDK_BUTTON1_MASK, BUTTON2_MASK, GDKBUTTON3MASK, GDK_BUTTON4_MASK, "BUTTON5MASK, GDKRELEASEMASK, GDK_MODIFIER_MASK
NOTIFY_ANCESTOR, GDK_NOTIFY_VIRTUAL, 'notifyinferior, gdk_notify_nonlinear, ’NOTIFY_NONLINEAR_VIRTUAL, GDK_NOTIFY_UNKNOWN
GdkOverlapTypeGDK
GDK^
GdkPropModeGDK
GDK^
GdkPropertyStateGDK
GdkRgbDitherGDK
GDK^
GdkSelectionGDK_
GdkSelectionTypeGDK
gdk" GDK* GDK* gdk'
GdkStatusGDK
gdk"
GdkSubwindowMode* GDK
GdkTargetGDK
gdk" GDK~
GdkVisibilityStateGDK
gdk"
GdkVisualTypeGDK
gdk" gdk"
GdkWMDecorationGDK
gdk" gdk"
GdkWMFunctionGDK
gdk"
OVERLAP_RECTANGLE_IN, GDK_OVERLAP_RECTANGLE_OUT, "overlap_rectangle_part
PROP_MODE_REPLACE, GDK_PROP_MODE_PREPEND, PROP_MODE_APPEND
PROPERTY_NEW_VALUE, GDK_PROPERTY_DELETE
RGB_DITHER_NONE, GDK_RGB_DITHER_NORMAL, "rgb_dither_max
SELECTION_PRIMARY, GDK_SELECTION_SECONDARY
SELECTIONTYPEATOM, GDK_SELECTION_TYPE_BITMAP, "selectiontypecolormap,
SELECTION_TYPE_DRAWABLE,
"selectiontypeinteger, gdk_selection_type_pixmap, ’SELECTIONTYPEWINDOW, GDK_SELECTION_TYPE_STRING
OK, GDK ERROR, GDKERRORPARAM, GDK_ERROR_FILE, "error^mem
_CLIP_BY_CHILDREN, GDK_INCLUDE_INFERIORS
TARGETBITMAP, GDK_TARGET_COLORMAP, "TARGET_DRAWABLE, GDKTARGETPIXMAP, ’TARGET_STRING
VISIBILITYUNOBSCURED, GDKVISIBILITY_PARTIAL, ^VISIBILITY—FULLY—OBSCURED
VISUALSTATIC-GRAY, GDK_VISUAL_GRAYSCALE,
VISUAL—STATIC—COLOR, GDK-VISUAL_PSEUDO_COLOR, "VISUAL-TRUECOLOR, GDK-VISUAL_DIRECT_COLOR
DECORALL, GDK—DECOR_BORDER, GDK_DECOR_RESIZEH, "DECOR-TITLE, GDK-DECORMENU, GDK-DECOR-MINIMIZE, "decormaximize
FUNC_ALL, GDK—FUNC—RESIZE, GDK_FUNC—MOVE, "FUNC MINIMIZE, GDK FUNC MAXIMIZE, GDK FUNC CLOSE
GdkWindowAttributesTypeGDKWATITLE, GDK_WA_X, GDK_WA_Yf GDK_WA_CURSORf GDK_WA_COLORMAP, GDKWAVISUAL, GDK_WA_WMCLASS, GDK WA NOREDIR
Имя типа
Имена возможных значений
GdkWindowClass
GDK_INPUT_OUTPUT, GDK_INPUT_ONLY
GdkWindowHints
GDKHINTPOS, GDK_HINT_MIN_SIZE, GDK_HINT_MAX_SIZE, GDK_HINT_BASE_SIZE, GDK_HINT_ASPECT, GDK_HINT_RESIZE_INC
GdkWindowType
GDKWINDOWROOT, GDK_WINDOW_TOPLEVEL, GDKWINDOWCHILD, GDK_WINDOW_DIALOG, GDK_WINDOW__TEMP, GDK_WINDOW_PIXMAP, GDK_WINDOW_FOREIGN
GnomeAnimatorLoopType
GNOME_ANIMATOR_LOOP_NONE, GNOMEANIMATORLOOPRESTART, GNOME_ANIMATOR_LOOP_PING_PONG
GnomeAnimatorStatus
GNOMEANIMATORSTATUSSTOPPED, GNOME_ANIMATOR_STATUS_RUNNING
GnomeCalculatorMode
GNOMECALCULATORDEG, GNOME_CALCULATOR_RAD, GNOME_CALCULATOR_GRAD
GnomeClientFlags
GNOME_CLIENT_IS_CONNECTED, GNOME_CLIENT_RESTARTED, GNOME_CLIENT_RESTORED
GnomeClientState
GNOME_CLIENT_IDLE, GNOME_CLIENT_SAVING_PHASE_1, GNOME_CL I ENT__WAI TING FOR PHASE 2 , GNOME_CLIENT_SAVING_PHASE_2, GNOME_CLIENT_FROZEN, GNOME_CLIENT_DISCONNECTED, GNOME_CLIENT_REGISTERING
GnomeDateEditFlags
GNOME DATE_EDIT_SHOW_TIME, GNOME_DATE_EDIT_24_HR, gnome3date_edit_week_starts_on_monday
GnomeDialogType
GNOMEDIALOGERROR, GNOMEDIALOGNORMAL
GnomeDockltemBehavior
GNOME_DOCK_ITEM_BEH_NORMAL, GNOMEDOCKITEMBEHEXCLUSIVE, GNOME_DOCK_ITEM_BEH_NEVER_FLOATING, GNOME_DOCK_ITEM_BEH_NEVER_VERTICAL, GNOME_DOCK_ITEM_BEH_NEVERHORIZONTAL, GNOME_DOCK_ITEM_BEH_LOCKED
GnomeDockPlacement
GNOME_DOCK_TOP, GNOME_DOCK_RIGHT, GNOMEDOCKBOTTOM, GNOMEDOCKLEFT, GNOMEDOCKFLOATING
GnomeFontPickerMode
GNOME_FONT_PICKER_MODE_PIXMAP, GNOME_FONT_PICKER_MODE_FONT_INFO, GNOME_FONT_PICKER_MODE_USER_WIDGET, GNOME_FONT_PICKER_MODE_UNKNOWN
GnomelconListMode
GNOME_ICON_LIST_ICONS, GNOME_ICON_LIST_TEXT_BELOW, GNOMEICONLISTTEXTRIGHT
GnomelnteractStyle
GNOME_INTERACT_NONE, GNOME_INTERACT_ERRORS, GNOME_INTERACT_ANY
GnomeMDIMode
GNOME_MDI_NOTEBOOK, GNOME^MDI TOPLEVEL, GNOMEMDIMODAL, GNOME_MDI_DEFAULT_MODE
GnomeMagicType
T_END, T_BYTE, TSHORT, T_LONG, T_STR, T_DATE, T_BESHORT, T_BELONG, T_BEDATE, T_LESHORT, T_LELONG, T_LEDATE
GnomeHetadataErrort
GNOME_METADATA_OK, GNOMEMETADATAIOERROR, GNOME_METADATA_NOT_FOUND
GnomePreferencesType
GNOME_PREFERENCES_NEVER, GNOME_PREFERENCES_USER, GNOME PREFERENCES ALWAYS
Имя типа
Имена возможных значений
GnomePropertyAction
GNOME PROPERTY_ACTION_APPLY, gnome'2property_action_update , GNOME PROPERTY_AOTION_LOAD,'
GNOME_PROPERTY ACTION^SAVE,
GNOME_PROPERTY_ACTION_LOAD_TEMP,
GNOME_PROPERTY ACTIONJSAVEJTEMP, gnomej?roperty2action_discard jtemp, GNOME_PROPERTY_ACTION_CHANGED
GnomeRestartStyle
GNOME RESTARTIF RUNNING, GNOME_RESTART_ANYWAY, GNOME^RESTART^IMMEDIATELY, GNOMEJRESTARTJiEVER
GnomeSaveStyle
GNOMESAVEGLOBAL, GNOME_SAVE_LOCAL, GNOME_SAVE_BOTH
GnomeStockPixmapTypo
GNOME_STOCK_PIXMAP_TYPE_NONE, GNOME STOCK_PIXMAP_TYPE_DATA, GNOME_STOCK_PIXMAP_TYPE_FILE, GNOME_STOCK_PIXMAP_TYPE_PATH, GNOME_STOCK PIXMAP_TYPE_WIDGET, GNOME^STOCK_PIXMAP_TYPE_IMLIB, GNOME_STOCK_PIXMAP_TYPE_IMLIB_SCALED, - GNOME_STOCK_PIXMAP_TYPE__GPIXMAP
GnomeUIInfo-
GNOME APP_CONFIGURABLE_ITEM_NEW,
ConfigurableTypes
GNOME_APP_CONFIGURABLE_ITEM_OPEN, GNOMEAPP CONFIGURABLE_ITEM_SAVE, GNOME APP_CONFIGURABLE_ITEM_SAVE_AS, GNOME_APP_CONFIGDRABLE_ITEM_REVERT, GNOME_APP CONFIGURABLE_ITEM_PRINT, GNOME app"configurable_item_print_setup, gnomeJapp_configurable_item_close, GNOME APPCONFIGURABLE_ITEM_EXIT, GNOMS_APP_CONFIGURABLE_ITEM_CUT, GNOME_APP CONFIGURABLE_ITEM_COPY, gnome_app"configurable_item_paste, gnome_app_configurable_item_clear, GNOME APP_CONFIGURABLE_ITEM_UNDO, gnome"app_configurable_item_redo, GNOMEAPP CONFIGURABLE_ITEM_FIND, gnome_app”configurable_item_find_again, GNOME APP_CONFIGURABLE_ITEM_REPLACE, GNOME^APP^ CONFIGURABLE_ITEM_PROPERTIES, GNOME APP CONFIGURABLE_ITEM_PREFERENCES, GNOME" APP"CONFIGURABLE_ITEM_ABOUT, GNOME APP~CONFIGURABLE_ITEM_SELECT_ALL, GNOME APP_CONFIGURABLE_ITEM_NEW_WINDOW, gnome"app_configurable_item_close_window, GNOME_APP_CONFIGURABLE_ITEM_NEW_GAME, GNOME_APP_CONFIGURABLE__ITEM_PAUSE_GAME, ' GNOME_APP_CONFIGURABLE_ITEM_RESTART_GAME, GNOME_APP_CONFIGURABLE_ITEM_UNDO__MOVE, GNOME_AP?_CONFIGURABLE_ITEM_REDO_MOVE, gnomeJappJconfigurable_item_hint, GNOME_APP_CONFIGURABLE_ITEM_SCORES, GNOME APP CONFIGURABLE ITEM END GAME
Имя типа
Имена возможных значений
GnomeUIInfоТуре
GNOME__APP_UI ENDOFINFO, GNOME_APP_UI ITEM, GNOME_APP_UI TOGGLEITEM, GNOME J4>PJJI_RAD 10 ITEMS, GNOME_APP_UI SUBTREE, GNOME APP UT^SEPARATOR, gnome_app_uijielp, gnome appjjiJ^UILDER^DATA, GNOME_APP_UI_ITEM_CONFIGURABLE, * GNOME_APP_UI_SUBTREE_STOCK
GnomeUIPixmapType
GNOME_APP_PIXMAP_NONE, GNOME APP PIXM7^P_ST0CK, GNOME_APP_PIXMAP_DATA, GNOME APP^PI^^AP^FILENAME
GnomeWinAppState
WIN_APP_STATE_NONE, WIN_APP_STATE_ACTIVE1, WIN_APP_STATE_ACTIVE2, WIN jAP? STATE ERROR1, WIN_APP_STATE_ERR0R2, WIN_APP_STATE FATAL_ERR0R1, WIN_APP_STATE_FATAL ERR0R2, WIN APP^STATE_IDLE1, WIN_APP_STATE_IDLE27 WINJXPP_STATE_WAITING1, WIN_APP_STATE_WAITING2, WIN_APP STATE^WORKINGl, WIN_APP_STATEW0RKING2,"
WIN_APP_STATE_NEED_USER_INPUT1, win_app_state_need7user_input2, WIN_APP_STATE_STRUGGLING1, WIN_APP_STATE_STRUGGLING2, WIN_APP_STATE_DISK„TRAFFIC1, WIN_APP_STATE_DISK_TRAFFIC2,
WIN_APP_STATE_NETWORK_TRAFFIC1, WIN_APP_STATE_NETWORK TRAFFIC2, WIN_APP_STATE OVERLOADED1, WIN APE S7ATE_0VERL0ADED2, WIN_APP_STATE_PERCENTOOO 1,~
WIN_APP_STATE_PERCENT00072,
WIN_APP_STATE PERCENT0101, win_app_state7percentoio_2, WIN_APP_STATE_PERCENT020_l, WIN_APP_STATE_PERCENT020J2, WIN_APP_STATE_PERCENT030_l, WIN_APP_STATE_PERCENT030 2, WIN_APP_STATE__PERCENT04G_l, WIN_APP_STATE_PERCENT040 2, WIN_APP_STATE_PERCENT05071, WIN_APP_STATE_PERCENT050J2, WIN_APP_STATE_PERCENT060_1, WIN_APP_STATE_PERCENT060 2, WIN_APP_STATE_PERCENT070Jг WIN_APP_STATE_PERCENT070_2, WIN_APP_STATE_PERCENT080_1, WIN_APP_STATE_PERCENT080\2, WIN_APP_STATE PERCENT090 1, WIN-APP-STATE^PERCENT090^2, WIN_APP_STATE PERCENT100_l, WIN APP_STATE_PERCENT100_2
GnomeWinHints
WIN_HINTS_SKIP_FOCUS, WIN_HINTS SKIP WINLIST, WIN_HINTS_SKIP_TASKBAR, WIN_HINTS GROUP TRANSIENT, WIN_HINTS_FOCUS_ON_CLICK, WIN_H1NTS DOJiOT COVER
GnomeWinLayer
WIN_LAYER_DESKTOP, WIN_LAYER^BELOWf WIN LAYER^NORMAL, WIN_LAYER_ONTOP, WIN_LAYER_DOCK, WIN IAYER_ABOVE_DOCK
GnomeWinState
WIN_STATE_STICKY, WIN_STATE MINIMIZED,'
WIN_STATE_MAXIMIZED_VERT, WINSTATE MAXIMIZED_HORIZ,
WIN_STATE_HIDDEN, W7IN_STATE_SHADED,
WIN_STATE_HID_WORKSPACE, WIN_STATE_HID_TRANSIENT, WIN_STATE_FIXED_POSITION, WIN_STATE_ARRANGELIGNORE
Имя типа
Имена возможных значений
GtkAccelFlags
GTK ACCEL VISIBLE, GTK_ACCEL__SIGNAL_VISIBLE, GTK_ACCEL_LOCKED, GTKACCELMASK
GtkAnchorType
GTK_ANCHOR_CENTER, GTK_ANCHOR_NORTH, GTK_ANCHOR_NORTH_WEST, GTK_ANCHOR_NORTH_EAST, GTK_ANCHOR_SOUTH, GTK_ANCHOR_SOUTH_WEST, GTKANCHORSOUTHEAST, GTK_ANCHOR_WEST, GTK_ANCHOR_EAST, GTK_ANCHOR_N, GTK_ANCHOR_NW, GTKANCHORNE, GTKANCHORS, GTKANCHORJSW, GTK_ANCHOR_SE, GTK_ANCHOR_W, GTK_ANCHOR_E
GtkArgFlags
GTK_ARG_READABLE, GTK_ARG_WRITABLE, GTKARGCONSTRUCT, GTK_ARG_CONSTRUCT_ONLY, GTK_ARG_CHILD_ARG, GTKARGMASK, GTKARGREADWRITE
GtkArrowType
GTKARROWUP, GTK_ARROW_DOWN, GTK_ARROW_LEFT, GTKARROWRIGHT
GtkAttachOptions
GTK_EXPAND, GTKSHRINK, GTK_FILL
GtkButtonAction
GTKBUTTONIGNORED, GTKBUTTONSELECTS, GTKBUTTONDRAGS, GTK_BUTTON_EXPANDS
GtkButtonBoxStyle
GTK_BUTTONBOX_DEFAULT_STYLE, GTK_BUTTONBOX_SPREAD, GTK_BUTTONBOX_EDGE, GTK_BUTTONBOX_START, GTK_BUTTONBOX_END
GtkCListDragPos
GTKCLISTDRAGNONE, GTKCLISTDRAGBEFORE, GTK_CLIST_DRAG_INTO, GTK_CLIST_DRAG_AFTER
GtkCTreeExpanderStyle
GTK_CTREE_EXPANDER_NONE, GTK_CTREE_EXPANDER_SQUARE, GTK_CTREE_EXPANDER_TRIANGLE, GTK_CTREE_EXPANDER_CIRCULAR
GtkCTreeExpans ionType
GTK_CTREE_EXPANSION_EXPAND, GTK_CTREE_EXPANSION_EXPAND_RECURSIVE, GTK_CTREE_EXPANSION_COLLAPSE, GTK_CTREE_EXPANSION_COLLAPSE_RECURSIVE, GTK_CTREE_EXPANSION_TOGGLE, GTK_CTREE_EXPANSION_TOGGLE_RECURSIVE
GtkCTreeLineStyle
GTK_CTREE_LINES_NONE, GTK_CTREE_LINES_SOLID, GTK_CTREE_LINES_DOTTED, GTK_CTREE_LINES_TABBED
GtkCTreePos
GTK_CTREE_POS_BEFORE, GTK_CTREE_POS_AS_CHILD, GTK_CTREE_POS_AFTER
GtkCalendarDisplay
GTK_CALENDAR_SHOW_HEADING,
Options
GTK_CALENDAR_SHOW_DAY_NAMES, GTK_CALENDAR_NO_MONTH_CHANGE, GTK_CALENDAR_SHOW_WEEK_NUMBERS, GTK_CALENDAR_WEEK__START_MONDAY
GtkCellType
GTK_CELL_EMPTY, GTK_CELL_TEXT, GTK_CELL_PIXMAP, GTK_CELL_PIXTEXT, GTK_CELL_WIDGET
GtkClockType
GTK_CLOCK_INCREASING, GTK_CLOCK_DECREASING, GTK_CLOCK_REALTIME
GtkCornerType
GTK_CORNER_TOP_LEFT, GTK_CORNER_BOTTOM_LEFT, GTK_CORNER_TOP_RIGHT, GTK_CORNER_BOTTOM_RIGHT
GtkCurveType
GTK_CURVE_TYPE_LINEAR, GTK_CURVE_TYPE_SPLINE, GTK CURVE TYPE FREE
Имя типаИмена возможных значений
GtkDebugFlag. GTK_DEBUG_OBJECTS, GTK_DEBUG_MISC, GTK_DEBUG_SIGNALS,
GTK_DEBUG_DND, GTK_DEBUG_PLUGSOCKET
GtkDestDefaultsGTKDESTDEFAULTMOTION, GTK_DEST_DEFAULT_HIGHLIGHT,
GTK_DEST_DEFAULT_DROP, GTK_DEST_DEFAULT_ALL
GtkDirectionTypeGTKDIRTABFORWARD, GTKDIRTABBACKWARD, GTK_DIR_UP,
GTKDIRDOWN, GTK_DIR_LEFT, GTK_DIR_RIGHT
GtkFontFilterTypeGTK_FONT_FILTER_BASE, GTK_FONT_FILTER_USER
GtkFontMetricTypeGTK_FONT_METRIC_PIXELS, GTK_FONT_METRIC_POINTS
GtkFontTypeGTK_FONT_BITMAP, GTK_FONT_SCALABLE,
GTK_FONT_SCALABLE_BITMAP, GTK_FONT_ALL
GtkFundamentalTypeGtkFundamentalTypeGtkFundamentalTypeGTK_TYPE_INVALID, GTK_TYPE_NONE, GTKJTYPECHAR,
GtkFundamentalType
GtkFundamentalType
GTK_TYPE_UCHAR, GTKTYPEBOOL, GTK_TYPE_INT, GTK_TYPE_UINT, GTK_TYPE_LONG, GTK_TYPE_ULONG, GTK_TYPE_FLOAT, GTK_TYPE_DOUBLE, GTK_TYPE_STRING, GTK_TYPE_ENUM, GTK_TYPE_FLAGS, GTK_TYPE_BOXED, GTK_TYPE_POINTER, gtk_type_signal, gtk_type_args, GTK_TYPE_CALLBACK, GTK_TYPE_C_CALLBACK, GTKTYPEFOREIGN, GTKTYPEOBJECT
GtkJustificationGtkMatchTypeGtkMenuDirectionTypeGtkMenuFactoryTypeGtkMetricTypeGtkJustificationGtkMatchTypeGtkMenuDirectionTypeGtkMenuFactoryTypeGtkMetricTypeGTK_JUSTIFY_LEFT, GTK_JUSTIFY_RIGHT, GTK_JUSTIFY_CENTER, GTK_JUSTIFY_FILL GTK_MATCH_ALL, GTK_MATCH_ALL_TAIL, GTKMATCHHEAD, GTK_MATCH_TAIL, GTK_MATCH_EXACT, GTK_MATCH_LAST GTK_MENU_DIR_PARENT, GTK_MENU_DIR_CHILD, GTK_MENU_DIR_NEXT, GTK_MENU_DIR_PREV
GtkJustification
GtkMatchType
GtkMenuDirectionType
GtkMenuFactoryType
GtkMetricType
GtkJustification
GtkMatchType
GtkMenuDirectionType
GtkMenuFactoryType
GtkMetricType
GTK MENU_FACTORY_MENU, GTK_MENU_FACTORY_MENU_BAR, GTK_MENU_FACTORY_OPTION_MENU GTK_PIXELS, GTK_INCHES, GTK_CENTIMETERS
GtkObjectFlagsGTKDESTROYED, GTK_FLOATING, GTK_CONNECTED,
GTK CONSTRUCTED
GtkOrientationGTKORIENTATIONHORIZONTAL, GTKORIENTATIONVERTICAL
GtkPackTypeGTKPACKSTART, GTK_PACK_END
GtkPackerOptionsGTKPACKEXPAND, GTK_FILL_X, GTK_FILL_Y
GtkPathPriorityType GTKPATHPRIOLOWEST, GTKPATHPRIOGTK, GTK_PATH_PRIO_APPLICATION, GTK_PATH_PRIO_RC, GTK_PATH_PRIO_HIGHEST, GTK_PATH_PRIO_MASK
GtkPathTypeGTK_PATH_WIDGET, GTK_PATH_WIDGET_CLASS, GTK_PATH_CLASS
GtkPolicyTypeGTKPOLICYALWAYS, GTKPOLICYAUTOMATIC,
GTKPOLICYNEVER
GtkPositionTypeGTKPOSLEFT, GTKPOSRIGHT, GTKPOSTOP,
GTKPOSBOTTOM
GtkPreviewTypeGTKPREVIEWCOLOR, GTKPREVIEWGRAYSCALE
GtkPrivateFlagsPRIVATE_GTK_USER_STYLE, PRIVATE_GTK_REDRAW_PENDING,
PRIVATE_GTK_RESIZE_PENDING, PRIVATE_GTK_RESIZE_NEEDED, PRIVATE_GTK_LEAVE_PENDING, PRIVATE_GTK_HAS_SHAPE_MASK, PRIVATE_GTK_IN_REPARENT, PRIVATE_GTK_IS_OFFSCREEN
Имя типа
Имена возможных значений
GtkProgressBar
GTK
PROGRESSLEFTTORIGHT,
Orientation
GTK
PROGRESS_RIGHT_TO_LEFT,
GTK
PROGRESSBOTTOMTOTOP, GTK_PROGRESS_TOP_TO_BOTTOM
GtkProgressBarStyle
GTK
PROGRESS-CONTINUOUS, GTK_PROGRESS—DISCRETE
GtkRcFlags
GTK
_RC_FG, GTK_RC_BG, GTK_RC_TEXT, GTK_RC^BASE
GtkRcTokenType
GTK
RC_TOKEN_INVALID, GTK-RC_TOKEN_INCLUDE,
GTK
RCTOKENNORMAL, GTKRCTOKENACTIVE,
GTK
RC_TOKEN_PRELIGHT, GTK_RC_TOKEN_SELECTED,
GTK
RC_TOKEN_INSENSITIVE, GTKRC_TOKEN_FG,
GTK
RC_TOKEN_BG, GTK_RC_TOKEN_BASE, GTK_RC_TOKEN_TEXT,
GTK
RCTOKENFONT, GTK—RC_TOKEN_FONTSET,
GTK
RC_TOKEN_BG_PIXMAP, GTK_RC_TOKEN_PIXMAP_PATH,
GTK
RC_TOKEN_STYLE, GTK_RC_TOKEN_BINDING,
GTK
RC_TOKEN_BIND, GTK_RC_TOKEN_WIDGET,
GTK
RCTOKENWIDGETCLASS, GTK_RC_TOKEN_CLASS,
GTK
RC_TOKEN_LOWEST, GTK_RC_TOKEN_GTK,
GTK
RC_TOKEN_APPLICATION, GTKRCTOKENRC,
GTK
RC_TOKEli_HIGHEST, GTK_RC_TOKEN_ENGINE,
GTK
RC_TOKEN_MODULE_PATH, GTKRC_TOKEN_LAST
GtkReliefStyle
GTK
_RELIEF_NORMAL, GTK_RELIEF_HALF, GTK_RELIEF_NONE
GtkResizeMode
GTK
RESIZE_PARENT, GTK_RESIZE_QUEUE,
GTK
RESIZE_IMMEDIATE
GtkScrollType
GTK
SCROLLNONE, GTK_SCROLL_STEP_BACKWARD,
gtk"
"SCROLL_STEP_FORWARD, GTK_SCROLL_PAGE_BACKWARD,
gtk"
’SCROLLPAGEFORWARD, GTKSCROLLJUMP
GtkSelectionMode
GTK
SELECTION_SINGLE, GTK_SELECTION_BROWSE,
GTK*
*SELECTION_MULTIPLE, GTK_SELECTION_EXTENDED
GtkShadowType
GTK
SHADOW_NONE, GTK_SHADOW_IN, GTK_SHADOW_OUT,
GTK^
"SHADOW_ETCHED_IN, GTK_SHADOW_ETCHED_OUT
GtkSideType
GTK
SIDETOP, GTKSIDE-BOTTOM, GTK_SIDE-LEFT,
GTK^
"SIDE—RIGHT
GtkSignalRunType
GTK
RUN_FIRST, GTK—RUN—LAST, GTK-RUN-BOTH,
GTK^
"rUNNORECURSE, GTK-RUNACTION, GTKRUN-NO-HOOKS
GtkSortType -
GTK
SORT-ASCENDING, GTK_SORT_DESCENDING
GtkSpinButtonUpdate
GTK
_UPDATE_ALWAYS, Policy GTK_UPDATE_IF_VALID
GtkSpinType
GTK
SPIN-STEP_FORWARD, GTKSPINSTEPBACKWARD,
gtk"
"SPINPAGEFORWARD, GTK-SPINPAGE-BACKWARD,
gtk"
’SPIN_HOME, GTK-SPIN-END, GTK_SPIN_USER_DEFINED
GtkStateType
GTK
STATE-NORMAL, GTK—STATE_ACTIVE,
gtk"
"STATE_PRELIGHT, GTK_STATE_SELECTED,
gtk’
^STATE_INSENSITIVE .
GtkSubmenuDirection
GTK_
DIRECTION_LEFT, GTK_DIRECTION_RIGHT
GtkSubmenuPlacement
GTK_
TOPBOTTOM, GTK_LEFT_RIGHT
GtkTargetFl&gs
GTK
_TARGET_SAME_APP, GTK_TARGET_SAME-WIDGET
GtkToolbarChildType
GTK
TOOLBAR-CHILD_SPACE, GTK_TOOLBARCHILD_BUTTON,
gtk"
’toolbarchildtogglebutton,
gtk"
"toolbarchildradiobutton,
gtk"
"tOOLBARCHILD_WIDGET
Имя типа
Имена возможных значений
GtkToolbarSpaceStyle
GTK_TOOLBAR_SPACE_EMPTY, GTK_TOOLBAR_SPACE_LINE
GtkToolbarStyle
GTK_TOOLBAR_ICONS, GTK_TOOLBAR_TEXT, GTK_TOOLBAR_BOTH
GtkTreeViewMode
GTK_TREE_VIEW_LINE, GTK_TREE_VIEW_ITEM
GtkTroughType
GTK_TROUGH_NONE, GTKJTROUGHJSTART, GTK_TROUGH_END, GTK_TROUGH_JUMP
GtkUpdateType
GTK_UPDATE_CONTINUOUS, GTKJJPDATE-DISCONTINUOUS, GTK_UPDATE_DELAYED
GtkVisibility
GTK_VISIBILITY—NONE, GTK_VISIBILITY—PARTIAL, GTK_VISIBILITY_FULL
GtkWidgetFlags
GTK_TOPLEVEL, GTK_NO_WINDOW, GTK_REALIZED, GTK_MAPPED, GTK_VISIBLE, GTK^SENSITIVE, GTK_PARENT_SENSITIVE, GTK_CAN_FOCUS, GTKHASFOCUS, GTK_CAN_DEFAULT, GTK_HAS_DEFAULT, GTK_HAS_GRAB, GTK_RC_STYLE, GTK_COMPOSITE_CHILD, GTK_NO_REPARENT, GTK_APP_PAINTABLE, GTK_RECEIVES_DEFAULT
GtkWindowPosition
GTK_WIN_POS_NONE, GTK_WIN_POS_CENTER, GTK_WIN_POS_MOaSE
GtkWindowType
GTK_WINDOW_TOPLEVEL, GTK_WINDOW_DIALOG, GTK_WINDOW_POPUP
СигналыСигналы
Сигналы
Сигналы
Каждое событие, полученное от аппаратного устройства, является результатом какого-либо действия пользователя и способно сигнализировать приложению при помощи обращения к функции обратного вызова. В табл. F. 1 перечислены классы, которые имеют сигналы, наименования сигналов и прототипы соответствующих функций обратного вызова.
Все функции обратного вызова имеют, по крайней мере, два аргумента, но могут иметь и больше. Первым аргументом всегда является указатель на виджет, который выдал сигнал. Последним аргументом всегда является указатель, который прикладная программа передает функции для регистрации виджетом обратного вызова. Некоторые функции обратного вызова имеют другие аргументы, которые включаются между указателем на виджет и указателем на данные.
Таблица F.1. Сигналы и их прототипы обратных вызовов
Наименование сигнала
Имя
Прототип обратного вызова
*abort_column_res ize *
GtkCList
void cb(GtkWidget *, gpointer)
"activate"
GtkEditable
void cb(GtkWidget *, gpointer)
"activate"
GtkMenuItem
void cb(GtkWidget *, gpointer)
"activate_current"
GtkMenuShell
void cb(GtkWidget *, gboolean,
gpointer)
"add"
GtkContainer
void cb(GtkWidget *, GtkWidget *,
gpointer)
"button_press_event"
GtkWidget
gboolean cb(GtkWidget *, GdkEvent
*, gpointer)
"button_release_event"
GtkWidget
gboolean cb(GtkWidget *, GdkEvent
*, gpointer)
"cancel"
GtkMenuShell
void cb(GtkWidget *, gpointer)
"change_focus_row_
GtkCTree
void cb(GtkWidget *,
expansion"
GtkCTreeExpansion Type,
gpointer)
"changed"
GtkAdjustment
void cb(GtkWidget *, gpointer)
"changed"
GtkEditable
void cb(GtkWidget *, gpointer)
"check_resize"
GtkContainer
void cb(GtkWidget *, gpointer)
"child_detached"
GtkHandleBox
void cb(GtkWidget *, GtkWidget *, gpointer)
"click_column"
GtkCList
void cb(GtkWidget *, gint, gpointer),
Наименование сигнала
Имя
Прототип обратного вызова
"clicked*
GtkButton
void cb(GtkWidget *, gpointer)
"client event"
GtkWidget
gboolean cb(GtkWidget *, GdkEvent *, gpointer)
"collapse"
GtkTreeltem
void cb(GtkWidget *, gpointer)
"color_changed"
GtkColorSelection
void cb(GtkWidget *, gpointer)
"configureevent"
GtkWidget
gboolean cb(GtkWidget *, GdkEvent *, gpointer)
"copy_c1ipboard"
GtkEditable
void cb(GtkWidget *, gpointer)
"curve typechanged"
GtkCurve
void cb(GtkWidget *, gpointer)
"cut_clipboard"
GtkEditable
void cb(GtkWidget *, gpointer)
"deactivate"
GtkMenuShell
void cb(GtkWidget *, gpointer)
"debugmsg"
GtkWidget
void cb(GtkWidget *, gchar *, gpointer)
"delete_event"
GtkWidget
gboolean cb(GtkWidget *, GdkEvent *, gpointer)
"delete_text"
GtkEditable
void cb(GtkWidget *, gint, gint, gpointer)
"deselect"
Gtkltem
void cb(GtkWidget *, gpointer)
"destroy"
GtkOb ject'
void cb(GtkWidget *, gpointer)
"destroyevent"
GtkWidget
gboolean cb(GtkWidget *, GdkEvent *, gpointer)
"disable_device"
GtklnputDialog
void cb(GtkWidget *, gint, gpointer)
"disconnect"
GtkData
void cb(GtkWidget *, gpointer)
"dock detach"
GnomeDockltem
void cb(GtkWidget *, gpointer)
"dockdragbegin"
GnomeDockltem
void cb(GtkWidget *, gpointer)
"dock_drag_end"
GnomeDockltem
void cb(GtkWidget *, gpointer)
"dockdragmotion"
GnomeDockltem
void cb(GtkWidget *, gint, gint, gpointer)
"drag_begin"
GtkWidget
void cb(GtkWidget *, GdkDragContext ♦, gpointer)
"drag datadelete"
GtkWidget
void cb(GtkWidget *, GdkDragContext *, gpointer)
"drag_data_get"
GtkWidget
void cb(GtkWidget *, GdkDragContext *, GtkSelectionData *, guint, guint, gpointer)
"drag_data_received"
GtkWidget
void cb(GtkWidget *, GdkDragContext *, gint, gint, GtkSelectionData *, guint, guint, gpointer)
"drag_drop"
GtkWidget
gboolean cb{GtkWidget *, GdkDragContext *, gint, gint, guint, gpointer)
Наименование сигнала
Имя
Прототип обратного вызова
"drag-end"
GtkWidget
void cb(GtkWidget *, GdkDragContext *, gpointer)
"drag-leave"
GtkWidget
void cb(GtkWidget *, GdkDragContext *, gpointer)
"drag_motion"
GtkWidget
gboolean cb(GtkWidget *, GdkDragContext *, gint, gint, guint, gpointer)
"draw"
GtkWidget
void cb(GtkWidget *, gpointer, gpointer)
Hdraw_default”
GtkWidget
void cb(GtkWidget *, gpointer)
"draw_focus"
GtkWidget
void cb(GtkWidget *, gpointer)
"editing started"
GnomelconTextltem
void cb(GtkWidget *, gpointer)
"editing_stopped"
GnomelconTextltem
void cb(GtkWidget *, gpointer)
"enable_device"
GtklnputDialog
void cb(GtkWidget *, gint, gpointer)
"end_selection"
GtkCList
void cb(GtkWidget *, gpointer)
"end_selection"
GtkListltem
void cb(GtkWidget *, gpointer)
"enter"
GtkButton
void cb(GtkWidget *, gpointer)
"enter_notify_event"
GtkWidget
gboolean cb(GtkWidget *, GdkEvent *, gpointer)
"event"
GtkWidget
gboolean cb(GtkWidget *, GdkEvent *, gpointer)
"expand"
GtkTreeltem
void cb(GtkWidget *, gpointer)
"expose_event"
GtkWidget
gboolean cb(GtkWidget *, GdkEvent *, gpointer)
"extendselection"
GtkCList
void cb(GtkWidget *, GtkScrollType, gfloat, gboolean, gpointer)
"extend_selection"
GtkListltem
void cb(GtkWidget *, gint, gfloat, gboolean, gpointer)
"focus"
GtkContainer
gint cb(GtkWidget *, GtkDirectionType, GtkDirectionType, gpointer)
"focusinevent"
GtkWidget
gboolean cb(GtkWidget *, GdkEvent *, gpointer)
"focus_out_event"
GtkWidget
gboolean cb(GtkWidget *, GdkEvent *, gpointer)
"grab focus"
GtkWidget
void cb(GtkWidget *, gpointer)
"height_changed"
GnomelconTextltem
void cb(GtkWidget *, gpointer)
"hide"
GtkWidget
void cb(GtkWidget *, gpointer)
"input"
GtkSpinButton
void cb(GtkWidget *, gpointer, gpointer)
"insert_text"
GtkEditable
void cb(GtkWidget *, gchar *, gint, gpointer, gpointer)
Наименование сигнала
Имя
Прототип обратного вызова
"кеу_pres s_event"
GtkWidget
gboolean cb(GtkWidget *, GdkEvent *, gpointer)
"key_release_event"
GtkWidget
gboolean cb(GtkWidget *, GdkEvent *, gpointer)
"kill_char"
GtkEditable
void cb(GtkWidget *, gint, gpointer)
"kill_line"
GtkEditable
void cb(GtkWidget *, gint, gpointer)
"kill-Word"
GtkEditable
void cb(GtkWidget *, gint, gpointer)
"layout-Changed"
GnomeDock
void cb(GtkWidget *, gpointer)
"leave"
GtkButton
void cb(GtkWidget *, gpointer)
"leave_notify_event"
GtkWidget
gboolean cb(GtkWidget *, GdkEvent ♦, gpointer)
"map"
GtkWidget
void cb(GtkWidget *, gpointer)
"map-event"
GtkWidget
gboolean cb(GtkWidget *, GdkEvent *, gpointer)
"motion_notify-event"
GtkWidget
gboolean cb(GtkWidget *, GdkEvent *, gpointer)
"move-Current"
GtkMenuShell
void cb(GtkWidget *,*
GtkMenuDirectionType, gpointer)
"move-Cursor"
GtkEditable
void cb(GtkWidget *, gint, gint, gpointer)
"move_page"
GtkEditable
void cb(GtkWidget *, gint, gint, gpointer)
"move_to_column"
GtkEditable
void cb(GtkWidget *,
gint, gint, gpointer)
"move_to_row"
GtkEditable
void cb(GtkWidget *, gint, gpointer)
"move-Word"
GtkEditable
void cb(GtkWidget *, gint, gpointer)
"nO-expose_event"
GtkWidget
gboolean cb(GtkWidget *, GdkEvent *, gpointer)
"orientation-Changed"
GtkToolbar
void cb(GtkWidget *, gint, gpointer)
"output"
GtkSpinButton
gboolean cb(GtkWidget *, gpointer)
"parent_set"
GtkWidget
void cb(GtkWidget *, GtkObject ♦, gpointer)
"paste-dipboard"
GtkEditable
void cb(GtkWidget *, gpointer)
"pressed"
GtkButton
void cb(GtkWidget *, gpointer)
"property-notify_event"
GtkWidget
gboolean cb(GtkWidget *, GdkEvent *, gpointer)
"proximity_in-event"
GtkWidget
gboolean cb(GtkWidget *,
GdkWidget *, gpointer)
Наименование сигнала
Имя .
Прототип обратного вызова
"proximity-Out-event"
GtkWidget
gboolean cb(GtkWidget *, GdkEvent *, gpointer)
"realize"
GtkWidget
void cb(GtkWidget *, gpointer)
"released"
GtkButton
void cb(GtkWidget *, gpointer)
"remove"
GtkContainer
void cb(GtkWidget *, GtkWidget *, gpointer)
"resize_column"
GtkCList
void cb(GtkWidget *, gint, gint, gpointer)
"row_move"
GtkCList
void cb(GtkWidget *, gint, gint, gpointer)
"scroll_horizontal"
GtkCList
void cb(GtkWidget *, GtkScrollType, gfloat, gpointer)
"scroll-horizontal"
GtkListltem
void cb(GtkWidget *, gint, gfloat, gpointer)
"scroll_vertical"
GtkCList
void cb(GtkWidget *, GtkScrollType, gfloat, gpointer)
"scroll_vertical"
GtkListltem
void cb(GtkWidget *, gint, gfloat, gpointer)
"select"
Gtkltem
void cb(GtkWidget *, gpointer)
"select_all"
GtkCList
void cb(GtkWidget ♦, gpointer)
"select_all"
GtkListltem
void cb(GtkWidget *, gpointer)
"select_child"
GtkList
void cb(GtkWidget *, GtkWidget *, gpointer)
"select_child"
GtkTree
void cb(GtkWidget *, GtkWidget *, gpointer)
"select_icon"
GnomelconList
void cb(GtkWidget *, gint, GdkEvent *, gpointer)
"select_row"
GtkCList
void cb(GtkWidget *, gint, gint, GdkEvent *, gpointer)
"selectionchanged"
GtkList
void cb(GtkWidget *, gpointer)
"selection_changed"
GtkTree
void cb(GtkWidget *, gpointer)
"selection_clear_event"
GtkWidget
gboolean cb(GtkWidget *, GdkEvent *, gpointer)
"selection_get"
GtkWidget
void cb(GtkWidget *, GtkSelectionData *, guint, guint, gpointer)
"selection_notify_event"
GtkWidget
gboolean cb(GtkWidget *, GdkEvent *, gpointer)
"selection_received"
GtkWidget
void cb(GtkWidget *, GtkSelectionData *, gpointer)
"selection_request_event
"GtkWidget
gboolean cb(GtkWidget *, GdkEvent *, gpointer)
"selection_started"
GnomelconTextltem
void cb(GtkWidget *, gpointer)
"selection_stopped"
GnomelconTextltem
void cb(GtkWidget *, gpointer)
"selection-done"
GtkMenuShell
void cb(GtkWidget *, gpointer)
Наименование сигнала
Имя
Прототип обратного вызова
"set_focus"
GtkWindow
void cb(GtkWidget *, GtkWidget *, gpointer)
*set_scroll_adjustments*
GtkCList
void cb(GtkWidget ♦,
GtkAdjustment *, GtkAdjustment *, gpointer)
"set_scroll_adjustments*
GtkLayout
void cb(GtkWidget *,
GtkAdjustment *, GtkAdjustment *, gpointer)
"set_scroll_adjustments*
GtkText
void cb(GtkWidget ♦, GtkTypeAdjustment *, GtkTypeAdjustment *, gpointer)
"set_scroll_adjustments"
GtkViewport
void cb(GtkWidget *,
GtkAdjustment *, GtkAdjustment *, gpointer)
"set-editable"
GtkEditable
void cb(GtkWidget *, gboolean, gpointer)
"set-focus-child"
GtkContainer
void cb(GtkWidget *, GtkWidget *, gpointer)
"show”
GtkWidget
void cb(GtkWidget *, gpointer)
"size_allocate"
GtkWidget
void cb(GtkWidget ♦, gpointer, gpointer)
"size_request"
GtkWidget
void cb(GtkWidget *, gpointer, gpointer)
"start_query"
GtkTipsQuery
void cb(GtkWidget ♦, gpointer)
"start_selection"
GtkCList
void cb(GtkWidget *, gpointer)
"start_selection"
GtkListltem
void cb(GtkWidget *, gpointer)
"state_changed"
GtkWidget
void cb(GtkWidget *, GtkStateType, gpointer)
"stop_query"
GtkTipsQuery
void cb(GtkWidget *, gpointer)
"style_changed"
GtkToolbar
void cb(GtkWidget *, gint, gpointer)
”style_set"
GtkWidget
void cb(GtkWidget *, GtkStyle *, gpointer)
"switch_page"
GtkNotebook
void cb(GtkWidget *, gpointer, guint, gpointer)
"text-Changed"
GnomelconTextltem
gboolean cb(GtkWidget ♦, gpointer)
"textpopped"
GtkStatusbar
void cb(GtkWidget *, guint, gchar *, gpointer)
"text-pushed"
GtkStatusbar
void cb(GtkWidget *, guint, gchar *, gpointer)
"toggle"
Gtkltem
void cb(GtkWidget ♦, gpointer)
"toggle-add_mode"
GtkCList
void cb(GtkWidget *, gpointer)
"toggle-add-mode"
GtkListltem
void cb(GtkWidget *, gpointer)
"toggle_focus_row"
GtkCList
void cb(GtkWidget ♦, gpointer)
"toggle-focus_row"
GtkListltem
void cb(GtkWidget *, gpointer)
Наименование сигнала
Имя
Прототип обратного вызова
"toggled"•
GtkCheckMenuItem
void cb(GtkWidget *, gpointer)
"toggled"
GtkToggleButton
void cb(GtkWidget *, gpointer)
"tree_collapse"
GtkCTree
void cb(GtkWidget *, GtkCTreeNode *, gpointer)
"tree_expand"
GtkCTree
void cb(GtkWidget ♦, GtkCTreeNode *, gpointer)
"tree_move"
GtkCTree
void cb(GtkWidget *, GtkCTreeNode *, GtkCTreeNode *, GtkCTreeNode ♦, gpointer)
"treeselectrow"
GtkCTree
void cb(GtkWidget *, GtkCTreeNode *, gint, gpointer)
"tree_unselect_row"
GtkCTree
void cb(GtkWidget *, ' GtkCTreeNode, gint, gpointer)
"undo_selection"
GtkCList
void cb(GtkWidget *, gpointer)
"undo_selection"
GtkListltem
void cb(GtkWidget *, gpointer)
"unmap"
GtkWidget
void cb(GtkWidget *, gpointer)
"unmap_event"
GtkWidget
gboolean cb(GtkWidget *, GtkEvent*, gpointer)
"unrealize"
GtkWidget
void cb(GtkWidget *, gpointer)
"unselect_all" '
GtkCList
void cb(GtkWidget *, gpointer)
"unselect_all"
GtkListltem
void cb(GtkWidget *, gpointer)
"unselect_child"
GtkList
void cb(GtkWidget *, GtkWidget ♦, gpointer)
"unselect_child"
GtkTree
void cb(GtkWidget *, GtkWidget *, gpointer)
"unselect_icon"
GnomelconList
void cb(GtkWidget *, gint, GdkEvent *, gpointer)
"unselect_row"
GtkCList
void cb(GtkWidget *, gint, gint, GdkEvent *, gpointer)
"value-Changed"
GtkAdjustment
void cb(GtkWidget *, gpointer)
"visibility-notify_ event"
GtkWidget
gboolean cb(GtkWidget *, GdkEvent *, gpointer)
"widget_entered"
GtkTipsQuery
void cb(GtkWidget *, GtkWidget *, gchar *, gchar *, gpointer)
"widget_selected"
GtkTipsQuery
gboolean cb(GtkWidget *, GdkWdiget *, gchar *, gchar *, GdkEvent *, gpointer)
"width-Changed"
GnomelconTextltem
void cb(GtkWidget *, gpointer)
ПРИЛОЖЕНИЕПРИЛОЖЕНИЕФункции по типу возвращаемого значения
ПРИЛОЖЕНИЕ
ПРИЛОЖЕНИЕ
В настоящем приложении перечислены все типы данных и функции, которые возвращают данный тип (или указатели на данный тип). Базовые типы (int, gint, gboolean, guint32 и т.д.) в перечень не входят.
GdkAtom
gdk_atom_intern(const gchar *atom_name, gint onlyifexists)
gdk_drag_get_selection(GdkDragContext *context)
GdkBitmap ♦
gdk_bitmap_ref(GdkBitmap *bitmap)
GdkColor *
gdk_color_copy(GdkColor *color)
GdkColorContext *
gdk_color context _new(GdkVisual *visual, GdkColormap *colormap)
gdk_color_context_new_mono(GdkVisual *visual, GdkColormap *colormap)
GdkColormap *
gdk_colormap_get system(void)
gdk_colormap_lookup(Colormap xcolormap)
gdk_colormap_new(GdkVisual *visual, gint privatecmap)
gdk colormap ref(GdkColormap *cmap)
gdk_rgb_get_cmap(void)
gdkwindow get colormap(GdkWindow *window)
gdkx_colormap_get(Colormap xcolormap)
gtk_preview__get_cmap (void)
gtk_widget_get_colormap(GtkWidget *widget)
gtk_widget_get_default_colormap(void)
GdkCursor *-
gdk_cursor_new(GdkCursorType cursor_type)
gdk_cursor_new_from_pixmap(GdkPixmap *source, GdkPixmap *mask, GdkColor
*fg, GdkColor *bg, gint x, gint y)
GdkDragContext *
gdk_drag_begin(GdkWindow *window, GList *targets) gdk_drag_context_new(void) gtk_drag_begin(GtkWidget *widget, GtkTargetList *target_list, GdkDragAction actions, gint button, GdkEvent *event)
GdkEvent ♦
gdk_event_copy(GdkEvent *event)
gdk_event_get(void)•
gdk_event_get_graphics_expose(GdkWindow *window) gdk_event_peek(void) gtk_get_currentevent(void)
GdkEventMask
gdk_ic_get_events(GdkIC *ic)
gdk_window_get_events(GdkWindow *window)
GdkExtensionMode
gtk_widget_get_extension events(GtkWidget *widget)
GdkFilterReturn
gdk_wm_protocols_filter(GdkXEvent *xev, GdkEvent *event, gpointer data) motif_dnd_filter(GdkXEvent *xev, GdkEvent ♦event, gpointer data) motif drag status(GdkEvent *event, guintl6 flags, guint32 timestamp) motif dragwindow filter(GdkXEvent *xevent, GdkEvent *event, gpointer data) motif_drop_start(GdkEvent *event, guintl6 flags, guint32 timestamp, guint32 sourcewindow, guint32 atom, gintl6 xroot, gintl6 y_root)
motif_motion(GdkEvent *event, guintl6 flags, guint32 timestamp, gintl6 xroot, gint16 yroot)
motif_operation changed(GdkEvent *event, guintl6 flags, guint32 timestamp) motif_top_level_leave(GdkEvent *event, guintl6 flags, guint32 timestamp)
GdkFont ♦
gdk_font_load(const gchar *font-Пате)
gdkfontref(GdkFont *font)
gdkfontset_load(gchar *fontsetname)
gnome_font_picker_get_font(GnomeFontPicker *gfp)
gtk font selection dialog get font (GtkFontSelectionDialog *fsd)
gtk_font_selection_get_font(GtkFontSelection *fontsel)
GdkGC *'
gdk_gc_new(GdkWindow *window)
gdk_gc_new_with_values(GdkWindow *window, GdkGCValues *values, GdkGCValuesMask valuesmask)
gdkgcref(GdkGC *gc)
gtkgcget(gint depth, GdkColormap *colormap, GdkGCValues *values, GdkGCValuesMask values_mask)
GdkIC ♦
gdk_ic_new(GdkICAttr *attr, GdkICAttributesType mask)
GdkICAttr *
gdkicattr new(void)
GdkICAttributesType
gdkicgetattr(GdkIC *ic, GdkICAttr *attr, GdkICAttributesType mask)
gdk_ic_set_attr(GdkIC *ic, GdkICAttr *attr, GdkICAttributesType mask)
Gdklmage *
gdkimageget(GdkWindow *window, gint x, gint у, gint width, gint height)
gdk_image_new(GdkImageType type, GdkVisual *visual, gint width, gint height)
gdkimagenewbitmap(GdkVisual *visual, gpointer data, gint w, gint h)
GdklMliblmage *
gnome_canvas_load_alpha(char *file)
GdkIMStyle
gdkicgetstyle(GdkIC *ic)
gdkimdecidestyle(GdkIMStyle supportedstyle)
gdk_im_set_best_style(GdkIMStyle style)
GdkOverlapType
gdk_region_rect_in(GdkRegion *region, GdkRectangle *rect)
GdkPixmap *
gdk_bitmap_createfrom_data(GdkWindow *window, const gchar *data, gint width, gint height)
gdk_pixmap_colormap_create_from_xpm(GdkWindow *window, GdkColormap *colormap, GdkBitmap **mask, GdkColor *transparent_color, const gchar *filename)
gdk pixmapcolormapcreate from_xpm_d(GdkWindow *window, GdkColormap *colormap, GdkBitmap **mask,
GdkColor *transparent_color, gchar **data)
gdk_pixmap_create_from data(GdkWindow *window,
const gchar *data, gint width, gint height, gint depth, GdkColor *fg, GdkColor *bg)
gdk_pixmap_create_from_xpm(GdkWindow *window, GdkBitmap **mask, GdkColor
*transparent_color, const gchar *filename)
gdk_pixmap_create_from_xpm_d(GdkWindow *window, GdkBitmap **mask, GdkColor *transparent_color, gchar **data)
gdk_pixmap_foreign_new(guint32 anid)
gdk_pixmap_new(GdkWindow *window, gint width, gint height, gint depth)
gdk_pixmap_ref(GdkPixmap *pixmap) gtk_rc_load_image(GdkColormap *colormap, GdkColor *transparent_color, const gchar *filename)
GdkRegion *
gdk_region_new(void)
gdk_region polygon(GdkPoint *points, gint npoints, GdkFillRule fill_rule) gdk_region_union_with_rect(GdkRegion *region, GdkRectangle *rect) gdk regions intersect(GdkRegion *sourcel, GdkRegion *source2) gdkregions subtract(GdkRegion *sourcel, GdkRegion *source2) gdk_regions union(GdkRegion *sourcel, GdkRegion *source2) gdk_regions_xor(GdkRegion *sourcel, GdkRegion *source2)
GdkRgbCmap *
gdk_rgb_cmap_new(guint32 *colors, gint n_colors)
GdkTimeCoord *
gdk_input_motion_events(GdkWindow *window, guint32 deviceid, guint32 start, guint32 stop, gint *nevents return)
GdkVisual * gdkcolormapget visual(GdkColormap *colormap) gdkrgb getvisual(void) gdkvisualget best(void) gdk_visual_get_best_with_both(gint depth, GdkVisualType visual_type) gdk_visual_get_best_with_depth(gint depth) gdk_visual_get_best_with_type(GdkVisualType visual_type) gdk_visual_get_system(void) gdk_visual_lookup(Visual *xvisual) gdk_visual_ref(GdkVisual *visual) gdk_window_get_visual(GdkWindow *window) gdkxvisual get(VisuallD xvisualid) gtk_preview_get_visual(void) gtkwidget_get_default_visual(void) gtk_widget get visual(Gtkwidget *widget)
GdkVisualType
gdk_visual_get_best_type(void)
GdkWindow *
gdk_selection_owner_get(GdkAtom selection) gdk_window_at pointer(gint *win x, gint *win_y) gdkwindow foreign_new(guint32 anid) gdkwindowgetparent(GdkWindow *window) gdk window get pointer(GdkWindow *window, gint *x, gint *y, GdkModifierType *mask)
gdk_window_get toplevel(GdkWindow *window)
gdk_window_new(GdkWindow *parent, GdkWindowAttr *attributes, gint attributesmask)
gdk_window_ref(GdkWindow *window)
gtk_widget_get_parent_window(GtkWidget *widget)
GdkWindowType
gdk_window_get_type(GdkWindow *window)
GList *
gdk_input_list_devices(void)
gdk_list_visuals(void)
gdkwindow get children(GdkWindow *window)
gdk_window_get_toplevels(void)
gnome_history_get recently_used(void)
gnome_il8n_get_language_list(const gchar *category^name) gnome_mime_get_keys(const char *mime_type)
gnome_paper name 1ist(void) gnome_unit_name_list(void) gnome_uri_list_extract_filenames(const gchar *uri_list) gnome_uri_list_extract_uris(const gchar *uri_list) gnome_win_hints_get_client_window_ids(void) gnome_win_hints_get_workspace_names(void) gtk_container_children(GtkContainer *container) gtk_container_get_toplevels(void) gtk_ctree find_all_by_row_data(GtkCTree *ctree, GtkCTreeNode *node, gpointer data)
gtk ctreefind_all_by_row_data_custom(GtkCTree *ctree, GtkCTreeNode *node, gpointer data, GCompareFunc func)-
gtk_type_children_types(GtkType type)
GNode *
gtk_ctree_export_to_gnode(GtkCTree *ctree, GNode *parent, GNode *sibling, GtkCTreeNode *node, GtkCTreeGNodeFunc func,
gpointer data)
GnomeAnimatorLoopType
gnome_animator_get_loop_type(GnomeAnimator *animator)
GnomeAnimatorStatus
gnome_animator_get_status(GnomeAnimator *animator)
GnomeApp *
gnome_mdi_get_active_window(GnomeMDI *mdi) gnome_mdi_get_app_from_view(GtkWidget *view)
GnomeAppProgressKey
gnome_app_progress_manual(GnomeApp *арр, const gchar *description, GnomeAppProgressCancelFunc cancel_cb, gpointer data)
gnome_app_progress_timeout(GnomeApp *app, const gchar ^description, guint32 interval, GnomeAppProgressFunc percentage_cb, GnomeAppProgressCancelFunc cancel_cb, gpointer data)
GnomeCanvasGroup *
gnome_canvas_root(GnomeCanvas *canvas)
GnomeCanvasItem *
gnome_canvas_get_item_at(GnomeCanvas *canvas, double x, double y) gnome_canvas_item_new(GnomeCanvasGroup *parent, GtkType type, const gchar *first_arg_name, . . .)
gnome_canvas_item_newv(GnomeCanvasGroup *parent, GtkType type, guint nargs, GtkArg *args)
GnomeCanvasPoints *
gnome_canvas_points_new(int num_points)
gnome_canvas_points ref(GnomeCanvasPoints *points)
GnomeClient ♦
gnomeciient_new(void)
gnome_client_new_without_connection(void) gnome_cloned_client(void) gnome_master client(void)
GnomeClientFlags'
gnomeclient get_flags(GnomeClient *client)
GnomeDesktopEntry *
gnome_dentry_get_dentry(GnomeDEntryEdit *dee) gnome_desktop_entry_copy(GnomeDesktopEntry *source) gnome_desktop_entry load(const char *file) gnome_desktop_entry_load flags(const char *file, int cleanfrom_memory_after_load) gnome desktop_entry loadflags_conditional(const char *file, int clean_from_memory_after_load, int unconditional) gnomedesktop entry loadunconditional(const char *file)
GnomeDock *
gnome_app_get_dock(GnomeApp *app)
GnomeDockltem *
gnome_app_get_dock_item_by name(GnomeApp *app, const gchar *name) gnome_dock_band get_item_by_name(GnomeDockBand *band, const char *name, guint *position_return, guint *offset_return)
gnome_dock_get_item_by_name(GnomeDock *dock, const gchar *name, GnomeDockPlacement *placement_return,
guint *num_band_return, guint *band_position_return, guint *offset_return)
GnomeDockltemBehavior
gnome_dock_item_get_behavior(GnomeDockltem *dock_item)
GnomeDockLayout *
gnome_dock_get_layout(GnomeDock *dock)
gnomedocklayout new(void)
GnomeDockLayoutltem *
gnome_dock_layout_get_item(GnomeDockLayout *layout, GnomeDockltem *item) gnome_dock_layout_get_item_by_name(GnomeDockLayout *layout, const gchar *name)
GnomeFontPickerMode
gnome_font_picker_get_mode(GnomeFontPicker *gf p)
GnomelconTextlnfo *
gnome_icon_layout_text(GdkFont *font, char *text, char *separators, int max_width, int confine)
GnomeMagicEntry *
gnome_magic_parse(const gchar *filename, gint *nents)
GnomeMDIChild *
gnome_mdi_find_child(GnomeMDI *mdi, gchar *name) gnome_mdi_get_active_child(GnomeMDI *mdi) '
gnome_mdi_get_child_from_view(GtkWidget *view)
GnomeMDIGenericChild *
gnome_mdi_generic_child_new(gchar *name)
GnomeMDIMode
gnomepreferencesgetmdimode()
GnomePaper *
gnome_paper_with_name(const gchar *papername)
gnome_paper_with_size(const double pswidth, const double psheight)
GnomePlugin *
gnome_plugin_use(const char *plugin_id)
GnomePropertyObject *
gnomepropertyobjectnew (GnomePropertyDescriptor *descriptor, gpointer property dataptr)
GnomeRegexCache *
gnomeregexcachenew(void)
GnomeStockPixmapEntry *
gnomestock pixmap_checkfor(const char *icon, const char *subtype)
GnomeUIInfo *
gnome_mdi_get_child_menu_infо(GnomeApp *app) gnome_mdi_get_menubar_infо(GnomeApp *app) gnome_mdi_get_toolbar_infо(GnomeApp *app)
GnomeUnit *
gnome_unit_with_name(const gchar *unitname)
GnomeWinAppState
gnome_win_hints_get_app_state(GtkWidget *window)
GnomeWinHints
gnome_win_hints_get_hints(GtkWidget *window)
'GnomeWinLayer
gnome_win_hints_get_layer(GtkWidget *window)
GnomeWinState
gnome_win_hints_get_state(GtkWidget *window)
GSList *
gtk_accel_group_entries_from_object(GtkObject *object) gtk_accel_groups_from object(GtkObject *object) gtk_radio_button_group(GtkRadioButton *radio_button) gtk_radio_menu_item_group(GtkRadioMenuItem *radio_menu_item)
GtkAccelEntry *
gtkaccelgroupgetentry(GtkAccelGroup *accel_group, guint accel_key, GdkModifierType accelmods)
GtkAccelGroup *
gnome_popup_menu_get_accel_group(GtkMenu *menu) gtk_accel_group_get default(void) gtk accel groupnew(void)
gtk_accel_group_ref(GtkAccelGroup *accel_group) gtk_menu_ensure_uline_accel_group(GtkMenu *menu) gtk_menu_get_accel_group(GtkMenu *menu) gtk_menu_get_uline_accel_group(GtkMenu *menu)
GtkAdjustment *
gtk_clist_get_hadjustment(GtkCList *clist)
gtk_clist_get_vadjustment(GtkCList *clist) gtk_dial_get_adjustment(GtkDial *dial) gtk_layout_get_hadjustment(GtkLayout *layout)
gtk_layout_get_vadjustment(GtkLayout *layout)
gtk_range_get_adjustment(GtkRange *range)
gtk_scrolled_window_get_hadjustment (GtkScrolledWindow *scrolled_window) gtk_scrolled_window_get_vadjustment (GtkScrolledWindow *scrolled_window) gtk_spin_button_get_adjustment(GtkSpinButton *spinbutton)
gtk_viewport_get_hadjustment(GtkViewport *viewport) gtk_viewport_get_vadjustment(GtkViewport *viewport)
GtkArg *
gtk_arg_copy(GtkArg *src_arg, GtkArg *dest arg)
gtk_arg_new(GtkType arg^type)
gtk_args_query(GtkType class_type, GHashTable *arg_info hash table, guint32 **arg_flags, guint *n_args_p)
gtk_container_query_child_args(GtkType class_type, guint32 **arg_flags, guint *n_args)
gtk_object_query_args(GtkType class_type, guint32 **arg_flags, guint *n_args)
GtkArglnfo *
gtk_arg_type_new_static(GtkType base_class_type, const gchar *arg_name, guint class_n_args_offset, GHashTable *arg_info_hash table, GtkType arg_type, guint arg_flags, guint arg_id)
GtkBindingSet *
gtk_binding_set_by_class(gpointer objectclass)
gtk_binding_set_find(const gchar *set_name)
gtk_binding_set_new(const gchar *set_name)
GtkButtonBoxStyle
gnome_preferences_get_button_layout (void)
gtk_button_box_get_layout(GtkButtonBox *widget)
gtk_hbutton_box_get_layout_default(void) gtk_vbutton_box_get_layout_default(void)
GtkCellType
gtk_clist_get_cell_type(GtkCList *clist, gint row, gint column)
gtk_ctree_node_get_cell_type(GtkCTree *ctree, GtkCTreeNode *node, gint column)
GtkCTreeNode *
gtk_ctree_find_by_row_data(GtkCTree *ctree, GtkCTreeNode *node, gpointer data)
gtk_ctree_find_by_row_data_custom(GtkCTree *ctree, GtkCTreeNode *node, gpointer data, GCompareFunc func)
gtk_ctree_find_node_ptr(GtkCTree *ctree, GtkCTreeRow *ctree_row) gtk_ctree_insert_gnode(GtkCTree *ctree, GtkCTreeNode *parent, GtkCTreeNode *sibling, GNode *gnode,
GtkCTreeGNodeFunc func, gpointer data) gtk_ctree_insert_node(GtkCTree *ctree, GtkCTreeNode *parent, GtkCTreeNode *sibling, gchar *text[], guint8 spacing, GdkPixmap *pixmap_closed, GdkBitmap *mask_closed, GdkPixmap *pixmap_opened, GdkBitmap *mask_opened, gboolean is_leaf, gboolean expanded) gtk_ctree_last(GtkCTree *ctree, GtkCTreeNode *node) gtk_ctree_node_nth(GtkCTree *ctree, guint row)
GtkEnumValue *
gtk_type_enum_find_value(GtkType enum_type, const gchar *value_name) gtk_type_enum_get_values(GtkType enum_type)
GtkFlagValue *
gtk_type_flags_find_value(GtkType flagtype, const gchar *value_name) gtk_type_flags_get_values(GtkType flags_type)
GtkltemFactory *
gtk_item_factory_from_path(const gchar *path) gtk_item_factory_from_widget(GtkWidget *widget) gtk_item_factory_new(GtkType container_type, const gchar *path, GtkAccelGroup *accel_group)
GtkMenuFactory *
gtk_menu_factorynew(GtkMenuFactoryType type)
GtkMenuPath *
gtk_menu_factoryfind(GtkMenuFactory * factory, const char *path)
GtkObject *
gnome_dentry_edit_new(void) gnome_dentry_edit_new_notebook(GtkNotebook *notebook) gnome_mdi_new(gchar *appname, gchar *title) gtk_adjustment_new(gfloat value, gfloat lower, gfloat upper, gfloat step_increment, gfloat page-increment, gfloat pagesize) gtk_object_new(GtkType objecttype, const gchar *first_arg_name, . . .) gtk_object_newv(GtkType objecttype, guint nargs, GtkArg *args) gtk_xmhtml_parser_new()
GtkOrientation
gnomedock—band_get-Orientation(GnomeDockBand *band) gnome_dock_item_get_orientation(GnomeDockltem *dock_item)
GtkPositionType
gnomepreferencesgetmditabpos()
GtkPreviewInfo *
gtk_preview_get_infо(void)
GtkProgress *
gnome_appbar_get_progress(GnomeAppBar *ab)
GtkRcStyle *
gtk_rc_style_new(void)
GtkReliefStyle
gtk_button_get_relief(GtkButton *button)
gtk_toolbar_get_button_relief(GtkToolbar *toolbar)
GtkSelectionData *
gtk_selection_data_copy(GtkSelectionData *data)
GtkShadowType
gnome_dock_item_get_shadow_type(GnomeDockItem *dock_item)
GtkSignalQuery *
gtk_signal_query(guint signal_id)
GtkStyle *
gtk_clist_get_cell_style(GtkCList *clist, gint row, gint column) gtk__clist_get_row_style(GtkCList *clist, gint row) gtk_ctree_node_get_cell_style(GtkCTree *ctree, GtkCTreeNode *node, gint column)
gtk__ctree_node_get_row_style(GtkCTree *ctree, GtkCTreeNode *node) gtk_rc_get_style(GtkWidget *widget)
gtk_style_attach(GtkStyle *style, GdkWindow *window)
gtk_style_copy(GtkStyle *style)
gtk_style_new(void)
gtk_style_ref(GtkStyle *style)
gtk_widget_get_default_style(void)
gtk_widget_get_style(GtkWidget *widget)
GtkTargetList *
gtk_target_list_new(const GtkTargetEntry *targets, guint ntargets)
GtkThemeEngine *
gtk_theme_engine get(gchar *name)
GtkTooltips *
gtk_tooltips_new(void)
GtkTooltipsData *
gtk_tooltips_data_get(GtkWidget *widget)
GtkType
gnome_app_get_type(void) gnome_canvas_ellipse_get_type(void) gnome canvas get type(void) gnome canvas group gettype(void) gnome_canvas image get_type(void) gnome_canvas_item_get_type(void) gnomecanvas 1ine gettype(void) gnomecanvaspolygonget type(void) gnomecanvasre get_type(void) gnomecanvas_rect_get-type(void) gnomecanvaS-textgettype(void) gnomecanvas_widget_get-type(void) gnomeclientgettype(void) gnomecolorpickergettype(void) gnome_dock_bandget-type(void) gnomedockgettype(void) gnome_font_picker_get_type(void) gnome_icon_text_item_get-type(void) gtkaccel-labelgettype(void) gtkadjustmentgettype(void) gtk_alignment_get-type(void) gtkarroW-get-type(void) gtkaspectframegettype(void) gtk_binget_type(void) gtk_box_get_type(void) gtk_button_boX-get-type(void) gtkbuttongettype(void) gtk_calendar_get_type(void) gtk_check-button_get-type(void) gtk-Check_menu_item_get_type(void) gtk_clistget_type(void) gtk_container_child_type(GtkContainer *container) gtk_container_get_type(void) gtkctree-gettype(void) gtkcurvegettype(void) gtkdatagettype(void) gtk-dialoggettype(void) gtkeditableget_type(void) gtkentryget-type(void)
gtk_event_box_get_type(void) gtk_file_selection_get_type(void) gtk_fixed_get_type(void) gtk_font_selection_get_type() gtk_frame_get_type(void) gtk_hbox_get_type(void) gtk_hscale_get_type(void) gtk_hscrollbar_get_type(void) gtk_hseparator_get_type(void) gtk_identifier_get_type(void)'
gtk_image_get_type(void) gtk_input_dialog_get_type(void) gtk_invisible_get_type(void) gtk_item_factory_get_type(void) gtk_item_get_type(void) gtk_label_get_type(void) gtk_layout_get_type(void) gtk_list_get_type(void) gtk_list_item_get_type(void) gtk_menu_bar_get_type(void) gtk_menu_get_type(void) gtk_menu_item_get_type(void) gtk_menu_shell_get_type(void) gtk_misc_get_type(void) gtk_notebook_get_type(void) gtk_object_get_type(void) gtk_option_menu_get_type(void) gtk_packer_get_type(void) gtk_paned_get_type(void) gtk_pixmap_get_type(void) gtk_pixmap_menu_item_get_type(void) gtk_progress_bar_get_type(void) gtk_progress_get_type(void) gtk_radio_button_get_type(void) gtk_radio_menu_item_get_type(void) gtk^rangegettype(void) gtk_scale_get_type(void) gtk_scrollbar_get_type(void) gtk_scrolled_window_get_type(void) gtk_separator_get_type(void)
gtkspin buttongettype(void) gtk_table_get_type(void) gtk_tearoff_menu_item_get_type(void) gtk_text_get type(void) gtk_toggle_button_get_type(void) gtktooltips gettype(void) gtktreegettype(void) gtk_tree_item_get_type(void) gtk_type_from_name(const gchar *name) gtk_type_get_varargs_type(GtkType foreigntype) gtktypeparent(GtkType type) gtk_type_register_enum(const gchar *type_name, GtkEnumValue *values) gtk_type_register_flags(const gchar *type_name, GtkFlagValue *values) gtk_type_unique(GtkType parent_type, const GtkTypelnfo *type info) gtkvbox gettype(void) gtkviewport gettype(void) gtk_vscale_get_type(void) • gtkvscrollbargettype(void) gtk_vseparator_get_type(void) gtkwidgetgettype(void) gtk_window_get_type(void)
GtkTypeClass *
gtk_type_check_class_cast(GtkTypeClass *klass, GtkType casttype)
GtkTypeObject *
gtk_type_check_object_cast(GtkTypeObject *type object, GtkType cast_type)
GtkTypeQuery *
gtktypequery(GtkType type)
GtkVisibility
gnome_icon_list_icon_is_visible(GnomelconList *gil, int pos) gtk_clist_row_is_visible(GtkCList *clist, gint row) gtk_ctree_node_is_visible(GtkCTree *ctree, GtkCTreeNode *node)
GtkWidget *
gnome about_new(const gchar *title, const gchar *version, const gchar *copyright, const gchar **authors, const gchar *comments, const gchar *logo)
gnome_animator_new_with_size(guint width, guint height) gnome_app_error(GnomeApp *app, const gchar *error) gnome_app_find_menu_pos(GtkWidget *parent, gchar *path, gint *pos) gnomeappmessage(GnomeApp *app, const gchar *message)
gnome_app_new(gchar *appname, char *title) gnome_app_ok_cancel(GnomeApp *app, const gchar *message, GnomeReplyCallback callback, gpointer data)
gnome_app_ok_cancel_modal(GnomeApp *app, const gchar *message, GnomeReplyCallback callback, gpointer data)
gnome_app_question(GnomeApp *app, const gchar *question, GnomeReplyCallback callback, gpointer data)
gnome_app_question_modal(GnomeApp *app, const gchar *question, GnomeReplyCallback callback, gpointer data)
gnome_app_request_password(GnomeApp *app, const gchar *prompt, GnomeStringCallback callback, gpointer data)
gnome_app_request_string(GnomeApp *app, const gchar *prompt, GnomeStringCallback callback, gpointer data)
gnome_app_warning(GnomeApp *app, const gchar *warning) gnome_appbar_new(gboolean has_progress, gboolean hasstatus, GnomePreferencesType interactivity)
gnome_calculator_new(void) gnome_canvas_new(void) gnome_canvas_new_aa(void) gnome_color_picker_new(void) gnome_date_edit_new(time_t the time, int show time, int use_24_format) gnome_date_edit_new_flags(time_t the_time, GnomeDateEditFlags flags) gnome_dentry_get_comment_entry(GnomeDEntryEdit *dee) gnome_dentry_get_doc_entry(GnomeDEntryEdit *dee) gnome_dentry_get_exec_entry(GnomeDEntryEdit *dee) gnome_dentry_get_icon_entry(GnomeDEntryEdit *dee) gnome_dentry_get_name_entry(GnomeDEntryEdit *dee) gnome_dentry_get_tryexec entry(GnomeDEntryEdit *dee) gnome_dialog_new(const gchar *title, . . .) gnome_dialog_newv(const gchar *title, const gchar **buttons) gnome_dock_band_new(void) gnome_dock_get_client_area(GnomeDock *dock) gnome_dock_item_get_child(GnomeDockltem *item) gnome_dock_item_new(const gchar *name, GnomeDockltemBehavior behavior)
gnome_dock_new(void)
gnome_entry_gtk_entry(GnomeEntry *gentry) gnome_entry_new(const gchar *history_id) gnome_error_dialog(const gchar *error) gnome_error_dialog_parented(const gchar *error, GtkWindow *parent) gnome_file_entry_gnome_entry(GnomeFileEntry *fentry) gnome_file_entry_gtk_entry(GnomeFileEntry *fentry)
gnome_file_entry_new(char *history_id, char *browse_dialog_title)
gnome_font_picker_create_inside(GnomeFontPicker *gfp) gnome_font_picker_new(void) gnome_font_selector_new(void)
gnome guru_current_page(GnomeGuru *guru)
gnome_guru_new(const gchar *name, GtkWidget *graphic, GnomeDialog *dialog) gnome_href_new(const gchar *url, const gchar *label) gnome_icon_entry_gnome_entry(GnomelconEntry *ientry) gnome_icon_entry_gnome_file_entry(GnomelconEntry *ientry) gnome_icon_entry_gtk_entry(GnomelconEntry *ientry) gnome_icon_entry_new(char *history_id, char *browse_dialog_title) gnome_icon_list_new(guint icon_width, GtkAdjustment *adj, int flags) gnome_icon_list_new_flags(guint icon_width, GtkAdjustment *adj, int flags) gnome_icon_selection_new(void) gnomeles s_new(void) gnomemdichildaddview(GnomeMDIChild *mdi_child) gnome_mdi_get_active_view(GnomeMDI *mdi) gnome_mdi_get_view_from_window(GnomeMDI *mdi, GnomeApp *app) gnomemessagebox new(const gchar *message, const gchar *message_box_type,
gnome_message_box_newv(const gchar *message, const gchar *message boxtype, const gchar **buttons)
gnome_number_entry_gnome_entry(GnomeNumberEntry *nentry) gnome_number_entry_gtk_entry(GnomeNumberEntry *nentry) gnome_number_entry_new(char *history_id, char *calc_dialog_title) gnome_ok_cancel_dialog(const gchar *message, GnomeReplyCallback callback, gpointer data)
gnome_ok_cancel_dialog_modal(const gchar *message, GnomeReplyCallback callback, gpointer data)
gnomeokcancel dialog_modal_parented(const gchar *message, GnomeReplyCallback callback, gpointer data, GtkWindow *parent)
gnome_ok_cancel_dialog_parented(const gchar *message, GnomeReplyCallback callback, gpointer data, GtkWindow *parent)
gnome_ok_dialog(const gchar *message)
gnome_ok_dialog_parented(const gchar *message, GtkWindow *parent) gnome_paper_selector_new(void) gnomepixmapbutton(GtkWidget *pixmap, const char *text) gnome_pixmap_entry_gnome_entry(GnomePixmapEntry *pentry) gnome_pixmap_entry_gnome_fileentry(GnomePixmapEntry *pentry) gnome_pixmap_entry_gtk_entry(GnomePixmapEntry *pentry) gnome pixmap entry new(char *history id,
char *browse_dialog_title, int do_preview) gnome_pixmap_new_from_file(const char «filename) gnome_pixmap_new_from_file_at_size(const char «filename, int width, int height)
gnome_pixmap_new_from_gnome_pixmap(GnomePixmap *gpixmap_old) gnome_pixmap_new_from_imlib(Gdklmliblmage *im) gnome_pixmap_new_from_imlib_at_size(Gdklmliblmage «im, int width, int height)
gnome_pixmap_new_from_rgb_d(unsigned char «data, unsigned char «alpha, int rgb_width, int rgb_height)
gnome_pixmap_new_from_rgb_d_at_size(unsigned char «data, unsigned char «alpha, int rgb_width, int rgb_height, int width, int height)
gnome_pixmap_new_from_rgb_d_shaped(unsigned char «data, unsigned char «alpha, int rgb_width, int rgb_height, GdklmlibColor *shape_color)
gnome_pixmap_new_from_rgb_d_shaped_at_size (unsigned char «data, unsigned char «alpha, int rgb_width, int rgb_height, int width, int height, GdklmlibColor *shape_color)
gnome_pixmap_new_from_xpm_d(char « «xpm_data) gnome_pixmap_new_from_xpm_d_at_size(char **xpm_data, int width, int height) gnome_popup_menu_new(GnomeUIInfo «uiinfo) gnome_popup_menu_new_with_accelgroup(GnomeUIInfо «uiinfo, GtkAccelGroup «accelgroup) gnome_property_box_new(void) gnome_property_entry_colors(GnomePropertyObject «object, const gchar «label, gint num_colors, gint columns, gint «tablepos, GdkColor «colors, const gchar *texts[])
gnome_property_entry_font(GnomePropertyObject «object, const gchar «label, gchar **font_name_ptr, GdkFont ««fontptr) gnome_question_dialog(const gchar «question, GnomeReplyCallback callback, gpointer data) gnomequestion_dialog_modal(const gchar «question, GnomeReplyCallback callback, gpointer data) gnome_question_dialog_modal_parented(const gchar «question, GnomeReplyCallback callback, gpointer data, GtkWindow «parent) gnome_question_dialog_parented(const gchar «question, GnomeReplyCallback callback, gpointer data, GtkWindow «parent) gnome_request dialog(gboolean password, const gchar «prompt, const gchar *default_text, const guintl6 max_length, GnomeStringCallback callback, gpointer data, GtkWindow «parent) gnome_request_password_dialog(const gchar «prompt, GnomeStringCallback callback, gpointer data) gnome_request_password_dialog_parented(const gchar «prompt, GnomeStringCallback callback, gpointer data, GtkWindow «parent) gnome_request_string_dialog(const gchar «prompt, GnomeStringCallback callback, gpointer data)
gnome_request_string_dialog_parented(const gchar «prompt,
GnomeStringCallback callback, gpointer data, GtkWindow «parent) gnome_scores_new(guint n_scores, gchar *«names, gfloat «scores, time_t «times, guint clear) gnome_spell_new() gnome_stock__button (const char «type) gnome_stock_menu_item(const char «type, const char «text) gnome_stock_new(void) gnome_stock_new_with_icon(const char «icon) gnome_stock_or_ordinary_button(const char «type) gnome_stock_pixmap_widget(GtkWidget *window, const char «icon) gnome_stock_pixmap_widget_at_size(GtkWidget «window, const char «icon, guint width, guint height)
gnome_stock_pixmap_widget_new(GtkWidget «window, const char «icon) gnome_stock_transparent_window(const char «icon, const char *subtype) gnome_warning_dialog(const gchar «warning) gnome_warning_dialog_parented(const gchar «warning, GtkWindow «parent) gtk_accel_label_new(const gchar «string) gtk_alignment_new(gfloat xalign, gfloat yalign, gfloat xscale, gfloat yscale)
gtk_arrow_new(GtkArrowType arrow_type, GtkShadowType shadow_type) gtk_aspect_frame_new(const gchar «label, gfloat xalign, gfloat yalign, gfloat ratio, gint obey_child) gtk_button_new(void) gtk_button_new_with_label(const gchar «label) gtk_calendar_new(void) gtk_check_button_new(void) gtk_check_button_new_with_label(const gchar «label) gtk_check_menu_item_new(void) gtk_check_menu_item_new_with_label(const gchar «label) gtk_clist_get_column_widget(GtkCList «clist, gint column) gtk_clist_new(gint columns) gtk_clist_new_with_titles(gint columns, gchar «titles[]) gtk_clock_new(GtkClockType type) gtk_color_selection_dialog_new(const gchar «title) gtk_color_selection_new(void) gtk_combo_new(void) gtk_ctree_new(gint columns, gint tree__column)
gtk_ctree_new_with_titles(gint columns, gint tree_column, gchar *titles[]) gtk_curve_new(void)
gtk_dial_new(GtkAdjustment «adjustment) gtk_dialog_new(void)
gtk_drag_get_source_widget(GdkDragContext *context) gtkdrawing_area_new(void) gtk_entry_new(void) gtk_entry_new_with_max length(guint16 max) gtkeventbox new(void) gtkfile_selection_new(const gchar *title) gtkf ixednew(void) gtkfont_selection_dialog_new(const gchar *title) gtk_font_selection_new() gtk_frame_new(const gchar *label) gtk_gamma_curve_new(void) gtkgeteventwidget(GdkEvent *event) gtkgrabgetcurrent(void) gtk_handle_box_new(void) gtkhbox new(gboolean homogeneous, gint spacing) gtkhbuttonboxnew(void) gtkhpanednew(void) gtkhrulernew(void) gtk_hscale_new(GtkAdjustment *adjustment) gtk_hscrollbar_new(GtkAdjustment ♦adjustment) gtkhseparatornew(void) gtk_image_new(GdkImage *val, GdkBitmap *mask) gtk_input_dialog_new(void) gtkinvis ible_new(void)
gtk_item_factory get_item(GtkltemFactory *ifactory, const gchar *path) gtkitemfactory_get_item_by_action(GtkltemFactory *ifactory, guint action) gtk_item_factory_get_widget(GtkltemFactory *ifactory, const gchar *path) gtk item factory_get_widget_by_action (GtkltemFactory * ifactory, guint action)
gtk_label_new(const char *str)
gtk_layout_new(GtkAdjustment *hadjustment, GtkAdjustment *vadjustment) gtklistitemnew(void) gtk_list_item_new_with_label(const gchar *label) gtklistnew(void) gtk_menu_bar_new(void) gtkmenugetactive(GtkMenu *menu) gtk_menu_get_attach_widget(GtkMenu *menu) gtk_menu_itemnew(void) gtkmenuitemnewwithlabel(const gchar *label) gtkmenunew(void)
gtknotebookgetmenulabel(GtkNotebook *notebook, GtkWidget *child)
gtk_notebook_getnth_page(GtkNotebook *notebook, gint page_num) gtk_notebook_get_tab_label(GtkNotebook *notebook, GtkWidget *child) gtk_notebook_new(void) gtk_option_menu_get_menu(GtkOptionMenu *option_menu) gtk_option_menu_new(void) gtk_packer_new(void) gtk_pixmap_menu_item_new(void) gtk_pixmap_new(GdkPixmap *val, GdkBitmap *mask) gtk_plug_new(guint32 socket_id) gtk_preview_new(GtkPreviewType type) gtk_progres s_bar_new(void) gtk_progress_bar_new_with_adjustment (GtkAdjustment *adjustment) gtk_radio_button_new(GSList *group) gtk_radio_button_new_from_widget(GtkRadioButton *group) gtk_radio_button_new_with_label(GSList *group, const gchar *label) gtk_radio_button_new_with_label_from_widget (GtkRadioButton *group, const gchar *label)
gtk_radio_menu_item_new(GSList *group) gtk_radio_menu_item_new_with_label(GSList *group, const gchar *label) gtk_scrolled_window_new(GtkAdjustment *hadjustment, GtkAdjustment *vadjustment)
gtk_socket_new() gtk_spin_button_new(GtkAdjustment *adjustment, gfloat climb_rate, guint digits)
gtk_statusbar_new(void) gtk_table_new(guint rows, guint columns, gboolean homogeneous) gtk_tearoff_menu_item_new(void) gtk_ted_new(char *name) gtk_ted_new_layout(char *name, char *layout) gtk_text_new(GtkAdjustment *hadj, GtkAdjustment *vadj) gtk_tips_query_new(void) gtk_toggle_button_new(void) gtk_toggle_button_new_with_label(const gchar *label) gtk_toolbar_append_element(GtkToolbar *toolbar, GtkToolbarChildType type, GtkWidget *widget, const char *text, const char *tooltip_text, const char *tooltip_private_text, GtkWidget *icon, GtkSignalFunc callback, gpointer user_data) gtk_toolbar_append_item(GtkToolbar *toolbar, const char *text, const char *tooltiptext, const char *tooltip_private_text, GtkWidget *icon, GtkSignalFunc callback, gpointer user_data) gtk_toolbar_insert_element(GtkToolbar *toolbar, GtkToolbarChildType type, GtkWidget *widget, const char *text, const char *tooltip_text, const char *tooltip_private_text, GtkWidget *icon, GtkSignalFunc callback, gpointer user_data, gint position)
gtk_toolbar_insert_item(GtkToolbar *toolbar, const char *text, const char *tooltip_text, const char *tooltip_private_text, GtkWidget *icon, GtkSignalFunc callback, gpointer user_data, gint position)
gtk_toolbar_new(GtkOrientation orientation, GtkToolbarStyle style)
gtk_toolbar_prepend_element(GtkToolbar *toolbar, GtkToolbarChildType type, GtkWidget *widget, const char *text, const char *tooltip_text, const char *tooltip_private_text, GtkWidget *icon, GtkSignalFunc callback, gpointer user_data)
gtk_toolbar_prepend_item(GtkToolbar *toolbar, const char *text, const char *tooltip_text, const char *tooltip_private_text, GtkWidget *icon, GtkSignalFunc callback, gpointer user_data)
gtk_tree_item_new(void)
gtk_tree_item_new_with_label(gchar *label)
gtk_tree_new(void)
gtk_vbox_new(gboolean homogeneous, gint spacing)
gtk_vbutton_box_new(void)
gtk_viewport_new(GtkAdjustment *hadjustment, GtkAdjustment *vadjustment) gtk_vpaned_new(void) gtk_vruler_new(void)
gtk_vscale_new(GtkAdjustment *adjustment)
gtk_vscrollbar_new(GtkAdjustment *adjustment)
gtk_vseparator_new(void)
gtk_widget_get_ancestor(GtkWidget *widget, GtkType widget type)
gtk_widget_get_toplevel(GtkWidget *widget)
gtk_widget_new(GtkType widget_type,
const gchar *first_arg_name, . . .)
gtk_widget_newv(GtkType type, guint nargs, GtkArg *args)
gtk_window_new(GtkWindowType type)
gtk_xmhtml_new(void)
GtkWindowPosition
gnome_preferences_get_dialog position()
GtkWindowType
gnome_preferences_get dialog type()
poptContext
gnomelib_parse_args(int argc, char *argv[], int popt_flags)
regex_t *
gnome_regex_cache_compile(GnomeRegexCache *rxc, const char *pattern, int flags)
time_t
gnome date edit get date(GnomeDateEdit *gde)
Window
gdk_window_xid_at(Window base, gint bx, gint by, gint x, gint у, GList *excludes, gboolean excl_child)
gdk_window_xid_at_coords(gint x, gint у, GList *excludes, gboolean excl_child)
moti f_f ind_drag_window(gboolean create)
XmHTMLForm ♦
_XmHTMLFormAddInput(XmHTMLWidget html, String attributes) _XmHTMLFormAddSelect(XmHTMLWidgethtml, String attributes) _XmHTMLFormAddTextArea(XmHTMLWidget html, String attributes, String text)
Глоссарий
Эти термины вы можете встретить в документации по GNOME и GTK+.
арр Сокращение термина application.
applet Прикладная программа (апплет), подобная любому другому приложению GNOME, за исключением того, что ее главное окно совсем маленькое и отображается на панели, а не в виде свободно размещенного окна верхнего уровня.
application Программа пользовательского уровня, которая работает в специфическом окружении (в данном случае в окружении рабочего стола GNOME), не являясь неотъемлемой частью этого окружения.
arg Существуют значения, которые могут быть установлены внутри виджетов с помощью обращения к функции и передачи ей имени и значения arg (аргумента). Значения аргументов также могут быть получены по их именам.
base class Базовый класс используется только как предок другого класса. Например, класс GtkWidget наследует характеристики своего базового класса GtkObject.
bitmap Это pixmap, где предусмотрен один бит на пиксел.
callback Вы можете выдать объекту адрес функции, вызываемой для отчета по некоторому выполненному действию. Как правило, программа передает GNOME или утилите из библиотеки GTK+ адрес одной из ее собственных функций, а по результатам работы будет выполнен обратный вызов программы.
child Окна приложения располагаются в виде иерархического дерева. Любое окно, имеющее одно или несколько подокон, называется parent (родительским) окном; подокна называются child (дочерними) окнами.
class Каждый объект является членом какого-нибудь класса. Для всех полученных из него объектов класс содержит общую информацию. Например, каждый виджет GtkButton принадлежит классу GtkButtonClass. Этот класс содержит функции, которые вызываются для реагирования на действия мыши, потому что это характерно для всех кнопок. Виджет GtkCheckButton имеет свой собственный индикатор размера и свою установку промежутков в этом классе, поэтому, изменив их однажды, далее меняешь для всех образцов GtkCheckButton.
color map Карта цветности предназначена для установки соответствия между актуальными RGB-значениями и цветами, хранящимися в памяти дисплея. В зависимости от технических средств сохранение цветов осуществляется в разных формах, следовательно, цвет — это индекс в массиве карты цветности.
container Контейнер — это виджет, задача которого позиционирование, установка размеров и отображение одного или более виджетов, содержащихся в нем.
convenience function Функция, вызывающая другую функцию. Требует подмножество аргументов, которое, в свою очередь, необходимо более сложной функции; будучи вызванной, вставляет стандартные значения по умолчанию. Часто встречается в графическом программировании, так как там приходится иметь дело с множеством предполагаемых опций.
CVS Concurrent Version System — система параллельно действующих версий. Архив исходных кодов, который позволяет нескольким программистам одновременно (параллельно) работать над одним и тем же проектом. По возможности CVS автоматически объединяет изменения, сделанные одним программистом, с изменениями, сделанными другими программистами.
dialog box Окно, что отображает текст и/или графические данные и позволяет пользователю осуществлять ввод с помощью мыши, клавиатуры или того и другого. Выглядит подобно главному окну, в которое менеджер окон включает строку заголовка и средства управления.
DND Drag-and-drop (перетащить и бросить).
dpi Единицы измерения (в точках на дюйм) разрешения монитора: чем больше точек на дюйм, тем выше разрешение. В некоторых мониторах разрешения в горизонтальном и вертикальном направлениях могут быть различны.
ELF Extensible Executable and Linking Format — расширенный выполняемый (исполняемый) и компонуемый формат. Двоичный формат объектных файлов, создаваемых компилятором. Файлы этого типа совместно компонуются для получения двоичных выполняемых файлов. Причем, файлы этого формата могут храниться как в статических, так и в совместно используемых библиотеках.
gc см. graphics context — графический контекст.
GDK Библиотека функций, являющихся оболочками для функций Xlib; дает возможность использовать функции glib.
GIMP (GNU Image Manipulation Project). Это графический редактор, который написан с использованием GTK+. Адрес его Web-сайта — www.gimp.org.
glib Коллекция функций и определений, которые используются при разработке приложений GDK и GTK+. Первоначально эта библиотека была создана для внедрения GIMP.
GNOME GNU Network Object Model Environment. Графический интерфейс пользователя, возведенный над GTK+.
GNU (GNU’s Not UNIX) Рекурсивный акроним, который означает — GNU не UNIX. Это название организации, находящейся на переднем плане движения за открытый исходный код программного обеспечения. Одним из ее достижений является общедоступная лицензия на программное обеспечение (GPL).
GPL (GNU Public License) Общедоступная лицензия GNU.
graphics contex Графический контекст определяет цвет, метод и шаблон заполнения, а также другие детали графических операций-
GTK+ (GIMP Toolkit) Общедоступная библиотека графического интерфейса пользователя для системы X Window, похожая на Motif. Состоит из объектов, написанных на С. Знак плюс к ее названию был добавлен после того, как GTK была модифицирована для использования механизма обратных вызовов и возможности наследования характеристик одного виджета другим.
GTK- Библиотека оболочек, написанных на C++, для классов GTK+.
GUI Graphic User Interface — графический интерфейс пользователя, или графический пользовательский интерфейс.
hint Менеджер окон отвечает за позиционирование и размеры всех окон. Любой запрос от приложения к менеджеру окон с требованием определенного размера и положения предполагает hint (совет, или всплывающую подсказку), так как запрос не всегда может быть удовлетворен из-за конфликтов с окнами, неизвестными приложению.
homogeneous Группа виджетов является homogeneous (гомогенной, или однородной), если контейнер отображает каждый из них одинаковой ширины, высоты или того и другого.
П8п Сокращение английского слова internationalization, означающего интернационализацию, число 18 в этой аббревиатуре указывает, что между первой буквой (i) и последней (п) находится 18 букв.
idle function Функция, что выполняется в период простоя, во время которого в противном случае (не будь этой функции) приложение ожидало бы поступлений из очереди событий.
inherit Когда на базе некоторого класса создается новый класс, то последний получает доступ ко всем ресурсам существующего виджета, чтобы наследовать (inherit) существующий виджет.
internationalization Создание программного обеспечения, отвечающего его локали (locale). Этот процесс может просто заключаться в изменении форматов даты и символа денежной единицы, а может требовать перевода всех кнопок, меню, подсказок и другого текста, выводимого приложением. Интернационализацию (internationalization) также называют И8п.
locale Формат времени и даты, символ денежной единицы, числовой формат и набор символов для указанного региона. Интернациональная программа может предоставлять возможность переключения между локалями.
MDI Multiple Document Interface — интерфейс для работы с несколькими документами. Единственное окно содержит набор подокон, между которыми вы можете переключаться. Другими словами, может отображаться любое из подокон набора.
MIME Multipurpose Internet Mail Extensions — многоцелевые почтовые расширения имен файлов в сети Internet. Метод, с помощью которого данные могут быть закодированы в форму, легко передаваемую через Internet или другое соединение, и декодированы получателем в исходный вид. Предназначен для поддержки подключений к электронной почте, но используется и с другими целями, например, в операциях drag-and-drop.
Multiple Document Interface см. MDI.
Modal Выводимое модальное (Modal) окно препятствует доступу с помощью мыши или клавиатуры к любому другому окну, отображаемому этим же приложением.
object Структура данных и набор функций, оперирующих ими. Такая организация кода используется GNOME и GTK+, но только не GDK и X.
parent Окна приложения в иерархическом дереве. Любое окно, имеющее одно или более подокон, называется родительским (parent) окном, а его подокна — дочерними (child).
pixmap Прямоугольный массив значений пикселов, принимаемых командами рисования. Чтобы нарисовать в окне pixmap (цветное растровое изображение), вам просто необходимо скопировать его пикселы на экран дисплея. Кроме того, программа может нарисовать pixmap в оперативной памяти таким же образом, как он может быть нарисован в окне на экране дисплея, но при этом рассматривать его как окно в памяти.
popt Пакет библиотек GNOME, предназначенных для считывания аргументов с командной строки.
popup То же, что и dialog box, но менеджер окон не добавляет к нему рамку с заголовком и средствами управления.
root window Родительское окно всех окон на экране дисплея. Заполняет всю область для отображения и предусматривает место для вывода пиктограмм и фон, заполняющий не занятое другими окнами пространство.
rpm (Red Hat Package Manager — менеджер пакетов Red Hat Linux). Создает и управляет пакетами программного обеспечения, предназначенными для распространения. Его можно использовать при создании новых пакетов, для инсталляции программного обеспечения из существующего пакета, обновления установленной версии, запроса состояния установленного пакета и его деинсталляции.
spline Алгоритм, который использует метод кусочного уточнения для построения полинома, который гладко соединяет набор точек. Часто используется для визуальной интерполяции точек на графе.
visual Формат отображаемых на экране данных. Обычно по умолчанию имеется один visual, который хранится в структуре GdkVisual и отображает все окна. Однако экраны некоторых мониторов позволяют одновременно использовать несколько visual: различные окна отображаются разными цветами и с использованием различных методов рисования пикселов.
X, или ХИ Так называется система X Window. Набор библиотечных программ, которые могут быть использованы для организации графического интерфейса пользователя. В Linux и BSD используется версия X под названием XFree86. Информацию по XFree86 можно получить на Web-сайте XFree86.org.
XInput Расширение X, которое позволяет использовать другие устройства ввода помимо мыши и клавиатуры.
ХРМ Формат графических файлов в форме исходного кода на языке С. Файл в этом формате можно напрямую включить в программу или использовать как независимый графический файл.
Предметный указатель
А
.а расширение 34
About всплывающее окно 192, 195 aboutCallback( ) функция обратного вызова 395
АС_ PROG_CXX макрос 460 AC_ARG_PROGRAM макрос 460 AC_HEADER_STC макрос 460 AC_INIT макрос 460 AC_OUTPUT макрос 460 AC_PROG_C макрос 460 AC_SUBST макрос 460 accelerator key 469 acconfig.h заголовочный файл 459, 463 add_sigdesc_to_tree( ) функция 150 add_siglist( ) функция 150 addChild( ) функция 414, 419 addlmage( ) функция 406, 408 affine transforms 257 AG_BARGRAPH макрос 429 ag_bargraph_add( ) функция 427, 430, 443 ag_bargraph_add_gc( ) функция 440, 441 AG_BARGRAPH_CLASS макрос 429 ag_bargraph_class_init( ) функция 432 ag_bargraph_destroy( ) функция обратного вызова 431, 432 ag_bargraph_draw( ) функция 432, 437, 438 ag_bargraph_event( ) функция 432, 438 ag_bargraph_get_type( ) функция 431, 432 ag_bargraph_init( ) функция 433 ag_bargraph_new( ) функция 427, 431, 444 ag_bargraph_paint( ) функция
431, 438, 439, 444 ag_bargraph_paint_text( ) функция 440 ag_bargraph_realize( ) функция 432, 433 ag_bargraph_send_configure( ) функция
436, 442, 443 ag_bargraph_set_text( ) функция 438
ag_bargraph_size_allocate( ) функция
432, 441, 442
ag_bargraph_size_request( ) функция
432, 441, 442
ag_bargraph_type статическая переменная 431
AGJS_BARGRAPH макрос 429
AgBargraph виджет 425
заголовочный файл 427-428
AgBargraph структура 429, 443
_AgBargraphBar структура 430
_AgBargraphClass структура класса 429
ALGORITHM файл 463
ALL.UNGUAS макрос 461,466.
ALL_SPACE значение 87
AM_ACLOCAL_INCLUDE макрос 461
AM.CONFIG.HEADER макрос 461
AM_GNU_GETTEXT макрос 461
AM_INIT_AUTOMAKE макрос 461
AM_MAINTAINER_MODE макрос 461
AM_PROG_LIBTOOL макрос 461
API 446
арр виджет 53
app_created сигнал 423
appCreatedf ) функция обратного вызова 423
applet-widget.h заголовочный файл 389
applet_widget_gtk_main( ) функция 389
applet_widget_init( ) функция 389
applet_widget_new( ) функция 389
applet_widget_register_callback( ) функция 395 applet widget register_stock_callback() функция
395
AppletWidget виджет 389, 391, 397
argv массив 38
art_affine_rotate( ) функция 260
art_affine_scale( ) функция 259
art_affine_translate( ) функция 260
attributes_mask маска 434
AUTHORS файл 459, 462, 463
autoconf программа 460, 464
autogen.sh сценарий 459, 463-464, 466
autoheader программа 463
automake программа 460
в
background цвет 307
bevel join 317
bin_PROGRAMS переменная 466
bindtextdomain( ) функция 455
bitmap изображение 162
bitmap утилита 170, 176, 318
bool тип данных' 451
BUGS файл 462
butt ending 317
button box 133
button виджет 53, 111, 126
buttonClick( ) функция обратного вызова 110
buttonFill( ) функция 83
buttonFirstCallback( ) функция 144
Button Mover структура 110
buttonSecondCallback( ) функция 144
С
.0 расширение 34
.с расширение 34
.сс расширение 34
.схх расширение 34
С библиотека 21
C++ 23
callback function 27
callback( ) функция 614, 617
calloc( ) функция 181
canvas 228, 230
canvasEvent( ) функция обратного вызова 335
case оператор 617
cat команда 603
cbfunction( ) функция обратного вызова 55
сс программа 34
CFLAGS переменная 39, 45, 390
change_orient сигнал 397
changeCallback( ) функция 395
changeColor( ) функция обратного вызова 330
Changelog файл 459, 463
child процесс 599 classes 24-25
clipboard 398, 408
closeDialog( ) функция обратного вызова 71
closedir( ) функция 608
color map 299
config.h заголовочный файл 455, 460, 463
config.h.in файл 463
configure сценарий 460
configure.in файл 459, 460
configure_event сигнал 293, 617 container 68
alignment 111
aspect frame 118 fixed 108 frame 114-118 layout 123 notebook 129 paned 120 scrolled window 127 contains_pointer значение 438 Context структура 364 convert утилита 163, 166 coords массив 232 copy операция 408 copy-and-paste операция 398 COPYING файл 462 creat( ) функция 599 createPositionWidget( ) функция 364 createView( ) функция обратного вызова
414, 419
CreateWindow( ) функция 617
ctime( ) функция 605
cut операция 408
cut-and-paste операция 398
CVS (Concurrent Version System) 625
cvs программа 627
CVSROOT переменная окружения 627
D
dashlist массив 317
delete_event сигнал 41, 414, 618
DEPENDS файл 462
describeEventButton( ) функция 239 describeEventCrossing( ) функция 239 describeEventMotion( ) функция 239 DESIGN файл 463 destroy событие 41, 618
destroy! ) функция 437 destroyColorsel( ) функция обратного вызова 329, 330
df утилита 393 dialog окно 50 disableProperties( ) функция обратного вызова 211, 213
DispatchMessage! ) функция 618 double dash 317 drag-and-drop операция 398 dragEvent( ) функция обратного вызова 243, 247, 249, 252
drawArcs( ) функция 283 drawing area 271-272 drawRandomRectangle( ) функция 310 dummyCallback( ) функция 424 dummyCallback( ) функция обратного вызова
195
Е
Edit меню 192, 410 enableProperties( ) функция обратного вызова 211, 213 encapsulation 24 errno глобальная переменная 598, 608 event queue 140 eventButton( ) функция 43, 154 eventChangef ) функция обратного вызова 372
eventConfigure( ) функция обратного вызова 293, 617
eventDelete( ) функция 41, 618 eventDestroy! ) функция обратного вызова 41, 48, 341, 414, 618
eventDraw( ) функция обратного вызова 273, 275, 281, 283, 286, 290, 293, 315, 320, 324, 365
eventExpose( ) функция обратного вызова 617 eventFocus( ) функция обратного вызова
344, 345 eventFontSet( ) функция обратного вызова 358, 365 eventHideShow( ) функция обратного вызова 380
eventlconChanged( ) функция обратного вызова 579
eventlconSelected! ) функция обратного вызова 579
eventPressKey! ) функция обратного вызова 344, 345
eventReleaseKey! ) функция обратного вызова 344, 346
eventSaveYourself( ) функция 561 eventShow( ) функция обратного вызова 376 eventShutdown( ) функция обратного вызова 71
ехес( ) функция 599, 600
execlp! ) функция 600
Exit команда 192
exit( ) функция 66
expand значение 83
expanding виджеты 80
expose_event сигнал 293, 617
F
(close! ) функция 603
fcntl( ) функция 160
fflush( ) функция 604
(gets! ) функция 603
File меню 192, 410
tileClose! ) функция 187
(ileExit( ) функция 187
fileOpen( ) функция 187
(ileSaveCallback( ) функция 63
(ill значение 83
(ill_color параметр 231
(illString! ) функция 306 float тип данных 451, 452
(ореп( ) Функция 603
foreground цвет 307 fork and exec 599 (ork( ) функция 599, 600 (print(( ) функция 599 (puts( ) функция 604 (ree( ) функция 281
(romlmage массив 407
(unctionCreateGC( ) функция 324 (unctionString! ) функция 306
G
.gnome подкаталог 447
,gnome_private подкаталог 447
_GdkGCValues структура 302, 307 g_bargraph_destroy( ) функция обратного вызова 436 g_free( ) функция 30 g_malloc( ) функция 30, 181 g_malloc0( ) функция 31 g_memdup( ) функция 31 g_print( ) функция 30, 369 g_printerr( ) функция 30 g_realloc( ) функция 31 g_str_equal( ) функция 30 g_strcasecmp( ) функция 30 g_strconcat( ) функция 30 g_strdown( ) функция 31 g_strdup( ) функция 30 g_strdup_printf( ) функция 30 g_strerror( ) функция 30 g_strfreev( ) функция 451 g_strndup( ) функция 30 g_strup( ) функция 31 Game меню 196 дсс программа 34 компиляция 35 компоновка 35 передача ей аргументов 37 распознаваемые ею суффиксы 34
GDK библиотека 21
GDK_2BUTTON_PRESS событие 260, 337
GDK_3BUTTON_PRESS событие 260, 337
GDK_AND функция 306
GDK.AND.INVERT функция 306
GDK_AND_REVERSE функция 306 gdk_bitmap_create from data( ) функция 178, 320
GDK.BUTTON.PRESS событие 260, 336, 337 GDK BUTTONRELEASE событие
260, 336, 337
GDK CLEAR функция 306
GDK_CLIENT_EVENT событие 260
GDKCLIP.BY.CHILDREN опция 307 gdk_color_alloc( ) функция 310, 316, 329, 436 gdk_color_parse( ) функция 316 gdk_colormap get system( ) функция
310, 316, 320
GDK CONFIGURE событие 260
GDK_COPY функция 306, 321 GDK.COPY.INVERT функция 306 gdk_cursor_new( ) функция 174, 175 gdk_cursor_new_from_pixmap( ) функция 178 GDK_DELETE событие 260
GDK.DESTROY событие 260
GDK_DRAG_ENTER событие 260
GDK_DRAG_LEAVE событие 260 GDK_DRAG_MOTION событие 260 GDK_DRAG_STATUS событие 260 gdk_draw_arc( ) функция 296, 337 gdk_draw_pixmap( ) функция 290, 296 gdk_draw_point( ) функция 275, 276 gdk_draw_points( ) функция 276 gdk_draw_polygon( ) функция
278, 281, 291, 316 gdk_draw_rectangle( ) функция
278, 293, 296, 311, 321, 440 gdk_draw_string( ) функция 287, 291, 441 gdk_draw_text( ) функция 287 GDK_DROP_FINISHED событие 260 GDK_DROP_START событие 260 GDK_ENTER_NOTIFY событие 234, 260, 336 GDK_EQUIV функция 306 GDK_EXPOSE событие 260, 337 GDK_FLEUR курсор 171 GDK.FOCUS.CHANGE событие 261 gdk_font_load( ) функция
287, 315, 357, 359, 365, 441 gdk_font_unref( ) функция 287, 365 gdk_gc_get_values( ) функция 305, 324 gdk_gc_new( ) функция 310, 316, 320 gdk_gc_new_with_values( ) функция 324 gdk_gc_set_dashes( ) функция 317, 324 gdk_gc_set_fill( ) функция 321 gdk_gc_set_foreground( ) функция
311, 316, 324 gdk_gc_set_line_attributes( ) функция 316, 324 gdk_gc_set_stipple( ) функция 320 gdk_gc_set_tile( ) функция 321 gdk_gc_set_ts_origin( ) функция 321 gdk_imlib_create_image_from_xpm data( )
функция 246 gdk_imlib_destroy_image( ) функция 247 gdk_input_add( ) функция 160
GDK.INVERT функция 306
GDK.KEY.PRESS событие 261 GDK.KEY.RELEASE событие 261 GDK.KEY_RELEASE.MASK маска 345 gdk_keyval_is_lower( ) функция 346 gdk_keyval_name( ) функция 345, 346 GDK.LEAVE.NOTIFY событие 261, 336 GDK.MAP событие 261, 336 GDK.MOTION.NOTIFY событие 261, 337 GDK.NAND функция 306 GDK.NO.EXPOSE событие 261 GDK.NOOP функция 306 GDK.NOTHING событие 261 GDK.OPAQUE.STIPPLED режим 321 GDK.OPAQUE.STIPPLED функция 307 GDK.OR функция 306 GDK.OR.REVERSE функция 306 gdk pixmap_create_from_xpm_d( ) функция 167, 290, 320, 386 gdk_pointer_grab( ) функция 339 gdk_pointer_is_grabbed( ) функция 341 gdk_pointer_ungrab( ) функция 341 GDK.PROPERTY.NOTIFY событие 261 GDK.PROXIMITY.IN событие 261 GDK.PROXIMITY.OUT событие 261 GDK.SELECTION.CLEAR событие 261 GDK.SELECTION.NOTIFY событие 261 GDK.SELECTION.REQUEST событие 261 GDK.SET функция 306 GDK.SOLID функция 307 GDK.STIPPLED режим 321 GDK.STIPPLED функция 307 gdk_text_extents( ) функция 365, 441 GDK.TILED функция 307 GDK.UNMAP событие 261 GDK.VISIBILITY.NOTIFY событие 261 gdk_visual_get_system( ) функция 301 gdk_window_clear( ) функция 329, 440 gdk_window_clear_area_e( ) функция 365, 366 gdk_window_new( ) функция 434 gdk_window_set_background( ) функция 329 gdk_window_set_cursor( ) функция 175, 178 gdk_window_set_user_data( ) функция 436 GDK.XOR функция 306 GdkBitmap объект 178
GdkColor объект 308, 310, 329, 590
GdkColor структура 21, 433
GdkCursor объект 175, 178
GdkEvent класс событий 260
GdkEvent событие 228
GdkEvent структура 234, 239, 263-264
GdkEventAny структура 264
GdkEventButton структура 239, 264
GdkEventClient событие 265
GdkEventConfigure событие 265, 436, 443
GdkEventCrossing событие 239, 265
GdkEventDND событие 266
GdkEventExpose событие 267, 268, 308
GdkEventFocus событие 267
GdkEventKey событие 267, 345
GdkEventMotion событие 239, 263, 268
GdkEventNoExpose событие 267, 268, 308
GdkEventProperty событие 268
GdkEventProximity событие 269
GdkEventSelection событие 269
GdkEventVisibility событие 269
GdkFont объект 287, 359
GdkGC объект 272, 302, 305, 324
GdkGCValues структура 305, 322, 324
Gdklmage объект 506
Gdklmliblmage изображение 244, 246
GdklnputCondition объект 160
gdkkeysyms.h заголовочный файл 345
GdkPixmap объект 167, 290
GdkPoint структура 276, 278
GdkRectangle объект 438
GdkVisual структура 301
GdkWindow объект 178
GdkWindowAttr структура 434
getenv( ) функция 611
GetMessage( ) функция 618
getpid( ) функция 600
getppidf ) функция 600
gettimeofday( ) функция 606
getTimeString( ) функция 157
GIMP (GNU Image Manipulation Program) программа 27
GIMP Toolkit. Cm. GTK+
glib библиотека 21, 27
полезные функции 29-31 типы данных 27-29 GMT (Greenwich Mean Time) 605 GNOME библиотека 22 gnome-app-helper.h заголовочный файл 190 gnome-stock.h заголовочный файл 205 GNOME-приложения 22 gnome_about_new( ) функция 378 GNOME_APP макрос 48 gnome_app_create_menus( ) функция
?88, 211, 213, 215, 219, 223, 410 gnome_app_create_menus_with_data( ) функция
419 gnome_app_create_toolbar( ) функция
201, 217, 221, 226, 423 gnome_app_install_menu_hints( ) функция 197 gnome_app_new( ) функция 31, 44, 188, 617 GNOME_APP_PIXMAP_DATA тип 208 GNOME_APP_PIXMAP_FILENAME тип 209 gnome_app_set contents( ) функция
231, 234, 273, 329, 364, 405 gnome_app_set_statusbar( ) функция 197 GNOME_APP_UI_ENDOF_INFO тип 219, 221 GNOME_APP_UI_ITEM тип 48, 187, 221 gnome_appbar_set_progress( ) функция 554 gnome_appbar_set_prompt( ) функция 554 gnome_canvas_item_lower( ) функция 235 gnome_canvasjtem_lower_to_bottom( ) функция 235 gnome_canvas_item_move( ) функция 243 gnome_canvas_item_new( ) функция
246, 249, 252, 255, 257, 259, 372, 407 gnome_canvas_item_raise( ) функция 235 gnome_canvas_item_raise_to_top( ) функция
234, 239 gnome_canvas_new( ) функция 230 gnome_canvas_points_free( ) функция 232 gnome_canvas_points_new( ) функция 232 gnome_canvas_root( ) функция 231 gnome_canvas_set_scroll_region( ) функция
230, 259 GNOME_COMPILE_WARNINGS макрос 461 gnome_config get_ семейство функций 449 gnome_config_get_bool( ) функция 451 gnome_config_get_bool_with_default( ) функция
451 gnome_config_get_float( ) функция 452 gnome_config_get_float_with_default( ) функция
452 gnome_config_get_int( ) функция 452 gnome_config_get_int_with_default( ) функция
452 gnome_config_get_string( ) функция 453 gnome_config_get_string_with default, ) функция
453 gnome config_get_translated_string( ) функция
453 gnome_config_get_translated_string_with_default( ) функция 453 gnome_config_get_vector( ) функция 453 gnome_config_get_vector_with_default( )
функция 453 gnome_config_private_get_bool( ) функция 452 gnome_config_private_get_bool_with_default( )
функция 452 gnome_config_private_get_float( ) функция 452 gnome_config_private_get_float_with_default( )
функция 452 gnome_config_private_get_int( ) функция 452 gnome_config_private_get_int_with_default( )
функция 452 gnome_config_private_get_string( ) функция 453 gnome_config_private_get_string_with_default( )
функция 453 gnome_config_private_get_translated_string( )
функция 453 gnome_config_private_get_translated_string_with
_default( ) функция 453 gnome_config_private_get_vector( ) функция 453 gnome_config_private_get_vector_with_default( )
функция 454 gnome_config_private_set_bool( ) функция 451 gnome_config_private_set_float( ) функция 452 gnome_config_private_set_int( ) функция 452 gnome_config_private_set_string( ) функция 452 gnome_config_private_set_translated_string( )
функция 453 gnome_config_private_set_vector( ) функция 453 gnome_config_set_bool( ) функция 451 gnome_config_set_float( ) функция 452
gnome_config_set_int( ) функция 452 gnome_config_set_string( ) функция 452 gnome_config_set_translated_string( ) функция 453 gnome_config_set_vector( ) функция 453 gnome_config_sync( ) функция 449 gnome_dialog_new( ) функция 566 gnome_dock_layout_add_to_dock( ) функция
570 gnome_font_picker_new( ) функция 365 gnomejcon_selection_getjcon( ) функция 580 GNOMEJNIT макрос 461 gnome_init( ) функция 22, 44, 52, 149, 153, 346, 351, 414, 419, 616 gnome_init_with_popt_table( ) функция 351 gnome_mdi_add_child( ) функция 419 gnome_mdi_add_view( ) функция 415 gnome_mdi_add_child( ) функция 414 gnome_mdi_generic_child_new( ) функция 414 gnome_mdi_generic_child_set_label_func( ) функция 414 gnome_mdi_generic_child_set_view_creator( ) функция 414, 415 gnome_mdi_generic_child_new( ) функция 419 gnome_mdi_new( ) функция 414, 419 gnome_mdi_open_toplevel( ) функция 414, 419 gnome_mdi_set_active_view( ) функция 420 gnome_mdi_set_menubar_template( ) функция
419 gnome_mdi_set_mode( ) функция 414, 419 GNOME_NO константа 55 GNOME_OK константа 55 gnome_ok_dialog( ) функция 52 gnome_pixmap_entry_new( ) функция 588 gnome_popup_menu_attach( ) функция 200 gnome_popup_menu_new( ) функция 200 gnome_proc_bar_new( ) функция 590 gnome_proc_bar_start( ) функция 590 gnome_property_box_append page( ) функция 593 gnome_property_box_changed( ) функция 593 gnome_property_box_new( ) функция 593 gnome_request_dialog( ) функция 60 gnome_request_string_dialog( ) функция 59 gnome_stock_or_ordinary_button( ) функция 596
GNOME_STOCK_PIXMAP_REVERT цветное растровое изображение 596, 597
GNOME.X.CHECKS макрос 461
GNOME_YES константа 55
GNOME_CANCEL константа 55
GnomeAbout виджет 378, 550
GnomeAnimator виджет 551-553
GnomeApp виджет 553
GnomeApp окно 420, 423
GnomeApp строка состояния 184
GnomeAppBar виджет 554
GnomeCalculator виджет 555
GnomeCanvas виджет 228-232, 335, 405,
555-556
GnomeCanvas окно 241-243
GnomeCanvasEllipse виджет 556
GnomeCanvasGroup класс 406, 556
GnomeCanvasGroup объекты 231
GnomeCanvasImage виджет 557
GnomeCanvasItem класс 247, 557-558
GnomeCanvasLine виджет 558
GnomeCanvasPqints объект 231, 256, 257
GnomeCanvasPolygon виджет 558
GnomeCanvasRE класс 558
GnomeCanvasRect виджет 559
GnomeCanvasText виджет 559
GnomeCanvasWidget объект 559
GnomeClient объект 559-563
GnomeColorPicker виджет 563-564
GnomeDEntryEdit объект 564-565
GnomeDialog виджет 565-567
GnomeDock виджет 567-570
GnomeDockBand виджет 570-571
GnomeDockltem контейнер 570, 571-572
GnomeDockLayout объекты 570, 572-573
GnomeEntry виджет 573-574
GnomeFileEntry виджет 574
GnomeFontPicker виджет 359, 365, 575
GnomeFontSelector виджет 575-576
GnomeGuru виджет 576-577
GnomeHRef виджет 577
GnomelconEntry виджет 577-579
GnomelconSelection виджет 580
GnomeLess виджет 580,-581 GNOMELOCALDIR определение 455
GnomeMDI виджет 581-582 GnomeMDI объект 414, 419 GnomeMDIChild объект 582 GnomeMDIGenericChild виджет 414, 582-583 GnomeMessageBox виджет 583-585 GnomeNumberEntry виджет 585 GnomePaperSelector виджет 585-586 GnomePixmap виджет 552, 586-587 GnomePixmapEntry виджет 588-589 GnomeProcBar виджет 589-590 GnomePropertyBox виджет 591-593 GnomeScores виджет 594 GnomeSpell виджет 595 GnomeStock виджет 595-596 GnomeStockPixmapWidget виджет 597 GnomeUlInfo структура 184, 187, 188, 200, 206, 213, 216, 219
GNOMEUIINFO.END макрос 48, 191 GNOMEUIINFO.HELP макрос 191 GNOMEUIINFO.ITEM макрос 191 GNOMEUIINFO_ITEM_DATA макрос 191 GNOMEUIINFO JTEM.STOCK макрос 191 GNOMEUIINFO_MENU_COPY ITEM макрос 196 GNOMEUIINFO.RADIOITEM макрос
219, 221
GNOMEUIINFO.RADIOITEM.DATA макрос 191 GNOMEUIINFO.RADIOLIST макрос 219, 221 GNOMEUIINFO.SEPARATOR макрос 191 GNOMEUIINFO.SUBTREE макрос 48, 187, 191 GNOMEUIINFO_SUBTREE_HINT макрос 191 GNOMEUIINFO.SUBTREE.STOCK макрос 191 GNOMEUIINFOJOGGLEITEM макрос
223, 225
GNOMEUIINFO.TOGGLEITEM.DATA макрос 192 GNOMEUIINFO.END макрос 187 grabMouse( ) функция обратного вызова 339 grep команда 602 GTK+ (GIMP Toolkit) библиотека 22 gtk-config сценарий 39 gtk.h файл 429 gtk/gdk/gdkcursors.h заголовочный файл 175 gtk/gdk/gtktypes.h заголовочный файл 175 GTK_ACTION_MOVE операция 401 gtk_adjustment_change<j( ) функция 470 gtk_adjustment_new( ) функция 126
gtk_adjustment_value_changed( ) функция 470 GTK.ARG.READABLE флаг 369 GTK.ARG.WRITABLE флаг 369
GTK_BIN макрос приведения типов данных 26 gtk_box_pack_start( ) функция 68, 88 gtk_box_vbox_new( ) функция 88 gtk_button_box_set_layout( ) функция 138 gtk_button_create( ) функция 432 gtk_button_create_with_label( ) функция 432 gtk_button_new_with_label( ) функция
25, 43, 255, 386
GTK_BUTTON1 MASK маска 407 GTK_BUTTON2_MASK маска 407 GTK_BUTTON3_MASK маска 407 gtk_clist_new_with_titles( ) функция 376 gtk_color_selection_dialog_new( ) функция 329 gtk_color_selection_get_color( ) функция 329 GTK_CONTAINER макрос приведения типов данных 26 gtk_container_add( ) функция 43, 66, 78, 135, 231, 427, 570 gtk_container_set_border_width( ) функция 44, 120, 135
GTK_DEST_DEFAULT_ALL флаг 406 GTK_DEST_DEFAULT_DROP флаг 406 GTK_DEST DEFAULT.HIGHLIGHT флаг 406 GTK_DEST DEFAULT-MOTION флаг 406 gtk_drag_dest_set( ) функция 406 gtk_drag_source_set( ) функция 400, 407 gtk_draw_line( ) функция 273 gtk_drawing_area_new( ) функция 273 gtk_drawing_area_size( ) функция 365 gtk_editable_cut_clipboard( ) функция 410 gtk_editable_paste-dipboard( ) функция 410 gtk_editable_copy_clipboard( ) функция 410 gtk_entry_get_text( ) функция 74 GTK.EXPAND опция 100 GTK.FILL опция 100 gtk_fixed_move( ) функция 110, 111 gtk_fixed_new( ) функция 110 gtk_fixed_put( ) функция 110, 111 gtk_font_selection_get_font( ) функция 497 gtk_font_selection_set_filter( ) функция 498 gtk_frame_new( ) функция 118, 500 gtk_frame_set_label_align( ) функция 117
gtk_frame_set_shadow_type( ) функция 116 gtk_hbox_new( ) функция 83 gtk_hbutton_box_new( ) функция 134 gtk_hpaned_new( ) функция 122 gtk_idle_add( ) функция 154 gtk_init( ) функция 38, 41, 44 gtk_label_new( ) функция 378 gtk_label_set_text( ) функция
110, 157, 175, 345, 346, 393 gtk_layout_move( ) функция 126 gtk_layout_put( ) функция 126 gtk_layout_set_size( ) функция 126 gtk_main( ) функция 38, 41, 51, 52, 140, 155, 617, 618 gtk_main_quit( ) функция 41, 618 gtk_main_quit( ) функция 495 gtk_menu_append( ) функция 513 gtk_menu_bar_append( ) функция 513 gtk_menu_item_new_with_label( ) функция 513 gtk_menu_new( ) функция 513 gtk_misc_set_alignment( ) функция 83 gtk_notebook_append_page( ) функция 132 gtk_notebook_get_current_page( ) функция 133 gtk_notebookinsertpage( ) функция 132 gtk_notebook_prepend_page( ) функция 132 gtk_notebook_remove_page( ) функция 133 gtk_notebook_set_page( ) функция 133 gtk_notebook_set_show_tabs( ) функция 133 gtk_notebook_set_tab_pos( ) функция 132 gtk_object_arg_get_info( ) функция 369 gtk_object_query_args( ) функция 369 gtk_object_set( ) функция 376, 377 gtk_object_set( ) функция 373 GTK_OBJECT_TYPE макрос 369 gtk_paned_add1 ( ) функция 122 gtk_paned_add2( ) функция 122 gtk_pixmap_new( ) функция 167 GTK_POLICY ALWAYS значение 129 GTK_POLICY_AUTOMATIC значение 129 GTK_POS_BOTTOM значение 132 GTK_POS_LEFT значение 132 GTK_POS_RIGHT значение 132 GTK_POS_TOP значение 132 gtk_progress_bar_update( ) функция 526 gtk_radio_button_new_with_label( ) функция 527
gtk_scrolled_window_new( ) функция 128 gtk_scrolled_window_set_policy( ) функция 129 gtk_selection data_set( ) функция 401, 407 GTK_SHADOW_ETCHED_IN тип рамки 116 gtk_signal_connect( ) функция . "41, 43, 63, 69, 154, 234, 238, 273, 329, 336, 344, 376, 400, 401, 406, 407, 414, 617, 618 gtk_signal_emit( ) функция 142 gtk_signal_emit_by_name( ) функция 142, 144 GTK_SIGNAL_FUNC макрос 41 gtk_signal_query( ) функция 149 gtk_signal_connect( ) функция 397, 406 gtk_signals статический массив 150 gtk_spin_button_new( ) функция 532 GTK_STATE_ACTIVE состояние 330-331, 381 GTK.STATE.INSENSITIVE состояние 330- 331, 381
GTK_STATE_NORMAL состояние 330-331, 381 GTK_STATE_PRELIGHT состояние 330-331, 381 GTK_STATE_SELECTED состояние 381 gtk_style_attach( ) функция 436 gtk_style_copy( ) функция 359, 386 gtk_style_set_background( ) функция 436 gtk_style_unref( ) функция 359 gtk_table_attach( ) функция 97 gtk_table_attach_defaults( ) функция
95, 96, 106 gtk_table_new( ) функция 96 gtk_text_new( ) функция 410 gtk_text_set_editable( ) функция 410 gtk_timeout_add( ) функция 157, 296, 393 gtk_timeout_remove( ) функция 157 gtk_toggle_button_get_active( ) функция
222, 226 gtk_toggle_button_set_active( ) функция 527 gtk_type_name( ) функция 149, 150, 369 gtk_type_new( ) функция 432 gtk_type_parent( ) функция 149 gtk_type_unique( ) функция 431 GTK_VALUE_UINT макрос 377 gtk_vbox_new( ) функция 68, 78, 364 gtk_widget_add_events( ) функция 345 gtk_widget_destroy( ) функция
69, 71, 378, 566
gtk_widget_event( ) функция 443 gtk_widget_get_default_style( ) функция 386 gtk_widget_get_name( ) функция 371 gtk_widget_get_style( ) функция 329, 359 gtk_widget_hide( ) функция
'71, 216, 217, 378, 380
gtk_widget_map( ) функция 378
gtk_widget_pop_style( ) функция 387 gtk_widget_push_style( ) функция 387 gtk_widget_realize( ) функция 378, 379 GTK.WIDGET.SET.FIAGS макрос 434 gtk_widget_set_name( ) функция 371 gtk_widget_set_sensitive( ) функция 211, 213 gtkwidget_set_style( ) функция 359, 386 gtk_widget_set_uposition( ) функция 373 gtk_widget_set_usize( ) функция
’230, 372, 386
gtk_widget_show( ) функция 38, 41, 53, 65, 71, 78, 126, 171, 216, 217, 329, 378, 380, 383, 385, 391
gtk_widget_show_all( ) функция 126, 169, 386, 389, 427, 540
gtk widget_unmap( ) функция 378 gtk_widget_unrealize( ) функция 379 gtk_widget_unref( ) функция 378 gtk_widget_usize( ) функция 507 GTK.WIDGETVISIBLE макрос 380 GTK_WINDOW_DIALOG тип окна 65 gtk_window_new( ) функция 38, 41, 65 GTK_WINDOW_POPUP тип окна 65 gtk_window_set_default_size( ) функция 110 gtk_window_set_modal( ) функция 53, 59, 69 GTK_WINDOW_TOPLEVEL тип окна 65 GtkAccelLabel виджет 469-470 GtkAdjustment объект 125-126, 410, 470 GtkAlignment виджет 112, 470-471 GtkArg массив 369, 376 GtkArg объекты 371 GtkArg структура 369, 374 GtkArrow виджет 471-472 GtkAspectFrame виджет 472-473 GtkBin виджет 367 GtkBin класс 24, 473 GtkBox класс 473
GtkButton виджет 25, 111, 367
GtkButton класс 24-25
GtkButton объект 24-25, 152, 474 GtkButtonBox класс 474-475
GtkCalendar виджет 152, 475-476
GtkCheckButton виджет 476 GtkCheckMenultem виджет 476-477
GtkCList виджет 369, 370, 375, 477-480
GtkClock виджет 480-481
GtkColorSelection виджет 481-482
GtkColorSelectionDialog виджет 482 GtkCombo виджет 482-483
GtkContaifier виджет 367, 370, 483-485
GtkCTree виджет 485-489
GtkCTreeNode структура 488
GtkCurve виджет 489-490
GtkData класс 490
GtkDial виджет 490-491
GtkDialog виджет 491-492, 499
GtkDrawingArea виджет 271, 272, 315, 492
GtkEdit виджет 410
GtkEditable виджет 410, 492-493
GtkEntry виджет ’ 410, 493-494, 588
GtkEventBox виджет 494-495
GtkFileSelection виджет 495-496
GtkFixed контейнер 496-497 GtkFontSelection виджет 497-498, 499 GtkFontSelectionDialog виджет 497, 498-499 GtkFrame контейнер 500 GtkGammaCurve виджет 500-501
GtkGC структура 167
GtkHandleBox контейнер 501
GtkHBox виджет 502
GtkHButtonBox контейнер 502-503
GtkHPaned контейнер 503
GtkHRuler виджет 503-504
GtkHScale виджет 504
GtkHScrollbar виджет 504-505
GtkHSeparator виджет 505
Gtklmage виджет 505-506
GtklnputDialog окно 506
Gtklnvisible виджет 507 Gtkltem класс 507-508 GtkltemFactory объект 508-509
GtkltemFactoryEntry структуры 508
GtkLabel виджет 378, 395, 472, 509-510
GtkLayout виджет 510
GtkList контейнер 510-512
GtkListltem виджет 511, 512
GtkMenu контейнер 512-514
GtkMenuBar контейнер 514
GtkMenultem виджет 515 GtkMenuShell класс 515-516 GtkMisc класс 516
GtkNotebook виджет 516-517
GtkObject виджет 367, 370
GtkObject класс 24, 518
GtkObject указатель 429
GtkOptionMenu контейнер 519-520
GtkPacker виджет 520-522
GtkPaned класс 522
GtkPixmap виджет 522
GtkPixmapMenultem виджет 523
GtkPlug виджет 523
GtkPreview виджет 523-524
GtkProgress виджет 525
GtkProgressBar виджет 525-526
GtkRadioButton виджет 526-527
GtkRadioMenultem виджет 527-528
GtkRange класс 528-529
GtkRuler виджет 529
GtkScale класс 530
GtkScrollbar класс 530
GtkScrolledWindow контейнер 530
GtkSelectionData структура 401, 407, 408
GtkSeparator класс 531
GtkSignalQuery структура 149, 150 gtksignals.c файл исходного кода 150 GtkSocket виджет 531 GtkSpinButton виджет 531-533 GtkStatusbar виджет 533
GtkStyle структура 167, 329, 359, 382, 386,
395
GtkTable виджет 533-534
GtkTargetEntry массивы 407
GtkTargetEntry структуры 406
GtkTargetEntry указатель 406 GtkTearoffMenultem виджет 534-535 GtkTed контейнер 535
GtkText виджет 410, 535-536
GtkTipsQuery виджет 536
GtkToggleButton виджет 536-537
GtkToolbar виджет 537-538
GtkTooltips объект 538-539
GtkTree виджет 539-541
GtkTreeltem виджет 540, 541
GtkType поле 374
GtkVBox виджет 541
GtkVButtonBox контейнер 541-542
GtkViewport контейнер 542
GtkVPaned контейнер 542
GtkVRuler виджет 543
GtkVScale виджет 543
GtkVScrollbar виджет 544
GtkVSeparator виджет 544-545
GtkWidget виджет 367, 370
GtkWidget родительский класс 545-548
GtkWidget структура 429
GtkWidget указатель 429
gtkwidget.h файл 429
GtkWindow виджет 548-549
GtkCList виджет 376
gzip утилита 621
н
.h расширение 34
HACKING файл 462
HEIGHT значение 234
helloauto каталог 459
helloauto.LDADD переменная 466
helloauto_SOURCES переменная 466
hellomath( ) функция 35
hellomath.c файл 35
Help меню 192, 196
help файлы 197
helpAbout( ) функция 195
helpColorsel( ) функция обратного вызова 330
hideProperties( ) функция обратного вызова
216, 217
hint всплывающая подсказка 193, 201
homogeneous виджеты 80
homogeneous значение 83
horizontal box 76
hot spot 169, 170
I
J расширение 34
Ji расширение 34
И8п. См. интернационализация
IDGBIBLE файл 459, 463 idle function 153 idleFunction( ) функция 154 INCLUDES переменная 465 inheritance 24 inheritance( ) функция 149 inputCallback( ) функция 160 inputSetup( ) функция 160 INSTALL файл 462 int тип данных 451, 452 internationalization 446, 454-456 ispell программа 595 itemEvent( ) функция обратного вызова 234, 238, 239
J
Java 23
К
keyval поле 345
L
LDFLAGS переменная 390 LDLIBS переменная 39, 45 libgnorba библиотека 390 libpanel_applet библиотека 390 lineStyleString( ) функция 308 listValues( ) функция обратного вызова 305 load_signals( ) функция 149 loadStats( ) функция 393 localtime( ) функция 605 logo.xpm файл 4 290 Is команда 602
М
,т расширение 34 macros подкаталог 459 main( ) функция 149, 405, 419, 616 make clean команда 36, 464, 466 make dist команда 464 make force команда 36 make install команда 36, 464, 466
make команда 35, 466
make-файлы 35-37
makeArrow( ) функция 256, 257
makeAspectFrame( ) функция 119
makeBottomBox( ) функция 91
makeBox( ) функция 78, 91, 175
makeBoxes( ) функция 83, 86
makeButtonBox( ) функция 106, 134, 138,
144
makeButtonFram3( ) функция 138
makeButtonPage( ) функция 132
makeCheckButtons( ) функция 105
makeColorBox( ) функция 328
makeDisplay( ) функция 138, 157
makefile файл 35
Makefile.am файл 459, 464
главный 464
подчиненный 465
MakefileJn файл 464
makeFixedContainer( ) функция 110
makeFrame( ) функция 117
makeFrames( ) функция 116
makeHorizontalPane( ) функция 122
makeLayout( ) функция 125, 405
makeMiddleBox( ) функция 91
makeNotebook( ) функция 131
makeOriginArrow( ) функция 259
makeTable( ) функция 94, 106
makeTextEntry( ) функция 105
makeTextPage( ) функция 132
makeWidget( ) функция 568
mark( ) функция 287
MDI (Multiple Document Interface) 412
меню 415
модальный режим 420
панель инструментов 420
режим записной книжки 420
memcpy( ) функция 206
memmove( ) функция 31
memory leak 459
menu 183
methods 24-25
MIME (Multipurpose Internet Mail Extensions) спецификация 401
miter joint 316
modal окно 52 modalCallback) ) функция обратного вызова 424
modeDefault) ) функция обратного вызова 420 modeModal) ) функция обратного вызова 420 modeNotebook) ) функция обратного вызова 419 modeToplevel) ) функция обратного вызова 420
Modulate пиктограмма 208
N
М_ макрос 456 newBall) ) функция 296, 297 newCursorFromXPM) ) функция 181 NEWS файл 459, 462, 463 next) ) функция обратного вызова 175 nextBall) ) функция 296, 297 nextFrame) ) функция 296 not-last ending 317 notebookcallback) ) функция обратного вызова 424
О .о расширение 34 on-off dashed lines 317 oneSecondCallback) ) функция 157 opendir) ) функция 608,
orientEvent) ) функция обратного вызова 397 outline_color параметр 231 outString строка символов 286
Р
PACKAGE определение 455, 461■
packReceivingButton) ) функция 401 packSendingButton) ) функция 400 parent процесс 599 paste операция 408 pclose) ) функция 603 реггог) ) функция 599 pgmContext структура 63 pipe 602 pixmap изображение 162 PKG_NAME переменная 464 polimorphism 25
polygon 255-257
popen) ) функция 603
poptOption структуры 348, 351
popup окно 50
PostQuitMessage) ) функция 618
previous) ) функция обратного вызова 175
print_signals( ) функция 149, 150
printf) ) функция 456
progress bar 63
projecting ending 317
propertyboxCallback) ) функция 593 quit сообщение 618
R
radioCallback) ) функция обратного вызова 593 radiomen массив 219 radioToolbar массив 221 rand) ) функция 275 read) ) функция 160 readdir) ) функция 608 README файл 459, 462, 463 receiveCallback) ) функция 401, 406, 407 rectangleEvent) ) функция 238 Redeks пиктограмма 209 RegisterClassEx) ) функция 617 retrievevector) ) функция 451 RGB значение 164 round ending 317 round join 317 RPM (Red Hat Package Manager) 625 runtime error 459
S .S расширение 34 .s расширение 34 Save команда 192 sendCallback) ) функция обратного вызова
400, 401, 407
setCursor) ) функция 175
setenv) ) функция 611
setlabel) ) функция 415, 419
Settings меню 196
shadow массив 116
shortcut символ 198•
showjext указатель 440
showArgs( ) функция 369 showColorsel( ) функция обратного вызова
328, 329
showDialog( ) функция обратного вызова 68, 74
showPopup! ) функция 68 showProperties( ) функция обратного вызова
216, 217
shutdown! ) функция 48
signames( ) функция 149
sleep! ) функция 154
sprintf( ) функция 393, 456
srand( ) функция 275
srcdir переменная окружения 464
startCallback( ) функция обратного вызова 391
stat( ) функция 608
stderr стандартный файл ошибок 464, 599
stdout стандартный файл вывода 464
stipple.xbm монохромное изображение 318
stipple_height значение 320
stipple_width значение 320
storeVector( ) функция 451
strerror( ) функция 599
string тип данных 451, 452
stringCallback( ) функция обратного вызова 59
stString массив 393
subwindowString( ) функция 307
switch/case оператор 239
sxpm утилита 168
system! ) функция 391, 602
Т
tbxpm.h заголовочный файл 221, 225
tear-off меню 184
tenSecondCallback( ) функция обратного
вызова 157
textdomain( ) функция 455
tiling 307
time( ) Функция 605
timers 155
timeval структура 606
tm структура 605
TODO файл 462
toggleOne( ) функция обратного вызова
224, 226
toolbar панель инструментов 183, 200
tooltip всплывающая подсказка 193, 201 topic.dat файл 197 topLevel виджет 167 toplevelCallback( ) функция обратного вызова 424 translated string тип данных 451, 453 TranslateMessage( ) функция 618 typedef оператор 261, 429
U
/usr/lib/X11/rgb.txt файл 316
ungrabMouse( ) функция обратного вызова
339, 341 unsetenv( ) функция 611 - updateCallback( ) функция 393 updateValue( ) функция 590 UTC (Universal Time Coordinate) 605
V
valueCreateGC( ) функция 324 vector тип данных 451, 453 VERSION определение 461 vertical box 76-77 View меню 196
w
wait( ) функция 601, 602
white_gc графический контекст 305
widget_list( ) функция 149
WIDTH значение 234
width pixels параметр 231
Windows меню 196
WinMainf ) функция 614
WM_DESTROY сообщение 618
X
X библиотека 21 xalign значение 112, 113, 118, 119 XBM формат 162, 169 горячая точка 169, 170 создание курсора мыши 169 утилита для работы с монохромными растровыми изображениями 170
Xevent событие 260
Xlnput устройства 506
xmag утилита 276
xoptions флаг 98 ХРМ формат 162-165 включение графического файла в программу 166 оформление кнопки 168 сохранение графики как текста ASCII
163 xscale значение 112 xVelocity значение 296 ХСоруАгеа( ) функция 290
yalign значение 112, 113, 118, 119 yoptions флаг 98 yscale значение 112 yVelocity значение 296
Символы
макрос 455
А активная страница 129 анимация 293-297 апплет 388 запуск приложения 390-393 меню 393 отображение меняющейся информации 391-393 аргумент 368 аффинные преобразования 257 Б бросить 398 буфер обмена 398, 408
В виджет-граф 425 виджеты 26 деактивизация 379 показ 377 преобразование 377 разрушение 378 реализация 377 создание 377 сокрытие 378 стили 381
время 604
по Гринвичу 605
универсальное скоординированное 605 всплывающая подсказка 193 всплывающее окно 50 вставить 408 вырезать 408 выступающее окончание 317
г
гравировка пунктиром 307, 318 граф 425 графический контекст 272, 273, 302 группирование компонентов на канве 250
д двойная штрихпунктирная линия 317 двухпозиционные штрихпунктирные линии 317 диалоговое окно 50
диалоговое окно для выбора цветов 326
Ж желоб-разделитель в контейнере 120 3
задание интервалов между виджетами в ящиках 86
заливка 306-307 запрещение доступа к пунктам меню 209 значение 368
И инкапсуляция 24 инсталляция исходного кода GNOME 458 интернационализация 446, 454-456
К
канал. См. конвейер канва 228, 230 карта цветности 299 каталог для разработки 459 клавиатура 332 клавиша-акселератор 188, 469 классы 24-25 базовые 24
компиляция программ 33 компоновка программ 34, 36 конвейер 602
контейнер 68
аспектный обрамляющий 118
записная книжка 129
настроенный 111
обрамляющий 114-118
с панелями 120
скроллинговый оконный 127
слоистый 123
фиксированный 108
контейнеры 26
конфигурация
настройки 446
установки 446
косой стык 317
курсор 169
горячая точка 169-170
отображение 171
создание 169, 176
М
манипулятор в контейнере с панелями 120
меню 183
всплывающее 198
иерархическая форма 184
кнопки 183
макросы, используемые для создания
187, 191-192
отрывное 184
скрытый пункт 213
создание 183-188
типы 188
методы 24-25
многоточечная функция 273
модальное окно 52
мышь 232
события 239
типы событий 239
н
наследование 24
незавершенное окончание 317
О
область для рисования 271-272
изменение размеров 291-293
основы рисования 271-273
объектно-ориентированное программирование 23
объектно-ориентированные языки программирования 23
объекты
инкапсуляция 24 наследование 24-25 реализация 25
однородные виджеты 80
одноточечная функция 273
окца верхнего уровня 38 окружение
вектор 450
данные файлов конфигурации 451-454 категория 447 ключ 447
расположение файла конфигурации 447 управление 446
файлы конфигурации 446-449
опция 368
основной цвет 307
отображение пунктов меню 213
отображение элементов панели инструментов
216
очередь событий 140
ошибка периода выполнения 459
П
панель инструментов 183, 200
параметр 368
переключатели 222-224 в меню 222
на панели инструментов 224
перекрывающиеся виджеты 101
перемещение компонента канвы 243
перетащить 398
покрытие 307 полигон 255-257.
полиморфизм 25
преобразование графических форматов 163 пригонка размеров
вертикального ящика 78 горизонтального ящика 79
процесс выполнение 599 дочерний 599
идентификатор процесса 600 порождение 599 разветвление 599 родительский 599
Р радиокнопки 217-219 в меню 217 на панели инструментов 219 разрешение доступа к пунктам меню 209 растровое изображение монохромное 162 рисование 287-291 цветное 162 рисование и заливка криволинейных фигур 281-284 полигонов 278-281 прямоугольников 276-278
С семейство пиктограмм 202 сигналы 27 базовых классов 145 динамическое определение 145 идентификаторы 144 наименования 144-145 создание 142-144 функции обратного вызова 144 скругленное окончание 317 скругленное соединение 317 события 27 события мыши 332-337 захват 337-341 реагирование 332-337 соглашения по наименованию, префиксы 22 сокрытие пунктов меню 213 сокрытие элементов панели инструментов 216 стили линий 311 стиль краев линий 317 строка отражения динамики процесса 63 * в автоматическом режиме 64 управляемая вручную из программы 64
т
таймеры 155 текст
на канве 247 рисование 285-287 торцевое окончание 317
У
упаковка виджетов 76
с помощью таблиц 76, 92
с помощью ящиков 76
установка 368
утечка памяти 459
ф
файлы FIFO 158
файлы подсказки 197
фацетное соединение 316
фоновый цвет 307
функции обратного вызова 27
выдача ваших собственных сигналов 144
параметры 145
прототипы 145, 150 форматы 145
функция простоя 153
ш
шрифты анатомия 353-355 метрики 360 наименования 355-357 размещение 365-366
Я
ящик с кнопками 133
Общедоступная лицензия GNU
(приводится в оригинальном виде)
GNU General Public License
Version 2, June 1991
Copyright (c) 1989, 1991 Free Software Foundation, Inc. *
675 Mass Ave., Cambridge, MA 02139, USA
Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software — to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation’s software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too.
When we speak offree software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things.'
To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether gratis or for a fee, you' must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.
We protect your rights with two steps: (1) copyright the software, and (2) offer you this license, which gives you legal permission to copy, distribute, and/or modify the software.
Also, for each author’s protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors’ reputations.
Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in
effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone’s free use or not licensed at all.
The precise terms and conditions for copying, distribution and modification follow.
Terms and Conditions for Copying, Distribution, and Modification
0.' This License applies to any program or other work that contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The “Program,” below, refers to any such program or work, and a “work based on the Program” means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term “modification.”) Each licensee is addressed as “you.”
Activities other than copying, distribution, and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.
You may copy and distribute verbatim copies of the Program’s source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program.
You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee..
You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:
You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.
You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.
If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: If the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered
independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole that is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program.
In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not, bring the other work under the scope of this License.
You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:
Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete, machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection (b) above.)
The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so forth) of the operating system on which the executable runs, unless that component itself accompanies the executable.
If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.
You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, or distribute the Program is void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.
You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.
Each4ime you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute, or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients’ exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License.
If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances.
' It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. ' This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.
If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.
The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
IM
Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and “any later version,” you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.
If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.
No Warranty
BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING, THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR, OR CORRECTION.
12.IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
End of Terms and Conditions
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software that everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the “copyright” line and a pointer to where the full notice is found:
<One line to give the program’s name and a brief idea of what it does.>
Copyright (c) 19yy (name of author)
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either Version 2 of the License or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this when it starts in an interactive mode:
Gnomovision version 69, Copyright (c) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type 'show w'
This is free software, and you are welcome to redistribute it under certain conditions; type 'show c' for details.
The hypothetical commands show w and show c should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than show w and show c; they could even be mouse-clicks or menu items — whatever suits your program.
You should also get your employer (if you work as a programmer) or your school, if any, to sign a “copyright disclaimer” for the program, if necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program “Gnomovision” (which makes passes at compilers) written by James Hacker.
x (signature of Ту Coon), 1 April 1989
Ту Coon, President of Vice
This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License.
Инструкция по инсталляции с компакт-диска
Вставьте компакт-диск (CD-ROM) в ваш дисковод для компакт-дисков. Если он не монтируется автоматически, вы можете смонтировать его вручную с помощью следующих двух команд:
cd /mnt
mount cdrom
Как только CD-ROM смонтируется, его содержимое появится в каталоге /mnt/cdrom. Linux может автоматически монтировать CD-ROM при добавлении следующей строки в файл /etc/fstab:
/dev/cdrom /mnt/cdrom iso9660 noauto,owner,ro 0 0
Содержимое компакт-диска описывает имеющийся на нем файл README.
Образцы исходного кода из книги хранятся в каталоге examples. Вы можете просмотреть и скопировать "исходники” прямо с компакт-диска. Содержимое каждого отдельного каталога может быть скопировано и откомпилировано с помощью находящегося в нем makefile. Кроме того, вы можете сдублировать полное дерево с примерами исходного кода, используя утилиту tar для извлечения дерева из файла examples • tgz.
Исходный код GNOME и GTK+ содержится в заархивированных и сжатых файлах. Каталоги /mnt/cdrom/gnome/base и /mnt/cdrom/gnome/core содержат исходный код библиотек разработки GNOME и GTK+. Чтобы применить этот исходный код, выберите рабочий каталог на вашем жестком диске и используйте tar для его распаковки. К каждому файлу прилагаются инструкции по инсталляции.
Исходный код утилит разработки программного обеспечения находится в tar-файлах в каталоге /mnt/cdrom/tools.
В приложении А содержится информация по распаковке и инсталляции файлов с компакт-диска.
Чтобы убрать CD-ROM, его необходимо прежде демонтировать, что может быть выполнено с помощью одной из следующих команд:
umount /mnt/cdrom
или
eject