23.4.2. Упаковка виджитов, поля ввода и кнопки

23.4.2. Упаковка виджитов, поля ввода и кнопки

Для размещения (упаковки) виджита в окне используются контейнеры. Существуют два основных вида контейнеров. Первый вид в качестве прародителя использует объект класса GtkBin, а второй — объект класса GtkContainer. Контейнеры первого вида могут иметь только один дочерний виджит, поэтому они используются для создания специфических интерфейсов: одной кнопки, рамки, окна.

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

? GtkHBox — позволяет размещать виджиты горизонтально;

? GtkVBox — используется для вертикального размещения виджитов;

? GtkFixed — позволяет размещать виджиты в фиксированных координатах;

? GtkTable — позволяет упаковывать виджиты в виде таблицы.

Наиболее удачным, на мой взгляд, является контейнер GtkTable, поэтому в этом параграфе мы рассмотрим именно его. GtkTable может с успехом заменить и горизонтальный, и вертикальный контейнеры — что нам стоит задать таблицу, состоящую или одной строки или одного столбца?

Кроме контейнера GtkTable, в этом параграфе будут рассмотрены:

? поля для ввода текста и обработка введенной информации;

? кнопки;

? файловый ввод/вывод.

Сейчас мы напишем небольшой конфигуратор, который будет вносить изменения в файл /etc/resolv.conf. Напомню вам формат этого файла:

domain firma.ru

nameserver 192.168.0.1

nameserver 192.168.0.2

Директива domain определяет наш домен, а две директивы nameserver — первый и второй DNS-серверы, соответственно. Наш конфигуратор не будет вносить изменения в настоящий файл /etc/resolv.conf — для этого нужны права суперпользователя. При желании можно будет потом скопировать файл resolv.conf, сгенерированный нашей программой, в каталог /etc.

На рисунке 23.2 изображена уже готовая программа. Работает она так. Когда пользователь введет что-нибудь в поле ввода и нажмет Enter, программа отобразит введенный им текст на консоли. Когда пользователь нажмет OK, введенная им информация будет еще раз выведена на консоль и записана в файл. При нажатии кнопки Quit программа завершит свою работу. Она должна также завершить работу при нажатии кнопки закрытия окна — в GTK программист сам определяет реакции на стандартные кнопки.

Рис. 23.3. Учебный конфигуратор

Как видно из рисунка, нам понадобятся три поля ввода, три надписи и две кнопки. Поля ввода мы будем хранить в массиве:

GtkWidget *edit[3];

Создать поле для ввода можно с помощью функции gtk_entry_new():

edit[i] = gtk_entry_new();

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

gtk_entry_set_editable(GTK_ENTRY(edit[i]), 1);

Ну и, само собой разумеется, нужно установить реакцию на нажатие клавиши Enter — сигнал activate:

gtk_signal_connect(GTK_OBJECT(edit[i]), "activate",

GTK_SIGNAL_FUNC(enter_callback), edit[i]);

Весьма желательно на этапе отладки программы видеть введенную информацию на консоли. Для этого нужно написать такую функцию enter_callback(), которая выводила бы содержимое поля на консоль. Получить введенную пользователем информацию очень легко:

domain = gtk_entry_get_text(GTK_ENTRY(edit[0]));

dns1 = gtk_entry_get_text(GTK_ENTRY(edit[1]));

dns2 = gtk_entry_get_text(GTK_ENTRY(edit[2]))?

Реакция на нажатие кнопки OK будет следующей:

void writetofile(GtkWidget *widget, gpointer data) {

 /* С помощью функции gtk_entry_get_text() мы получаем

  введенный пользователем текст из полей ввода */

 domain = gtk_entry_get_text(GTK_ENTRY(edit[0]));

 dns1 = gtk_entry_get_text(GTK_ENTRY(edit[1]));

 dns2 = gtk_entry_get_text(GTK_ENTRY(edit[2]));

 /* Выводим прочитанный текст на консоль */

 g_print("Domain %s ", domain);

 g_print("DNS1 %s ", dns1);

 g_print("DNS2 %s ", dns2);

 /* Перезаписываем файл resolv.conf в текущем каталоге */

 if ((resolv = fopen("resolv.conf","w")) == NULL) {

  /* Наверное, нет места на диске или прав маловато... */

  g_print("ERR: Cannot open resolve.conf file ");

  gtk_main_quit();

 }

 /* Запись в файл */

 fprintf(resolv,"domain %s ",domain);

 fprintf(resolv, "nameserver %s ",dns1);

 fprintf(resolv,"nameserver %s *,dns2);

 fclose(resolv);

}

Если ваше окно должно содержать много надписей, то я рекомендую вам поступать так: объявить всего одну переменную, затем создать надпись, поместить ее в контейнер, затем опять создать надпись с использованием этой же переменной, поместить ее в контейнер и т.д. Примерно так:

label = gtk_label_new("Domain: ");

gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1);

gtk_widget_show(label);

label = gtk_label_new("DNS #1; ");

gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 1, 2);

gtk_widget_show (label);

label = gtk_label_new("DNS #2: ");

gtk_table_attach_defaults (GTK_TABLE(table), label, 0, 1, 2, 3);

gtk_widget_show (label);

Листинг 23.6 содержит полный код конфигуратора Resolver.

Листинг 23.6. Файл resolver.c

#include <gtk/gtk.h>

#include <stdlib.h>

#include <stdio.h>

gchar *domain, *dns1, *dns2;

/* Массив из трех полей ввода. Первое предназначено для

 ввода имени домена, два вторых - [1] и [2] - для ввода

 IP-адресов серверов DNS */

GtkWidget *edit[3];

/* Наш файл */

FILE *resolv;

/* Функция записи в файл */

void writetofile(GtkWidget *widget, gpointer data) {

 /* С помощью функции gtk_entry_get_text() мы получаем

  введенный пользователем текст из полей ввода */

 domain = gtk_entry_get_text(GTK_ENTRY(edit[0]));

 dns1 = gtk_entry_get_text(GTK_ENTRY(edit[1]));

 dns2 = gtk_entry_get_text(GTK_ENTRY(edit[2]));

 /* Выводим прочитанный текст на консоль */

 g_print("Domain %s ", domain);

 g_print("DNS1 %s ", dns1);

 g_print("DNS2 %s ", dns2);

 /* Перезаписываем файл resolv.conf в текущем каталоге */

 if ((resolv = fopen("resolv.conf","w")) == NULL) {

  /* Наверное, нет места на диске или прав маловато... */

  g_print("ERR: Cannot open resolve.conf file ");

  gtk_main_quit();

 }

 /* Запись в файл */

 fprintf(resolv,"domain %s ",domain);

 fprintf(resolv,"nameserver %s ",dns1);

 fprintf(resolv,"nameserver %s ",dns2);

 fclose(resolv);

}

/* Эта функция будет запущена, когда пользователь нажмет

кнопку закрытия окна или кнопку Quit */

gint delete_event(GtkWidget *widget, GdkEvent *event,

 gpointer data) {

 /* Функция gtk_main_quit() используется для завершения

  работы GTK-программы. Не нужно для этого использовать

 exit() */

 gtk_main_quit();

 return(FALSE);

}

/* Когда пользователь введет текст и нажмет Enter,

 введенный им текст будет выведен на консоль */

void enter_callback(GtkWidget *widget,

 GtkWidget *entry) {

 domain = gtk_entry_get_text(GTK_ENTRY(entry));

 printf("Domain: %s ", domain);

}

