Программирование на Gtk/Perl

(все, что посвящено разработке или переодам по поводу Gtk, может быть подверженно исправленям, т.к. могут быть выявлены некоторые новые ошибки)

Начиная введение в Gtk-perl, приведем пример простейшей программы. Эта программа создает маленькое окошко с одной кнопкой, на которой написано "Прощай, Мир!". Нажимая на кнопку или закрывая окно, мы закончим действие программы.

      
#!/usr/bin/perl -w

use Gtk;         # загрузить Gtk-perl модуль
use strict;      # хорошая идея для всех нетривиальных perl-скриптов

set_locale Gtk;  # локализация
init Gtk;        # инициализация Gtk-Perl

# для удобства объявим переменные true и false
my $false = 0;
my $true = 1;

# создаем виджет
my $window = new Gtk::Window( "toplevel" );
my $button = new Gtk::Button( "Прощай, Мир!" );

# регистрация отзыва
$window->signal_connect( "delete_event", \&CloseAppWindow );   
$button->signal_connect( "clicked", \&CloseAppWindow );

# показать кнопку
$button->show();

# установить атрибуты окна и показать его
$window->border_width( 15 );
$window->add( $button );
$window->show();

# вызываем Gtk
main Gtk;

# конец программы
exit(0);

### Вызвать подпрограмму, закрывающую окно
sub CloseAppWindow{
   Gtk->exit(0);
   return $false
}

Разберем работу программы.

use Gtk; необходимо во всех Gtk-Perl программах. Данная строчка позволяет Перлу использовать переменные, функции, структуры, и т.д., которые определены в GTK.

init Gtk; также необходимо включать во все Ctk-Perl программы. Эта строка инициализирует модуль Gtk и определяет некоторые вещи вроде цветовой палитры или вида графического вывода.

set_locale Gtk; локализация, необходимая для корректного написания языков, с отличной от латиницы символикой.

new Ctk::Window() создает новое окно. Window Manager определяет как и где быдет выводиться создаваемое окно. Все GUI виджеты располагаются внутри нового окна, также вы можете создавать больше окон в своей программе. Вы также можете создавать диалоговые окна, используя new Gtk::Dialog();

new Gtk::Button(); создает новое окно. В нашем примере мы создаем одну кнопку с тектовым полем. Что произойдет если не поставить текст внутри кнопки? Gtk автоматически подстраивает размер окна в зависимости от длинны набранного на кнопке текста.

Функция border_width() берет container(например window) и устанавливает размер свободного места вокруг кнопки. Параметр, передаваемый функции(в пикселах), является шириной отступа.

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

Функция add() создает виджет и добавлет его в контейнет(в нашем примере на окно). Если вы не добавите эту функцию, то не увидите кнопку, потому, что её не будет внутри созданного Gtk окна.

Функция show() делает виджет видимым. Не выполняйте show() до того, как определите все свойства виджета. Если создается несколько дочерних виджетов, то их необходимо создавать до родительского виджета(т.е. показать кнопку до показа содержащего её окна).

main Gtk; запускает основной обработчик событий Gtk. Эта строчка должна всегда находится в каждой Cgk-Perl программе. Когда компилятор достигнет этой строки, Gtk приостановит события для X-сервера(такие как нажатие клавиши или мышиной кнопки), таймауты или file IO до получения соответствующего сигнала.

Последняя подпрограмма вызывается, когда происходит нажате кнопки или закрыте окна.

Обзор виджетов. создание виджета: Основные шаги для создание виджета в Gtk-Perl:

  1. new Gtk::Widget() - функция, создающая виждет.
  2. Обработка сигналов и событий, которые генерируются для управления программой.
  3. Установка атрибутов виджету.
  4. Привязка виджета в контейнеру, используя ссылки подобные $container->add(); или $box->pack_start();
  5. show() - вывод виджета на экран.

show() говорит Gtk-Perl что виджету выставлены все атрибуты и он может быть показан на экране. Можно так-же использовать hide() для скрытия виджета. Порядок, в котором будут выведены виждеты, не важен, но лучше, если виджет будет выведен сразу после его создания(некоторый стиль написания). Поотомки родительского виждета(window так-же явялется виждетом) появятся только тогда, когда будет показан их парент.

