Нейл Мэтью - Основы программирования в Linux
return 0;
}
На рис. 16.10 показана программа buttons.c в действии с виджетами GtkButton четырех часто применяемых типов.
Рис. 16.10
Щелкните мышью кнопку OK, чтобы увидеть состояние разных кнопок.
Данная программа — простой пример использования кнопок GtkButton четырех типов — показывает, как можно считать состояние кнопки типа GtkToggleButton, GtkCheckButton и GtkRadioButton с помощью единственной функции gtk_toggle_button_get_active. Это одно из огромных преимуществ объектно-ориентированного подхода — поскольку вам не нужны отдельные функции get_active для каждого типа кнопки, вы можете сократить требующийся программный код.
GtkTreeView
К этому моменту мы рассмотрели несколько простых виджетов GTK+, но не все виджеты представляют собой однострочные инструменты для ввода или отображения. Сложность виджетов ничем не ограничивается, и GtkTreeView — яркий пример виджета, инкапсулирующего огромный объем функциональных возможностей.
GtkWidget
+---- GtkContainer
+---- GtkTreeView
GtkTreeView — член семейства виджетов, новых для комплекта GTK+ 2, создающий представление данных в виде дерева или списка наподобие тех, которые вы можете встретить в электронной таблице или файловом менеджере. С помощью виджета GtkTreeView можно создать сложные представления данных, смешивая текст, растровую графику и даже данные, вводимые с помощью виджетов GtkEntry, и т.д.
Самый быстрый способ испытания GtkTreeView — запуск приложения gtk-demo, которое поставляется вместе с GTK+. Демонстрационное приложение показывает возможности всех виджетов GTK+, включая GtkTreeView (рис. 16.11).
Рис. 16.11
Семейство GtkTreeView составляется из четырех компонентов:
□ GtkTreeView — отображение дерева или списка;
□ GtkTreeViewColumn — представление столбца списка или дерева;
□ GtkCellRenderer — управление отображаемыми ячейками;
□ GtkTreeModel — представление данных дерева и списка.
Первые три компонента формируют так называемое Представление, а последний — Модель. Концепция разделения Представления и Модели (часто называемая проектным шаблоном Модель/Представление/Действие (Model/View/Controller) или сокращенно MVC) не свойственна GTK+, но проектированию уделяется все больше и больше внимания на всех этапах программирования.
Ключевое достоинство проектного шаблона MVC заключается в возможности одновременной визуализации данных в виде разных представлений без ненужного их дублирования. Например, текстовые редакторы могут иметь две разные панели и редактировать разные фрагменты документа без хранения в памяти двух копий документа.
Шаблон MVC также очень популярен в Web-программировании, поскольку облегчает создание Web-сайтов, которые визуализируются в мобильных или WAP-обозревателях не так, как в настольных, просто за счет наличия отдельных компонентов Представление, оптимизированных для Web-обозревателя каждого типа. Вы также можете отделить логику сбора данных, например, запросов к базе данных, от логики пользовательского интерфейса.
Мы начнем с рассмотрения компонента Модель, представленного в GTK+ двумя типами. Объект типа GtkTreeStore содержит многоуровневые данные, например иерархию каталогов, а объект GtkListStore предназначен для простых данных.
Для создания объекта GtkTreeStore в функцию передается количество столбцов, за которым следуют типы всех столбцов:
GtkWidget *store = gtk_tree_store_new(3, G_TYPE_STRING, G_TYPE_INT,
G_TYPE_BOOLEAN);
Чтение, вставка, редактирование и удаление данных из модели выполняется с помощью структур GtkTreeIter. Эти структуры итераторов указывают на узлы дерева (или строки списка) и помогают находить фрагменты структур данных потенциально очень большого объема, а также манипулировать ими. Есть несколько вызовов API для получения объекта-итератора для разных точек дерева, но мы рассмотрим простейшую функцию gtk_tree_store_append.
Перед тем как вставлять какие-либо данные в модель дерева, вам нужно получить итератор, указывающий на новую строку. Функция gtk_tree_store_append заполняет объект GtkTreeIter, который представляет новую строку в дереве, как строку верхнего уровня (если вы передаете значение NULL в третьем аргументе), так и подчиненную или дочернюю строку (если вы передаете итератор главной или родительской строки):
GtkTreeIter iter;
gtk_tree_store_append(store, &iter, NULL);
Получив итератор, вы можете заполнять строку с помощью функции gtk_tree_store_set:
gtk_tree_store_set(store, &iter,
0, "Def Leppard",
1, 1987,
2, TRUE, -1);
Номер столбца и данные передаются парами, которые завершаются -1. Позже вы примените тип enum для того, чтобы сделать номера столбцов более информативными.
Для того чтобы добавить ветвь к данной строке (дочернюю строку), вам нужен только итератор для дочерней строки, который вы получаете, вызвав снова функцию gtk_tree_store_append и указав на этот раз в качестве параметра строку верхнего уровня:
GtkTreeIter child;
gtk_tree_store_append(store, &child, &iter);
Дополнительную информацию об объектах GtkTreeStore и функциях объекта GtkListStore см. в документации API, а мы пойдем дальше и рассмотрим компонент Представление типа GtkTreeView.
Создание объекта GtkTreeView — сама простота: только передайте в конструктор в качестве параметра модель типа GtkTreeStore или GtkListStore:
GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
Сейчас самое время настроить виджет для отображения данных именно так, как вы хотите. Для каждого столбца следует определить GtkCellRenderer и источник данных. Можно выбрать, например, визуализацию только определенных столбцов данных или изменить порядок вывода столбцов.
GtkCellRenderer — это объект, отвечающий за прорисовку каждой ячейки на экране, и существует три подкласса, имеющие дело с текстовыми ячейками, ячейками пиксельной графики и ячейками кнопок-выключателей:
□ GtkCellRendererText;
□ GtkCellRendererPixBuf;
□ GtkCellRendererToggle.
В вашем Представлении будет применено текстовое представление ячеек, GtkCellRendererText.
GtkCellRenderer* renderer = gtk_cell_renderer_text_new();
gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
"This is the column title", renderer, "text", 0, NULL);
Вы создаете представление ячейки и передаете его в функцию вставки столбца. Эта функция позволяет сразу задать свойства GtkCellRendererText, передавая заканчивающиеся значением NULL пары "ключ/значение". В качестве параметров указаны представление дерева, номер столбца, заголовок столбца, представление ячейки и его свойства. В приведенном примере вы задаете атрибут "text", передав номер столбца источника данных. Для объекта GtkCellRendererText определено несколько других атрибутов, включая подчеркивание, шрифт, размер и т.д.
В упражнении 16.7, выполнив необходимые шаги, вы увидите, как это работает на практике.
Упражнение 16.7. Использование виджета GtkTreeViewВведите следующий программный код и назовите файл tree.с.
1. Примените тип enum для обозначения столбцов, чтобы можно было ссылаться на них по именам. Общее количество столбцов удобно обозначить как N_COLUMNS:
#include <gtk/gtk.h>
enum {
COLUMN_TITLE, COLUMN_ARTIST, COLUMN_CATALOGUE, N_COLUMNS
};
void closeApp(GtkWidget *window, gpointer data) {
gtk_main_quit();
}
int main(int argc, char *argv[]) {
GtkWidget *window;
GtkTreeStore *store;
GtkWidget *view;
GtkTreeIter parent_iter, child_iter;
GtkCellRenderer *renderer;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size(GTK_WINDOW(window), 300, 200);
g_signal_connect(GTK_OBJECT(window), "destroy",
GTK_SIGNAL_FUNC(сloseApp), NULL);
2. Далее вы создаете модель дерева, передавая количество столбцов и тип каждого из них:
store = gtk_tree_store_new(N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING,
G_TYPE_STRING);
3. Следующий этап — вставка родительской и дочерней строк в дерево:
gtk_tree_store_append(store, &parent_iter, NULL);
gtk_tree_store_set(store, &parent_iter,
COLUMN_TITLE, "Dark Side of the Moon",
COLUMN_ARTIST, "Pink Floyd",
COLUMN_CATALOGUE, "B000024D4P", -1);
gtk_tree_store_append(store, &child_iter, &parent_iter);
gtk_tree_store_set (store, &child_iter,
COLUMN_TITLE, "Speak to Me", -1);
view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
4. Наконец, добавьте столбцы в представление, задавая источники данных для них и заголовки: