GTK+ Reference Manual |
---|
Краткий обзор виджета Дерево и СписокTree and List Widget Overview Краткий обзор GtkTreeModel, GtkTreeView и других связанных с ними виджетов |
Для создания дерева или списка в GTK+, используйте GtkTreeModel интерфейс в связке с GtkTreeView виджетом. Этот виджет создан вокруг Model/View/Controller конструкции и содержит четыре составных части:
Виджет просмотра дерева (GtkTreeView) |
Просмотр столбцов (GtkTreeViewColumn) |
Ячейки представления (GtkCellRenderer etc.) |
Модель интерфейса (GtkTreeModel) |
Вид (View) - это скомпонованные первые три объекта, а последний это модель (Model). Одно из преимуществ конструкции MVC в том, что из одной модели можно создать множество видов. Например, для файлового менеджера можно создать модель отображения файловой системы. Для отображения частей файловой системы можно создать множество видов, но только одна копия будет храниться в памяти.
Предназначение ячейки представления (cell renderers) в обеспечении расширяемости виджета, а также для представления одного типа данных множеством способов. Например, рассмотрим как представить логическую переменную. Должна ли она представляться как строка "True" или "False", "On" или "Off", или же она должна быть представлена как флажок (checkbox)?
GTK+ обеспечивает две простые модели которые могут быть использованы: GtkListStore и GtkTreeStore. GtkListStore используется для модели виджетов списка, а GtkTreeStore модели деревьев. Возможна разработка новых типов моделей, но существующие модели должны удовлетворять большинство ситуаций, кроме самых специфических. Создание модели достаточно просто:
GtkListStore *store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);Это создаст список с двумя столбцами: строковый столбец и логический столбец. Обычно 2 никогда не помещаются непосредственно как такойвые; создаётся перечисление, причём перечисляются разные столбцы сопровождаемые символом представляющим полное количество столбцов. Это проиллюстрировано в следующем примере, только вместо списка использовано дерево. Создание дерева (tree store) почти то же самое.
enum { TITLE_COLUMN, AUTHOR_COLUMN, CHECKED_COLUMN, N_COLUMNS }; GtkTreeStore *store = gtk_tree_store_new (N_COLUMNS, /* Общее число столбцов */ G_TYPE_STRING, /* Заголовок книги */ G_TYPE_STRING, /* Автор */ G_TYPE_BOOLEAN); /* Просмотрен? */
Добавление данных к модели выполняется с помощью
gtk_tree_store_set()
илиgtk_list_store_set()
, зависит от вида созданной модели. Для этого нужен GtkTreeIter. Итератор указывает точку куда добавлены данные.Как только итератор приобретён,
gtk_tree_store_set()
используется для применения данных к части модели в точке на которую указывает итератор. Рассмотрим следующий пример:GtkTreeIter iter; gtk_tree_store_append (store, &iter, NULL); /* Приобретаем итератор */ gtk_tree_store_set (store, &iter, TITLE_COLUMN, "The Principle of Reason", AUTHOR_COLUMN, "Martin Heidegger", CHECKED_COLUMN, FALSE, -1);
Обратите внимание, последний параметр -1. Он устанавливается всегда, потому что это функция с переменным числом аргументов (variable-argument) и он нужен для определения конца аргументов. Она может использоваться для установки данных в любых или во всех столбцах в данную строку.
Третий аргумент
gtk_tree_store_append()
это родительский итератор. Он используется для добавления строк в GtkTreeStore как дочерних для существующих строк. Это значит что новая строка будет видима только когда видима её родительская строка находящаяся в расширенном состоянии. Рассмотрим нижеследующий пример:GtkTreeIter iter1; /* Родительский итератор */ GtkTreeIter iter2; /* Дочерний итератор */ gtk_tree_store_append (store, &iter1, NULL); /* Создаём итератор верхнего уровня */ gtk_tree_store_set (store, &iter1, TITLE_COLUMN, "The Art of Computer Programming", AUTHOR_COLUMN, "Donald E. Knuth", CHECKED_COLUMN, FALSE, -1); gtk_tree_store_append (store, &iter2, &iter1); /* Создаём дочерний итератор */ gtk_tree_store_set (store, &iter2, TITLE_COLUMN, "Volume 1: Fundamental Algorithms", -1); gtk_tree_store_append (store, &iter2, &iter1); gtk_tree_store_set (store, &iter2, TITLE_COLUMN, "Volume 2: Seminumerical Algorithms", -1); gtk_tree_store_append (store, &iter2, &iter1); gtk_tree_store_set (store, &iter2, TITLE_COLUMN, "Volume 3: Sorting and Searching", -1);
Создаём компоненты вида
В то время как существует разные модели выбора, есть только один виджет вида связанный с ними. Он работает или со списком или с деревом. Установка GtkTreeView достаточно проста. Он нуждается в GtkTreeModel чтобы знать откуда брать данные.
GtkWidget *tree; tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
Столбцы и ячейки представления
Как только виджет GtkTreeView получил модель, он должен знать как отобразить её. Это выполняется с помощью столбцов и ячеек представления.
Ячейки представления используются для отображения данных на направлениях модели дерева. Есть множество ячеек представления поставляемых с GTK+ 2.x, включая GtkCellRendererText, GtkCellRendererPixbuf и GtkCellRendererToggle. Они относительно просты для написания обычного представления.
GtkTreeViewColumn это объект который используется GtkTreeView для организации вертикальных столбцов в дереве просмотра. Он нужен чтобы знать имя столбца маркируемое для пользователя, кокой тип ячейки представления используется и какую часть данных искать в модели для данной строки.
GtkCellRenderer *renderer; GtkTreeViewColumn *column; renderer = gtk_cell_renderer_text_new (); column = gtk_tree_view_column_new_with_attributes ("Author", renderer, "text", AUTHOR_COLUMN, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
В этом пункте были рассмотрены все шаги создания отображаемого дерева. Создание модели, сохранение в ней данных, создание дерева просмотра и добавление к нему столбцов.
Обработка выбора
Большинству приложений нужно не просто иметь дело с отображаемыми данными, но также получать события ввода от пользователя. Чтобы это сделать, достаточно получить ссылку на выделенный объект и подключить сигнал "changed".
/* Прототип callback-функции обработки выбора */ static void tree_selection_changed_cb (GtkTreeSelection *selection, gpointer data); /* Установка обработчика выбора */ GtkTreeSelection *select; select = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree)); gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE); g_signal_connect (G_OBJECT (select), "changed", G_CALLBACK (tree_selection_changed_cb), NULL);
Затем находим данные для выбранной строки:
static void tree_selection_changed_cb (GtkTreeSelection *selection, gpointer data) { GtkTreeIter iter; GtkTreeModel *model; gchar *author; if (gtk_tree_selection_get_selected (selection, &model, &iter)) { gtk_tree_model_get (model, &iter, AUTHOR_COLUMN, &author, -1); g_print ("You selected a book by <link linkend="s"><literal>s</literal></link>\n", author); g_free (author); } }
Простой пример
Вот простой пример использования виджета GtkTreeView в контексте другого виджета. Просто совмещаем создание простой модели и вида. Помните что модель не заполняется данными это остаётся как упражнение для читателя. Дополнительная информации об этом может быть найдена в разделе GtkTreeModel.
enum { TITLE_COLUMN, AUTHOR_COLUMN, CHECKED_COLUMN, N_COLUMNS }; void setup_tree (void) { GtkTreeStore *store; GtkWidget *tree; GtkTreeViewColumn *column; GtkCellRenderer *renderer; /* Создаём модель. Мы используем новую модель хранения, хотя мы * можем использовать любую другую модель GtkTreeModel */ store = gtk_tree_store_new (N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN); /* настраиваемая функция для заполнения модели данными */ populate_tree_model (store); /* Создаём вид */ tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store)); /* Создаём ссылку для вида. Мы можем освобождать собственные * ссылки */ g_object_unref (G_OBJECT (store)); /* Создаём ячейку для представления и произвольно делаем её красной для демонстрации */ renderer = gtk_cell_renderer_text_new (); g_object_set (G_OBJECT (renderer), "foreground", "red", NULL); /* Создаём столбец, связанный с параметром "text" * cell_renderer для первого столбца в модели */ column = gtk_tree_view_column_new_with_attributes ("Author", renderer, "text", AUTHOR_COLUMN, NULL); /* Добавляем столбец к виду. */ gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column); /* Второй столбец.. заголовок книги. */ renderer = gtk_cell_renderer_text_new (); column = gtk_tree_view_column_new_with_attributes ("Title", renderer, "text", TITLE_COLUMN, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column); /* Последний столбец.. была ли книга просмотрена. */ renderer = gtk_cell_renderer_toggle_new (); column = gtk_tree_view_column_new_with_attributes ("Checked out", renderer, "active", CHECKED_COLUMN, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column); /* Теперь мы можем манипулировать видом просто как обычным виджетом GTK */ ... }