Иерархия виждетов показана в виде иерархии классов, в котором базовым для всего Gtk является класс Gtk::Object:

       Gtk::Object
         +-Gtk::Widget
         |   +-Gtk::Misc
         |   |   +-Gtk::Label
         |   |   |   +-Gtk::AccelLabel
         |   |   |   +-Gtk::TipsQuery
         |   |   +-Gtk::Arrow
         |   |   +-Gtk::Image
         |   |   +-Gtk::Pixmap
         |   +-Gtk::Container
         |   |   +-Gtk::Bin
         |   |   |   +-Gtk::Alignment
         |   |   |   +-Gtk::Frame
         |   |   |   |   +-Gtk::AspectFrame
         |   |   |   +-Gtk::Button
         |   |   |   |   +-Gtk::ToggleButton
         |   |   |   |   |   +-Gtk::CheckButton
         |   |   |   |   |       +-Gtk::RadioButton
         |   |   |   |   +-Gtk::OptionMenu
         |   |   |   +-Gtk::Item
         |   |   |   |   +-Gtk::MenuItem
         |   |   |   |   |   +-Gtk::CheckMenuItem
         |   |   |   |   |   |   +-Gtk::RadioMenuItem
         |   |   |   |   |   +-Gtk::TearoffMenuItem
         |   |   |   |   +-Gtk::ListItem
         |   |   |   |   +-Gtk::TreeItem
         |   |   |   +-Gtk::Window
         |   |   |   |   +-Gtk::ColorSelectionDialog
         |   |   |   |   +-Gtk::Dialog
         |   |   |   |   |   +-Gtk::InputDialog
         |   |   |   |   +-Gtk::DrawWindow
         |   |   |   |   +-Gtk::FileSelection
         |   |   |   |   +-Gtk::FontSelectionDialog
         |   |   |   |   +-Gtk::Plug
         |   |   |   +-Gtk::EventBox
         |   |   |   +-Gtk::HandleBox
         |   |   |   +-Gtk::ScrolledWindow
         |   |   |   +-Gtk::Viewport
         |   |   +-Gtk::Box
         |   |   |   +-Gtk::ButtonBox
         |   |   |   |   +-Gtk::HButtonBox
         |   |   |   |   +-Gtk::VButtonBox
         |   |   |   +-Gtk::VBox
         |   |   |   |   +-Gtk::ColorSelection
         |   |   |   |   +-Gtk::GammaCurve
         |   |   |   +-Gtk::HBox
         |   |   |   +-Gtk::Combo
         |   |   |   +-Gtk::Statusbar
         |   |   +-Gtk::CList
         |   |   |   +-Gtk::CTree
         |   |   +-Gtk::Fixed
         |   |   +-Gtk::Notebook
         |   |   |   +-Gtk::FontSelection
         |   |   +-Gtk::Paned
         |   |   |   +-Gtk::HPaned
         |   |   |   +-Gtk::VPaned
         |   |   +-Gtk::Layout
         |   |   +-Gtk::List
         |   |   +-Gtk::MenuShell
         |   |   |   +-Gtk::MenuBar
         |   |   |   +-Gtk::Menu
         |   |   +-Gtk::Packer
         |   |   +-Gtk::Socket
         |   |   +-Gtk::Table
         |   |   +-Gtk::Toolbar
         |   |   +-Gtk::Tree
         |   +-Gtk::Calendar
         |   +-Gtk::DrawingArea
         |   |   +-Gtk::Curve
         |   +-Gtk::Editable
         |   |   +-Gtk::Entry
         |   |   |   +-Gtk::SpinButton
         |   |   +-Gtk::Text
         |   +-Gtk::Ruler
         |   |   +-Gtk::HRuler
         |   |   +-Gtk::VRuler
         |   +-Gtk::Range
         |   |   +-Gtk::Scale
         |   |   |   +-Gtk::HScale
         |   |   |   +-Gtk::VScale
         |   |   +-Gtk::Scrollbar
         |   |       +-Gtk::HScrollbar
         |   |       +-Gtk::VScrollbar
         |   +-Gtk::Separator
         |   |   +-Gtk::HSeparator
         |   |   +-Gtk::VSeparator
         |   +-Gtk::Preview
         |   +-Gtk::Progress
         |       +-Gtk::ProgressBar
         +-Gtk::Data
         |   +-Gtk::Adjustment
         |   +-Gtk::Tooltips
         +-Gtk::ItemFactory

Знание этой иерархии важно, так как позволяет знать, какую функцию можно вызывать в кждом виджете. Для примера, SpinButton виджет относится к классу методов Entry, который в свою очередь является методом Editable и так далее.

Следующие виджеты не ассоциированы с окнами. Если вы хотите обработать событие, то вы можете использовать EventBox.