int main(int argc, char *argv[]) {

 GtkWidget *window; /* Окно */

 GtkWidget *button; /* Кнопка */

 GtkWidget *table; /* Таблица для размещения виджитов */

 GtkWidget *label; /* Надпись */

 /* Как видите, все виджиты одного типа — GtkWidget,

  поэтому мы могли бы обойтись даже тремя виджитами — для

  окна, таблицы и для всех остальных элементов GUI*/

 int i;

 /* Инициализация любой GTK-программы */

 gtk_init (&argc, &argv);

 /* Создаем новое окно */

 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

 /* Устанавливаем заголовок окна */

 gtk_window_set_title (GTK_WINDOW(window), "Resolver");

 /* Устанавливаем реакцию на кнопку закрытия окна.

  Сигнал - delete_event. Вызываем функцию delete_event(),

  которая описана выше */

 gtk_signal_connect (GTK_OBJECT (window), "delete_event",

  GTK_SIGNAL_FUNC(delete_event), NULL);

 /* Устанавливаем рамку окна */

 gtk_container_set_border_width(GTK_CONTAINER (window), 20);

 /* Создаем таблицу 3x3 */

 table = gtk_table_new (3, 3, TRUE);

 /* Помещаем таблицу в контейнер. Обязательно! */

 gtk_container_add(GTK_CONTAINER (window), table);

 /* Рисуем надписи, помещаем их в таблицу и отображаем.

  Обратите внимание, что в этом случае нам не нужно объявлять

  отдельную переменную для каждой надписи */

 label = gtk_label_new("Domain: ");

 /* О координатах ячеек поговорим после этого листинга */

 gtk_table_attach_defaults(GTK_TABLE(table),

  label, 0, 1, 0, 1);

 gtk_widget_show(label);

 label = gtk_label_new("DNS #1: ");

 gtk_table_attach_defaults(GTK_TABLE(table),

  label, 0, 1, 1, 2);

 gtk_widget_show(label);

 label = gtk_label_new("DNS #2: ");

 gtk_table_attach_defaults(GTK_TABLE(table),

  label, 0, 1, 2, 3);

 gtk_widget_show (label);

 /* Заполняем наш массив полей ввода. По аналогии с Delphi,

  я назвал массив edit[]*/

 for (i=0; i<3; i++) {

  /* Новое поле */

  edit[i] = gtk_entry_new();

  /* Если забыть этот оператор, пользователь ничего не

   сможет ввести */

  gtk_entry_set_editable(GTK_ENTRY(edit[i]), 1);

  /* Определяем одну для всех реакцию на сигнал activate -

   нажатие Enter*/

  gtk_signal_connect(GTK_OBJECT(edit[i]), "activate",

   GTK_SIGNAL_FUNC(enter_callback), edit[i]);

  /* Помещаем edit[i] в таблицу */

  gtk_table_attach_defaults (GTK_TABLE(table),

   edit[i], 1, 2, i, i+1);

  /* Показываем */

  gtk_widget_show(edit[i]);

 }

 /* Создаем кнопку "OK", помещаем в таблицу,

  определяем реакцию на нажатие и показываем */

 button = gtk_button_new_with_label("OK");

 gtk_table_attach_defaults(GTK_TABLE(table),

  button, 2, 3, 0, 1);

 gtk_signal_connect(GTK_OBJECT(button), "clicked",

  GTK_SIGNAL_FUNC(writetofile), NULL);

 gtk_widget_show(button);

 /* То же самое для кнопки Quit */

 button = gtk_button_new_with_label("Quit");

 gtk_table_attach_defaults(GTK_TABLE(table),

  button, 2, 3, 2, 3);

 gtk_signal_connect(GTK_OBJECT(button),"clicked",

  GTK_SIGNAL_FUNC(delete_event), NULL);

 gtk_widget_show(button);

 gtk_widget_show(table); /* Показываем таблицу */

 gtk_widget_show(window); /* Показываем окно */

 /* Запускаем GTK-программу */

 gtk_main();

 return 0;

}

Я старался писать подробные комментарии, но все же кое-что осталось в тумане. Это координаты ячеек. Рассмотрим нашу таблицу 3?3:

table = gtk_table_new(3, 3, TRUE);

0      1    2  3

 Domain Поле OK

1

 DNS1   Поле

2

 DNS2   Поле Quit

3

Сначала указываются координаты по X, затем — по Y. Вот координаты кнопки OK: 2, 3, 0, 1. Это означает, что кнопка будет расположена в последнем столбце (между 2 и 3), но в первой строке (между 0 и 1).

gtk_table_attach_defaults(GTK_TABLE(table), button,

 2, 3, 0, 1);

Подробнее рассматривать контейнер GtkTable я не вижу смысла: основные операции, я думаю, вам понятны — это создание таблицы с указанием ее размерности и добавление в таблицу виджита функцией gtk_table_attach_defaults(). Еще раз напомню о необходимости отображения виджитов, помещенных в таблицу, и самой таблицы:

gtk_widget_show (table);

Теперь откомпилируем нашу программу:

$ gcc resolv.с -о resolv `gtk-config --cflags` `gtk-config --libs`

Программа gtk-config сообщает компилятору всю необходимую информацию о библиотеке GTK.

Обратите внимание на директиву

#include <gtk/gtk.h>

Обычно файлы заголовков GTK находятся в другом каталоге, например, gtk-1.2, но это не имеет значения — все необходимые параметры укажет программа gtk-config.

В заключение этого пункта перечислим события, характерные для кнопок (таблица 23.3).

События кнопок Таблица 23.3

Событие Описание
clicked Щелчок
pressed Кнопка нажата мышью (и пока не отпущена)
released Кнопка отпущена
enter Указатель мыши в пределах кнопки
leave Указатель мыши вышел за пределы кнопки
Поделитесь на страничке

Следующая глава >

Похожие главы из других книг

2.5.1 Поля

Из книги C++ автора Хилл Мюррей

2.5.1 Поля Использование char для представления двоичной переменой, например, переключателя включено/выключено, может показаться экстравагантным, но char является наименьшим объектом, который в С++ может выделяться независимо. Можно, однако, сгруппировать несколько таких


8.5.14 Поля Бит

Из книги Как функции, не являющиеся методами, улучшают инкапсуляцию автора Мейерс Скотт

8.5.14 Поля Бит Описатель_члена видаидентификатор opt : константное_выражениеопределяет поле; его длина отделяется от имени поля дветочием. Поля упаковываются в машинные целые; они не являются альтернативой слов. Поле , не влезающее в оставшееся в целом место, помещается в


Интерфейсы и упаковка

Из книги Защити свой компьютер на 100% от вирусов и хакеров автора Бойцев Олег Михайлович

