Библиотека сайта rus-linux.net
Программирование с использованием gtkmm 3. Контейнерные виджеты
Оригинал: Programming with gtkmm 3
Авторы: Murray Cumming, Bernhard Rieder, Jonathon Jongsma, Ole Laursen, Marko Anastasov, Daniel Elstner, Chris Vine, David King, Pedro Ferreira, Kjell Ahlstedt
Перевод: А.Панин
8.2. Контейнеры для множества виджетов
Класс контейнеров для множества виджетов наследуется от класса Gtk::Container
; как и при работе с классом Gtk::Bin
, вы можете использовать методы add()
и remove()
для добавления и удаления хранимых виджетов. Однако, в отличие от метода Gtk::Bin::remove()
, метод remove()
класса Gtk::Container
принимает аргумент, указывающий на то, какой виджет следует удалить.
8.2.1. Упаковка
Вы наверняка заметили, что окна, созданные с помощью gtkmm, являются "эластичными" - обычно их размер может изменяться различными способами. Такое поведение обусловлено применением системы упаковки виджетов (widget packing system).
- Виджеты не изменяют свое расположение при изменении размера окна. Некоторые виджеты скрываются в том случае, если размер окна уменьшается, при этом появляется много неиспользуемого пространства в том случае, если размер окна увеличивается.
- Невозможно предугадать потребность в пространстве при использовании строк в случае перевода их на другие языки или показа их с использованием другого шрифта. В Unix также невозможно предвидеть последствия использования каждой из тем и каждого из менеджеров окон.
- Изменение конфигурации окна "на лету" для показа некоторых виджетов, к примеру, является достаточно сложной операцией. Она требует сложных расчетов для вычисления позиции каждого из виджетов.
gtkmm использует систему упаковки виджетов для решения описанных проблем. Вместо указания позиции и размера каждого из виджетов в окне, вы можете упорядочить виджеты с использованием строк, столбцов и/или таблиц. gtkmm позволяет устанавливать размер вашего окна автоматически на основе размеров содержащихся в нем виджетов. А размеры виджетов, в свою очередь, устанавливаются на основании объема текста, который они содержат, или указанных вами минимального и максимального размеров и/или установленной вами стратегии распределения доступного пространства между наборами виджетов. Вы можете улучшить распределение виджетов, указав размеры пустых областей и параметры центрирования для каждого из ваших виджетов. Впоследствии gtkmm использует всю эту информацию для изменения размера и позиции всех элементов разумно и плавно тогда, когда пользователь производит манипуляции с окном.
gtkmm производит иерархическое распределение виджетов с помощью контейнеров (containers). Контейнерный виджет может содержать другие виджеты. Большинство предоставляемых gtkmm виджетов являются контейнерами. Окна, вкладки наборов страниц и кнопки являются контейнерными виджетами. Существует два типа контейнеров: контейнеры для хранения одного дочернего виджета, представленные унаследованными от класса Gtk::Bin
классами и контейнеры для хранения множества виджетов, представленные унаследованными от класса Gtk::Container
классами. Большинство классов предоставляемых gtkmm виджетов, включая класс Gtk::Window
, унаследовано от класса Gtk:Bin
.
Gtk::Grid
и Gtk::Box
.
- Виджет, представленный классом
Gtk::Grid
, распределяет дочерние виджеты в строках и столбцах. Следует использовать методыattach()
,attach_next()
иadd()
для добавления дочерних виджетов. - Виджет, представленный классом
Gtk::Box
, распределяет виджеты в вертикальной и горизонтальной плоскостях. Следует использовать методыpack_start()
иpack_end()
для добавления дочерних виджетов.
Существует несколько других контейнеров, которые мы также обсудим.
Если вы ранее никогда не использовали тулкит с упаковкой виджетов, вам потребуется некоторое время для привыкания. Однако, скорее всего, вы переоцените необходимость визуальных редакторов форм, которые могут активно использоваться при работе с другими тулкитами.
8.2.2. Улучшенная программа Hello World
Давайте рассмотрим немного улучшенную программу helloworld
, демонстрирующую изученные нами подходы к разработке приложений.
Рисунок 8-6: Второй вариант программы Hello World
Файл helloworld.h
(Для использования совместно с gtkmm 3, а не с gtkmm 2)
Файл helloworld.cc
(Для использования совместно с gtkmm 3, а не с gtkmm 2)
Файл main.cc
(Для использования совместно с gtkmm 3, а не с gtkmm 2)
После сборки и запуска программы попробуйте изменить размер окна для ознакомления с его поведением. Также попробуйте изменить параметры метода pack_start()
в процессе чтения раздела "Контейнеры общего назначения".
8.2.3. Контейнеры общего назначения (Boxes)
Для упаковки большинства виджетов, как и в описанном выше примере, используются контейнеры общего назначения. Это невидимые контейнеры, в которые мы можем помещать наши виджеты. При упаковке виджетов с помощью горизонтального контейнера общего назначения объекты размещаются в горизонтальной плоскости слева направо или справа налево в зависимости от того, используется ли метод pack_start()
или pack_end()
. В вертикальном контейнере общего назначения виджеты размещаются сверху вниз или наоборот. Вы можете использовать любую комбинацию контейнеров общего назначения внутри или рядом с другими контейнерами общего назначения для создания желаемого интерфейса.
8.2.3.1. Добавление виджетов
8.2.3.1.1. Параметры упаковки для дочерних виджетов
Методы pack_start()
и pack_end()
позволяют разместить виджеты в описанных контейнерах. Метод pack_start()
начнет размещение виджетов сверху и будет размещать каждый новый виджет ниже предыдущего при условии использования контейнера общего назначения с вертикальной ориентацией или будет размещать виджеты слева направо в случае использования контейнера общего назначения с горизонтальной ориентацией. Метод pack_end()
будет работать с точностью наоборот, упаковывая виджеты снизу вверх или справа налево. Использование этих методов позволяет выравнивать виджеты по правой или левой стороне окна. Мы будем использовать метод pack_start()
в большинстве наших примеров.
Существует несколько параметров, влияющих на способ упаковки виджетов, которые могут смущать неопытных разработчиков. Если вы сталкиваетесь с проблемами при работе с контейнерами общего назначения, иногда хорошей идеей является использование инструмента проектирования графических пользовательских интерфейсов glade для ознакомления со всеми возможными вариантами упаковки. Вы можете даже принять решение о необходимости использования API Gtk::Builder для загрузки файла вашего графического пользовательского интерфейса в процессе работы приложения.
В общем случае можно выделить пять различных стилей, показанных на рисунке:
Рисунок 8-7: Упаковка виджетов с использованием контейнеров общего назначения 1
Каждая строка содержит один контейнер общего назначения с несколькими кнопками. Каждая из кнопок в строке упакована в контейнер общего назначения с использованием одних и тех же аргументов при вызове метода pack_start()
.
pack_start()
:
void pack_start(Gtk::Widget& child, Gtk::PackOptions options = Gtk::PACK_EXPAND_WIDGET, guint padding = 0);
В качестве первого аргумента выступает виджет, который вы упаковываете. В нашем примере это все кнопки из строки.
options
может передаваться одна из следующих трех констант:
Gtk::PACK_SHRINK
: Пространство выделяется в зависимости от размера дочернего виджета. Виджет займет достаточное пространство и никогда не будет расширяться.Gtk::PACK_EXPAND_PADDING
: Неиспользуемое пространство не используется виджетами. Виджеты будут равномерно растянуты, но их размеры не изменятся - вместо этого между виджетами будет свободное пространство.Gtk::PACK_EXPAND_WIDGET
: Дополнительное пространство будет занято виджетами с увеличенным размером, причем пространство между виджетами не будет затронуто.
Аргумент padding
указывает ширину дополнительной рамки вокруг упакованного виджета.
8.2.3.1.2. Параметры упаковки для контейнеров
Gtk::Box(Gtk::Orientation orientation = Gtk::ORIENTATION_HORIZONTAL, int spacing = 0); void set_spacing(int spacing); void set_homogeneous(bool homogeneous = true);
Передача логического значения true
методу set_homogeneous()
приведет к тому, что все дочерние виджеты будут иметь одинаковый размер. Аргумент spacing
устанавливает (минимальное) количество пикселей для использования в промежутках между виджетами.
Какая разница между параметром spacing
(устанавливаемым в момент создания контейнера общего назначения) и padding
(устанавливаемым тогда, когда элементы упаковываются)? С помощью параметра spacing
устанавливается размер промежутков между всеми объектами, а с помощью параметра padding
дополнительное пространство может быть добавлено с любой стороны виджета. Следующий рисунок должен дополнительно прояснить ситуацию:
Рисунок 8-8: Упаковка виджетов с использованием контейнеров общего назначения 2
8.2.3.2. Класс Gtk::Application и параметры командной строки
Gtk::Application
.
- Обработка параметров в рамках функции
main()
и сокрытие их от механизма классаGtk::Application
путем установки значенияargc = 1
при вызовеGtk::Application::create()
. - Передача всех аргументов командной строки методу
Gtk::Application::create()
с добавлением флагаGio::APPLICATION_HANDLES_COMMAND_LINE
. Соединение обработчика сигнала с сигналом"command_line"
и последующая обработка параметров командной строки на уровне обработчика сигнала. Вы должны установить дополнительный параметрafter = false
в вызовеsignal_command_line().connect()
, так как ваш обработчик сигнала должен вызываться до стандартного обработчика сигнала. Вы также должны вызватьGio::Application::activate()
в обработчике сигнала, если вы не хотите, чтобы ваше приложение завершило свою работу без показа главного окна. (КлассGio::Application
является базовым классом для классаGtk::Application
).
8.2.3.3. Пример
Ниже приведен пример исходного кода, который использовался для сборки программ, изображения окон которых были показаны выше. При запуске этого примера следует передать число в диапазоне от 1 до 3 в качестве параметра командной строки для ознакомления с различными параметрами упаковки.
Файл examplewindow.h
(Для использования совместно с gtkmm 3, а не с gtkmm 2)
Файл packbox.h
(для использования совместно с gtkmm 3, а не с gtkmm 2)
Файл packbox.cc
(Для использования совместно с gtkmm 3, а не с gtkmm 2)
Файл examplewindow.cc
(Для использования совместно с gtkmm 3, а не с gtkmm 2)
Файл main.cc
(Для использования совместно с gtkmm 3, а не с gtkmm 2)
Следующий раздел : 8.2.4. Контейнеры для кнопок (ButtonBoxes).