Gtk::Alignment
Gtk::Arrow
Gtk::Bin
Gtk::Box
Gtk::Image
Gtk::Item
Gtk::Label
Gtk::Pixmap
Gtk::ScrolledWindow
Gtk::Separator
Gtk::Table
Gtk::AspectFrame
Gtk::Frame
Gtk::VBox
Gtk::HBox
Gtk::VSeparator
Gtk::HSeparator

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

Создание и уничтожение виджетов.

Для создания виджета используйте

$widget = new Gtk::Widget();

Но помните, что при создании некоторых виджетов может понадобится несколько функций new() подобно функции new_with_label() для кнопок и деревьев.

Уничтожить виджет можно при помощи строчки

$widget -> destroy();

Если будет получен вызов зарезервированный как destroy, то он быдет выполнен для текущего виджета, но не для объекта, породившего этот виджет.

Вывод и скртыие виджетов.

Следующие две функции показа и скрытия виджета уже были использованы нами в формах,Они показывают и скрывают виджет:

$widget->show();

$widget->show_now();

$widget->show_all();

$widget->hide();

$widget->hide_all();

Отметим, что если не показан контейнер, то не показан и виджет, содержащийся в этом контейнере. Рекомендуется, чтобы widgets показывался до содержания контейнеров, хотя точный порядок обычно не имеет значения, если окно показывается последним.

Показ и запрет показа виджетов

$widget->realize();

$widget->unrealize(); 

Показ необходим, когдавы хотите создать видет используя GdkWindow с запросом к X серверу. При нормальном раскладе виджет будет показан когда будет запрошена функция show(), но иногда бывает необходимо вызвать realize() до вызова show(). Основное правило заключается в том, что как правило существует лучший выход из ситуации, которая провоцирет вызов realize() до вызова show(). Вобщем короче нужно четко знать что ты делаешь в таком случае и не рекомендуется использвать первую функцию без особой в том нужды.

Фокус и виджет по умолчанию

Gtk-perl позволяет виждету считывать фокус с клавиатуры используя следующую функцию

$widget->grab_focus();

Виджет также может быть установлен в режим по умолчанию, это можно сделать следующими строчками:

$widget->can_default( $default );

$widget->grab_default(); 

Запомните, что нужно вызывать can_default() до вызова grab_default(). Аргументом функции can_default() может быть истина или ложь, определяющие может ли быть виджет введен в режим по умолчанию.

Чувствительность виджета

Нечувствительный виджет не отвечает на ввод. Он может так-же обозначаться как бездействующий виджет. Установить чувствительность виджета можно, используя следующую функцию:

$widget->set_sensitive( $sensitive ); 

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

$widget->sensitive();

$widget->is_sensitive(); 

отличие этих функций в том, что первая только проверяет widgets на чувствительнсть, в то время как вторая проверяет чувствительность всей иерархии порожденых виждетов. Только вторая функция сообщит, является widget чувствительным или нет.

Установка положения и размера виджета

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

$widget->set_uposition( $x, $y );

$widget->set_usize( $width, $height ); 

Функция set_uposition() устанавливает левый верхний угод виджета на экране монитора на $x пикелов слева и $y пикселов сверху. Функция set_usize() устанавливает положение виджета с шириной в $width и высотой в $height пикселов сответственно. Необходимо быть осторожным при установке параметров виждетов, например если программа будет использоваться людьми со слабым зрением, то им нехобходимо увеличить размер управляющих кнопок, или просто позволить настроить программу под себя, В то-же время, если в программе используется показ деревьев каталогов, списков и или иных стандартных объектов, виджет должен быт стрго фиксирован в зависимости от числа и типа окна, дерева или иной специфичной для XWindow оболочки графической структуры.

Расположение виджетов в форме

При создании приложения, вам будет необходимо расположить более одного виджета на формочке, ооветственной за все приложение. В первом примере была всего одна кнопка, и поэтому можно было использовать простую конструкцию $window->add() чтобы поместить виджет в окно. Но когда нужно поместить более одного виджета, необходимо их позиционировать относительно друг друга, с тем чтобы создать некий интерфейс к создаваемому Вами приложению.