Интерфейсы и упаковка Herb Sutterr объяснил, что "интерфейс" класса (подразумевая, функциональные возможности, обеспечиваемые классом) включает также внешние функции, связанные с классом. Им также показано, что правила области видимости имен в C++ поддерживают эти изменения


Упаковка

Из книги Язык программирования С# 2005 и платформа .NET 2.0. [3-е издание] автора Троелсен Эндрю

Упаковка Начнем с упаковки как самого популярного метода сокрытия вирусного кода. К слову будет сказано, именно упаковка является самым простым инструментом, чтобы скрыть вирус, который уже засветился в антивирусных базах.Упаковка заключается в сжатии исполняемого


Открытые поля, приватные поля и открытые свойства

Из книги Photoshop. Мультимедийный курс автора Мединов Олег

Открытые поля, приватные поля и открытые свойства Заметим, что в указанных выше классах поля данных были определены открытыми только для того, чтобы упростить пример. Конечно, с точки зрения объектно-ориентированного подхода предпочтительнее использовать приватные


Целлофановая упаковка

Из книги Обработка баз данных на Visual Basic®.NET автора Мак-Манус Джеффри П

Целлофановая упаковка Действие данного фильтра описать словами непросто, его лучше увидеть. Изображение как будто покрывается полупрозрачной целлофановой пленкой, причем эта «пленка» рельефная, местами как будто вздутая. Область применения данного фильтра зависит


12.3.3. Кнопки

Из книги Удвоение продаж в интернет-магазине автора Парабеллум Андрей Алексеевич


Подарочная упаковка

Из книги Linux: Полное руководство автора Колисниченко Денис Николаевич

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


23.4.8. Иерархия виджитов

Из книги Fiction Book Designer 3.2. Руководство по созданию книг автора

23.4.8. Иерархия виджитов GtkObject+GtkWidget| +GtkMisc| | +GtkLabel| | | +GtkAccelLabel| | | `GtkTipsQuery| | +GtkArrow| | +GtkImage| | `GtkPixmap| +GtkContainer| | +GtkBin| | | +GtkAlignment| | | +GtkFrame| | | | `GtkAspectFrame| | | +GtkButton| | | | +GtkToggleButton| | | | | `GtkCheckButton| | | | | `GtkRadioButton| | | | `GtkOptionMenu| | | +GtkItem| | | | +GtkMenuItem| | | | | +GtkCheckMenuItem| | | | | | `GtkRadioMenuItem| | | | | `GtkTearoffMenuItem| | | | +GtkListItem|


Кнопки

Из книги Цифровой журнал «Компьютерра» № 167 автора Журнал «Компьютерра»

Кнопки done: запомнить новые установки.reload file: перезагрузить текущий файл с новыми установками.cancel: отменить новые установки.default: назначить установки по


Игрушки из картонной коробки: многофункциональная упаковка для развивающихся стран Николай Маслухин

Из книги Firebird РУКОВОДСТВО РАЗРАБОТЧИКА БАЗ ДАННЫХ автора Борри Хелен

Игрушки из картонной коробки: многофункциональная упаковка для развивающихся стран Николай Маслухин Опубликовано 01 апреля 2013 Каждый день организация ЮНИСЕФ (детский фонд ООН) отправляет тысячи картонных коробок в страны Африки и Азии с


Упаковка привилегий

Из книги Цифровой журнал «Компьютерра» № 175 автора Журнал «Компьютерра»

Упаковка привилегий SQL Firebird реализует возможности упаковки множества привилегий для назначения индивидуальным получателям, спискам или специально сгруппированным пользователям. Это пакет ALL, разделенные запятыми списки и роли SQL.Ключевое слово ALLКлючевое слово ALL


Повседневный дизайн: удобная упаковка для фастфуда Николай Маслухин

Из книги Язык Си - руководство для начинающих автора Прата Стивен

Повседневный дизайн: удобная упаковка для фастфуда Николай Маслухин Опубликовано 30 мая 2013 Десятки компаний, производящих фастфуд, используют самую разнообразную упаковку для переноски, но если покупатель вместе с едой берет ещё и напиток, то обе


Поля

Из книги Графология XXI века автора Щеголев Илья Владимирович

Поля Второй способ манипуляции разрядами заключается в использовании поля. Полем считается последовательность соседних разрядов в числе типа int или unsigned int. Поле устанавливается при помощи определения структуры, в котором помечается каждое поле и определяется его


7. Поля

Из книги автора

7. Поля Признаки слева направо и сверху вниз (рис. 187):• все поля широкие; Рис. 187• все поля узкие или отсутствуют;• поля левые широкие;• поля левые очень узкие или отсутствуют совсем;• поля левые сужающиеся;• поля левые расширяющиеся;• поля левые неровные;• поля правые