Packing boxes - невидимые widget контейнеры, в которых располагаются вджеты. Packing boxes имееют две формы: горизонтальную и вертикальную. При помещении widgets в горизонтальный бокс, объекты вставлены горизонтально слева направо или наоборот в зависимости от используемого запроса. В вертикальном боксе, widgets упакованы сверху донизу или наоборот. Вы можете использовать любую комбинацию боксов для расположения виджетов внутри или рядом с двругими Packing boxes, чтобы придать желательные эффект и дизайн вашему приложению. Для создания нового горизонтального или вертикального бокса, нужно написать следующие строчки:

$hbox = new Gtk::HBox( $homogeneous, $spacing );

$vbox = new Gtk::VBox( $homogeneous, $spacing ); 

Иерархия наследования

Object
   +--- Widget
         +--- Container
               +--- Box

Если переменная $homogeneous истинна, то виждет можно располагать в пределах, определяемых HBox и Vbox. Переменная $spacing определяет границу в пикселах, на которую отстоят виджеты друг от друга. Следующие функции используются для расположения объектов внутри бокса:

$box->pack_start( $child, $expand, $fill, $padding );

$box->pack_end( $child, $expand, $fill, $padding ); 

Функция pack_start() располагает элементы списка сверху в VBox и соответственно в слева направо в HBox. Действие функции pack_end() противоположно действию pack_start(). Добавленный объект может быть другим контейнером, например много виджетов - те-же самые контейнеры, за исключением что в аких случаях как правло используются либо pixmaps либо кнопки. Расположенный виджет в боксе является дочерним к этому боксу.

Если аргумент $expand истеннен, то виджеты расположены в боксе так, что заполняют все место, если аргумент ложен, то бокс сокращается до размера виджета. Присваивая параметру расширения ложное значение виждет будет выравниваться по левому или правому краю в зависимости от желания. Следует отметить, что присваивание переменное $homogeneous значение true аналогично присваиванию значения ture переменной $expand.

Если аргумент $fill истеннен, тогда дополнительное место распределено между объектами. В другом случае дополнительное свободное место распределяется между виджетами. Такое распределение возможно когда $expand выставлен в положение true.

Используя данные вариации, Gtk знает, где Вы хотите разместить ваш widgets, и автоматически может изменять размер виджета и другие изящные вещи. Вобщем использование данного метода дает немного гибкости при размещении и создании widgets.

Из-за этой гибкости боксы в GTK могут быть немного запутанны. Есть много различных способов расположения виджетов и не сразу очевидно, как они взаимодействуют между собой. В основном есть 5 различных стилей размещения, примеры которых приведены ниже:

Каждая линия примера содержит один горизонтальный бокс с несколькими кнопками. Запрос pack записывается для каждого pack отвечающего за кнопку внутри hbox. Каждая из кнопок помещается в hbox различными способами(то есть, те же самые аргументы подходят для функции pack_start()). Метод является быстрым вызовом из pack_start() и pack_end(), которые устанавливают растягивающую виджет переменную в true, заполняют её и устанавливают переменную в 0:

$box->pack_start_defaults( $widget );

$box->pack_end_defaults( $widget );

Однотипная переменная бокса, в котором располагаются виджеты, может быть установлена в on или off при помощи следующей функции:

$box->set_homogeneous( $homogeneous );

Переменная устанваливающая отступы вокруг виджета, может быть установлена при помощи функции

$box->set_spacing( $spacing );

Если Вы хотите перестить потомка на новое место, то нужно использовать функцию

$box->reorder_child( $child, $position ); 

где $child - перемещаемый виджет и $position - позиция для перемещения, начиная с 0. Если Вы хотите рассмотреть текущий порядок, то нежно смотреть на список, возвращаемый функцией children() (унаследованной от Container). Если необходимо изменить установку потомка, то используется следующая функция:

$box->set_child_packing( $widget, $expand, $fill, $padding, $pack_type ); 

Аргументы этой функции похожи на аргументы pack_start() и pack_end(), за исключением $pack_type(), которая может принимать значения либо 'start' либо 'end'. Каково различие между интервалом и дополнением? Интервал добавлен между объектами, а дополнение добавлено с обоих сторон объекта. Приведенная картинка поясняет сказанное более ясно:

Приведенная ниже программа показывает, как реализовать некоторые из типов расположения структур в приложении:

#!/usr/bin/perl -w

use Gtk;
use strict;

set_locale Gtk;
init Gtk;

unless ($ARGV[0]){
    print( "Использование: выберите тип расположения 1, 2, или 3.\n" );
    Gtk->exit( 1 );
    exit( 1 );
  }

my $false = 0;
my $true = 1;
my $which = $ARGV[0];
my ($window,$box1,$box2,$label,$separator,$quitbox,$button);

# Вы должны всегда определять обработчик сигнала
# delete_event для основного окна
# Это очень важно для верного поведения програмы в случае сбоев
$window = new Gtk::Window( "toplevel" );
$window->signal_connect( "delete_event", sub { Gtk->exit( 0 ); } );
$window->border_width( 10 );

# Мы создаем вертикальный бокс(vbox), и затем в него 
# ставим горизонтальные боксы. Такое расположение позволяет
# расставлять горизонтальные боксы, заполненные кнопками, один над другим
$box1 = new Gtk::VBox( $false, 0 );

# какой пример, соответствующий изображениям выше, показывать
if ( $which == 1 )
  {
    # создаем новый лейбл.
    $label = new Gtk::Label( 'new Gtk::HBox( $false, 0 );' );
    # Выравниваем его по левой стороне. Описание этой функции ниже.
    $label->set_alignment( 0, 0 );
    # Поместить лейбл в вертикальный бокс(vbox box1). Запомните, что
    # эти виджеты добавляются в vbox, который будет расположен свеху
    # остальных
    $box1->pack_start( $label, $false, $false, 0 );
    
    # показываем лейбл
    $label->show();

    # запрашиваем нашу создаваемую box функцию
    # homogeneous = FALSE, spacing = 0, 
    # expand = FALSE, fill = FALSE, padding = 0
    $box2 = make_box( $false, 0, $false, $false, 0 );
    $box1->pack_start( $box2, $false, $false, 0 );
    $box2->show();

    # запрашиваем создающую бокс функцию 
    # homogeneous = FALSE, spacing = 0,
    # expand = TRUE, fill = FALSE, padding = 0
    $box2 = make_box( $false, 0, $true, $false, 0 );
    $box1->pack_start( $box2, $false, $false, 0 );
    $box2->show();
    
    # Аргументы следующие: homogeneous, spacing, expand, fill, padding
    $box2 = make_box( $false, 0, $true, $true, 0 );
    $box1->pack_start( $box2, $false, $false, 0 );
    $box2->show();

    # Создаем разделитель, описание позднее.
    $separator = new Gtk::HSeparator();
    
    # Устанавливаем сепаратор в vbox, помните, 
    # что каждый из этих widgets упаковывается в vbox,
    # так что они будут сложены вертикально 
    $box1->pack_start( $separator, $false, $true, 5 );
    $separator->show();
    
    # Создаем другой лейбл и показываем
    $label = new Gtk::Label( 'new Gtk::HBox( $true, 0 );' );
    $label->set_alignment( 0, 0 );
    $box1->pack_start( $label, $false, $false, 0 );
    $label->show();
    
    # Аргументы: homogeneous, spacing, expand, fill, padding
    $box2 = make_box( $true, 0, $true, $false, 0 );
    $box1->pack_start( $box2, $false, $false, 0 );
    $box2->show();
    
    # Аргументы: homogeneous, spacing, expand, fill, padding
    $box2 = make_box( $true, 0, $true, $true, 0 );
    $box1->pack_start( $box2, $false, $false, 0 );
    $box2->show();
    
    # Другой новый сепаратор.
    $separator = new Gtk::HSeparator();
    
    # Последние три аргумента gtk_box_pack_start:
    # expand, fill, padding.
    $box1->pack_start( $separator, $false, $true, 5 );
    $separator->show();
  }
elsif ( $which == 2 )
  {
    # Создаем новый лейбл, запомните, что box1 это vbox
    $label = new Gtk::Label( 'new Gtk::HBox( $false, 10 );' );
    $label->set_alignment( 0, 0 );
    $box1->pack_start( $label, $false, $false, 0 );
    $label->show();
    
    # Аргументы: homogeneous, spacing, expand, fill, padding
    $box2 = make_box( $false, 10, $true, $false, 0 );
    $box1->pack_start( $box2, $false, $false, 0 );
    $box2->show();
    
    # Аргументы: homogeneous, spacing, expand, fill, padding
    $box2 = make_box( $false, 10, $true, $true, 0 );
    $box1->pack_start( $box2, $false, $false, 0 );
    $box2->show();
    
    $separator = new Gtk::HSeparator();
    # Последние три аргумента gtk_box_pack_start: expand, fill,
    # и padding.
    $box1->pack_start( $separator, $false, $true, 5 );
    $separator->show();
    
    $label = new Gtk::Label( 'new Gtk::HBox( $false, 0 );' );
    $label->set_alignment( 0, 0 );
    $box1->pack_start( $label, $false, $false, 0 );
    $label->show();
    
    # Аргументы: homogeneous, spacing, expand, fill, padding
    $box2 = make_box( $false, 0, $true, $false, 10 );
    $box1->pack_start( $box2, $false, $false, 0 );
    $box2->show();
    
    # Аргументы: homogeneous, spacing, expand, fill, padding
    $box2 = make_box( $false, 0, $true, $true, 10 );
    $box1->pack_start( $box2, $false, $false, 0 );
    $box2->show();
    
    $separator = new Gtk::HSeparator();
    # Последние три аргумента: expand, fill,
    # и padding.
    $box1->pack_start( $separator, $false, $true, 5);
    $separator->show();
  }
elsif ( $which == 3 )
  {
    # этот пример показывает, как pack_end() выравнивает
    # widgets по правому краю. Создаем новый box.
    $box2 = make_box( $false, 0, $false, $false, 0);
    
    # Создаем новый лейбл, который будет установлен в конец.
    $label = new Gtk::Label( "end" );
    # Установка с применением gtk_box_pack_end(), 
    $box2->pack_end( $label, $false, $false, 0 );
    # показываем лейбл.
    $label->show();
    
    # Помещаем box2 в box1
    $box1->pack_start( $box2, $false, $false, 0 );
    $box2->show();
    
    # Сепаратор снизу
    $separator = new Gtk::HSeparator();
    # далее подробно устанавливаем параметры разделителя
    # в 400 пикселов и ширинойц и 5 пикселов высотой
    # так-же это значит, что hbox быдет создан шириной в 400 пикселов 
    # и ярлык "end" будет отделен от других лейблов в hbox.
    # В противном случае все лейблы будут прилегать друг к другу вплотную
    $separator->set_usize( 400, 5 );
    # добавить сепаратор в vbox(box1), созданный вначале программы
    $box1->pack_start( $separator, $false, $true, 5 );
    $separator->show();    
  }

# создать другой бокс, 
$quitbox = new Gtk::HBox( $false, 0 );

# создаем кнопку выход.
$button = new Gtk::Button( "Quit" );

# Послать сигнал для завершения программы, когда кнопка будет нажата
$button->signal_connect( "clicked", sub { Gtk->exit( 0 ); } );
# Добавить кнопку в quitbox
# последние три аргумента gtk_box_pack_start:
# expand, fill, padding.
$quitbox->pack_start( $button, $true, $false, 0 );
# добавить quitbox в vbox (box1)
$box1->pack_start( $quitbox, $false, $false, 0 );

# Добавить vbox(box1) который теперь содержит все наши виджеты в основное окно
$window->add( $box1 );

# и показать все слева
$button->show();
$quitbox->show();

$box1->show();
# Показ всего окна со всеми лейблами и кнопками.
$window->show();

# вызов основной функции.
main Gtk;
exit(0);



# создаем новый hbox, заполненный кнопками и лейбралми. 
# Мы не показываем сам бокс, но показываем его содержимое 

sub make_box{
    my ($homogeneous,$spacing,$expand,$fill,$padding) = @_;
    # создаем новый hbox с соответствующими установками типов и отступов
    my $box = new Gtk::HBox( $homogeneous, $spacing );
    $button = new Gtk::Button( '$box->' );
    $box->pack_start( $button, $expand, $fill, $padding );
    $button->show();
    
    # Create a series of buttons with the appropriate settings
    # Создаем серию кнопок с соответствующими настройками
    $button = new Gtk::Button( "pack" );
    $box->pack_start( $button, $expand, $fill, $padding );
    $button->show();
    
    $button = new Gtk::Button( '( $button,' );
    $box->pack_start( $button, $expand, $fill, $padding );
    $button->show();
    
    # создаем кнопку с лейблом, зависящим от переменной, отвечающей за растягивание
    if ($expand){
      $button = new Gtk::Button('$true,');
    } else {
      $button = new Gtk::Button('$false,');
    }
    
    $box->pack_start( $button, $expand, $fill, $padding );
    $button->show();
    if ( $fill ) {
      $button = new Gtk::Button( '$true,' );
    } else {
      $button = new Gtk::Button( '$false,' );
    }
    
    $box->pack_start( $button, $expand, $fill, $padding );
    $button->show();
    
    $button = new Gtk::Button( "$padding );" );
    $box->pack_start( $button, $expand, $fill, $padding );
    $button->show();
    
    return ( $box );
  }