Рассылка закрыта
При закрытии подписчики были переданы в рассылку "Обзор инструментов SEO-оптимизатора и методов продвижения" на которую и рекомендуем вам подписаться.
Вы можете найти рассылки сходной тематики в Каталоге рассылок.
← Апрель 2010 → | ||||||
1
|
2
|
3
|
4
|
|||
---|---|---|---|---|---|---|
5
|
6
|
7
|
8
|
9
|
10
|
11
|
12
|
13
|
14
|
15
|
16
|
17
|
18
|
19
|
20
|
21
|
22
|
24
|
25
|
|
26
|
27
|
28
|
29
|
30
|
Статистика
0 за неделю
Практические советы по GTK+ (Создание нового виджета)
Создание нового виджета Внимание! Все выпуски, включая этот, можно найти в одном файле gtk_book.zip
Попробуем создать свой собственный виджет, на примере виджета в виде текстовой ссылки (вроде GtkLinkButton). GtkLinkButton меня не устраивает по ряду причин, например обработчик нажатия общий для всех ссылок и при наведении на ссылку, появляются контуры кнопки. Поэтому пришлось сделать альтернативу. Наш виджет назовём GtkLinkLabel и он будет выглядеть вот так: Все функции нашего виджета GtkLinkLabel: // Создать текстовую метку GtkWidget* gtk_link_label_new (const gchar *str); // сменить тестовую метку void gtk_link_label_set_text(GtkLinkLabel *linklabel,const gchar *str); // сменить размер шрифта void gtk_link_label_set_size(GtkLinkLabel *linklabel,const gchar *str_size);
К виджету можно будет подключить обработчик нового сигнала "click_label", который посылается при нажатии на текстовую метку. Это было полное описание нашего нового виджета. Рассмотрим пример его использования: // создание виджета GtkWidget *label_test = gtk_link_label_new(_("Ссылка1")); // смена размера текста в виджета на более мелкий (не обязательно) gtk_link_label_set_size(GTK_LINK_LABEL(label_test),"smaller"); // подключаем обработчик сигнала нажатия курсором мышки на наш виджет g_signal_connect (G_OBJECT (label_test),"click_label",G_CALLBACK (click_label_test),NULL);
// обработчик сигнала нажатия курсором мышки на наш виджет void click_label_test(GtkLinkButton *button,gpointer user_data) { printf("нажали на текстовую метку\n"); }
Теперь посмотрим исходный код, который состоит из двух файлов gtklinklabel.h и gtklinklabel.с. Виджет содержит совсем немного кода, в основном это стандартный каркас, который присутствует во всех виждетах. Оба файла исходного кода виджета с подробными комментариями представлены ниже:
/* * GtkLinkLabel widget for GTK+ * * Файл gtklinklabel.h * */
#ifndef __GTK_LINK_LABEL_H__ #define __GTK_LINK_LABEL_H__
#include <gdk/gdk.h> #include <gtk/gtkhbox.h>
G_BEGIN_DECLS
// Стандартные макросы для класса #define GTK_TYPE_LINK_LABEL (gtk_link_label_get_type ()) #define GTK_LINK_LABEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_LINK_LABEL, GtkLinkLabel)) #define GTK_LINK_LABEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_LINK_LABEL, GtkLinkLabel)) #define GTK_IS_LINK_LABEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_LINK_LABEL)) #define GTK_IS_LINK_LABEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_LINK_LABEL)) #define GTK_LINK_LABEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_LINK_LABEL, GtkLinkLabel))
typedef struct _GtkLinkLabel GtkLinkLabel; typedef struct _GtkLinkLabelClass GtkLinkLabelClass;
// Для каждого экземпляра виджета создается структура объекта, предназначенаая для хранения индивидуальной информации этого экземпляра. struct _GtkLinkLabel { GtkEventBox linklabel;// родительский виджет
GtkWidget *label; // текстовая метка gint state; // состояние: 1 - курсор находится над текстовой меткой, 0 - нет gchar *size; // размер текста:'smaller' или 'larger' и абсолютные значения: 'xx-small', 'x- small', 'small', 'medium', 'large', 'x-large', 'xx-large' gchar *str; // непосредственно сам текст };
struct _GtkLinkLabelClass { GtkEventBoxClass parent_class;// родительский класс - текстовая метка // функция для обработчика сигнала "click_label" void (* click_label) (GtkLinkLabel *linklabel); };
GType gtk_link_label_get_type (void) G_GNUC_CONST;
// Создать текстовую метку GtkWidget* gtk_link_label_new (const gchar *str); // сменить тест void gtk_link_label_set_text(GtkLinkLabel *linklabel,const gchar *str); // сменить размер шрифта // str_size - 'smaller' или 'larger' и абсолютные значения: 'xx-small', 'x- small', 'small', 'medium', 'large', 'x-large', 'xx-large'. void gtk_link_label_set_size(GtkLinkLabel *linklabel,const gchar *str_size);
G_END_DECLS
#endif /* __GTK_LINK_LABEL_H__ */
/* * GtkLinkLabel widget for GTK+ * * Файл gtklinklabel.c * */ #include <gtk/gtk.h> #include "gtklinklabel.h"
static GtkWidgetClass *parent_class = NULL;
// инициализия структуры класса виджета и регистрация сигналов для этого класса static void gtk_link_label_class_init (GtkLinkLabelClass *class); // инициализация структуру объекта static void gtk_link_label_init (GtkLinkLabel *linklabel); // обработчик сигналов "enter-notify-event"(курсор мышки зашёл в область виджета) и "leave-notify-event"(курсор мышки вышёл из области виджета) static void move_cursor(GtkWidget *widget,GdkEventCrossing *event,gpointer user_data); // обработчик сигнала "button-press-event" - нажали мышкой на виджете static void click_cursor(GtkWidget *widget,GdkEventButton *event,gpointer user_data); // деструктор static void gtk_link_label_unrealize(GtkWidget *object); // обновить текстовую метку static void gtk_link_label_update_text(GtkLinkLabel *linklabel);
// состояние текстовой метки - нормальное или выделенное typedef enum { GTK_LINK_LABEL_NORMAL = 0, GTK_LINK_LABEL_ACTIVE = 1 } GtkLinkLabelState;
// список сигналов виджета (только один сигнал) enum { CLICK_LABEL_SIGNAL, LAST_SIGNAL }; static guint link_label_signals[LAST_SIGNAL] = { 0 };
/* Главной функцией для каждого объекта является функция xxx_get_type (). При первом вызове она информирует библитеку о новом классе и получает уникальный идентификатор созданного класса. При всех последующих вызовах она возвращает только идентификатор ID. */ GType gtk_link_label_get_type (void) { static GType date_type = 0;
if (!date_type) { static const GTypeInfo date_info = { sizeof (GtkLinkLabelClass), /* размер структуры класса */ NULL, /* конструктор базового класса */ NULL, /* деструктор базового класаа */ (GClassInitFunc) gtk_link_label_class_init, NULL, /* деструктор класса */ NULL, /* данные конструкторов и деструктров класса */ sizeof (GtkLinkLabel),/* размер объекта класса */ 0, /* количество кешируемых в памяти объектов */ (GInstanceInitFunc) gtk_link_label_init,/* конструктор объекта */ };
date_type = g_type_register_static (GTK_TYPE_EVENT_BOX, "GtkLinkLabel", &date_info, 0); }
return date_type; }
// Функция xxx_class_init () инициализирует поля структуры класса виджета и регистирует сигналы для этого класса static void gtk_link_label_class_init (GtkLinkLabelClass *class) { GtkWidgetClass *widget_class;
widget_class = (GtkWidgetClass*) class; parent_class = g_type_class_peek_parent (class);
class->click_label = NULL; // задать деструктор класса (нужен только, чтобы удалить строку str) widget_class->unrealize = gtk_link_label_unrealize;
// Наш виджет имеет только один сигнал - "click_label", // который посылается при нажатии на текстовую метку. Создание нового сигнала выполняется с помощью функции g_signal_new link_label_signals[CLICK_LABEL_SIGNAL] = // Функция g_signal_new() возвращает уникальный целочисленный идентификатор сигнала //который в нашем примере сохраняется в массиве link_label_signals g_signal_new("click_label",// название сигнала // идентификатор типа объекта, распространяющего сигнал G_OBJECT_CLASS_TYPE((GObjectClass*)class), // флаг запуска обработчика сигнала, устанавливает // порядок вызова заданного по умолчанию обработчика сигнала G_SIGNAL_RUN_FIRST,// обработчик сигнала по умолчанию выполняется до пользовательских обработчиков сигнала // смещение в пределах структуры класса указателя на заданный по умолчанию обработчик G_STRUCT_OFFSET (GtkLinkLabelClass, click_label), // accumulator — для большинства классов может быть установлен в NULL NULL, // accu_data - пользовательские данные, которые будут обрабатываться функцией accumulator NULL, // c_marshaller (сигнальщик) - функция вызова обработчика сигнала по // указателю с передачей ей аргументов.. Для обработчиков сигнала, аргументы которого // представлены только объектом, породившем сигнал, и пользовательскими данными, // МОЖНО использовать g_cclosure_marshal_VOID __ VOID; g_cclosure_marshal_VOID__VOID, // return_type - тип возвращаемого значения G_TYPE_NONE, // типы параметров 0); }
/* Инициализация структуру объекта - выполняется при создании каждого экземпляра виджета GtkLinkLabel. Обычно эта функция выполняет присваивание полям структуры объекта значений по умолчанию. В нашем случае эта функция также создает компоненты виджета */ static void gtk_link_label_init (GtkLinkLabel *linklabel) { // Параметры по умолчанию linklabel->str = NULL;// строка с текстовым полем, которое отображается в нашем виджете linklabel->size = NULL;// размер текста linklabel->state = GTK_LINK_LABEL_NORMAL;// текстовая метка не выделена // создаём единственный виджет внутри нашего нового виджета и упаковываем его в родительский виджет EventBox linklabel->label = gtk_label_new(NULL); gtk_container_add (GTK_CONTAINER (linklabel), linklabel->label); gtk_widget_show(linklabel->label); // разрешаем принимать нашему виджету требуемые сигналы gtk_widget_set_events (GTK_WIDGET(linklabel),GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK); // подключение обработчиков сигналов g_signal_connect (G_OBJECT (linklabel),"button-press-event",G_CALLBACK (click_cursor),NULL);// нажали мышкой на виджете g_signal_connect (G_OBJECT (linklabel),"enter-notify-event",G_CALLBACK (move_cursor),NULL);// курсор мышки зашёл в область виджета g_signal_connect (G_OBJECT (linklabel),"leave-notify-event",G_CALLBACK (move_cursor),NULL);// курсор мышки вышёл из области виджета }
// деструктор static void gtk_link_label_unrealize(GtkWidget *object) { GtkLinkLabel *linklabel; g_return_if_fail(object!=NULL); g_return_if_fail(GTK_IS_LINK_LABEL(object)); linklabel = GTK_LINK_LABEL(object); // очистка выденной памяти при создании виджета if(linklabel->str) g_free(linklabel->str); if(linklabel->size) g_free(linklabel->size); // запуск деструктора родительского класса для очистки остатков виджета if(GTK_OBJECT_CLASS(parent_class)->destroy) (* GTK_OBJECT_CLASS(parent_class)->destroy)(GTK_OBJECT(object)); }
// обновить текстовую метку static void gtk_link_label_update_text(GtkLinkLabel *linklabel) { char *str; if(!linklabel->str) return; // underline - подчёркивание (single-одной чертой) // foreground - цвет текста (в зависимости от linklabel->state) // size - размер шрифта текста str = g_strdup_printf("<span underline=\"single\" foreground=\"%s\" size=\"%s\">%s</span>", (linklabel->state==GTK_LINK_LABEL_ACTIVE)?"#b737ff":"#4737ff",// цвет метки в зависимости от нахождения над ней курсора (linklabel->size)?linklabel->size:"medium",// если размер шрифта не задан, то средний linklabel->str); gtk_label_set_markup(GTK_LABEL(linklabel->label),str); g_free(str); }
// обработчик сигналов "enter-notify-event"(курсор мышки зашёл в область виджета) и "leave-notify-event"(курсор мышки вышёл из области виджета) static void move_cursor(GtkWidget *widget,GdkEventCrossing *event,gpointer user_data) { // зашли в поле виджета if(event->type==GDK_ENTER_NOTIFY) { static GdkCursor *hand_cursor = NULL; // создать курсор и применить - только один раз if(!hand_cursor) { hand_cursor = gdk_cursor_new (GDK_HAND2); gdk_window_set_cursor(widget->window,hand_cursor); }
GTK_LINK_LABEL(widget)->state = GTK_LINK_LABEL_ACTIVE; } // вышли из поля виджета if(event->type==GDK_LEAVE_NOTIFY) GTK_LINK_LABEL(widget)->state = GTK_LINK_LABEL_NORMAL; // обновить текстовую метку gtk_link_label_update_text(GTK_LINK_LABEL(widget)); }
// обработчик сигнала "button-press-event" - нажали мышкой на виджете static void click_cursor(GtkWidget *widget,GdkEventButton *event,gpointer user_data) { // послать сигнал CLICK_LABEL_SIGNAL if(event->type==GDK_BUTTON_PRESS) g_signal_emit (GTK_LINK_LABEL(widget), link_label_signals[CLICK_LABEL_SIGNAL], 0); }
// создать новый виджет // str - новая текстовая строка GtkWidget* gtk_link_label_new(const gchar *str) { // создать экземпляр нашего виджета GtkWidget *w = GTK_WIDGET (g_object_new (GTK_TYPE_LINK_LABEL, NULL)); // запоминаем текстовую метку в структуре виджета if(str) GTK_LINK_LABEL(w)->str = g_strdup(str); // обновить текстовую метку gtk_link_label_update_text(GTK_LINK_LABEL(w));// обновить текстовую метку return w; }
// сменить размер шрифта // 'smaller' или 'larger' и абсолютные значения: 'xx-small', 'x- small', 'small', 'medium', 'large', 'x-large', 'xx-large'. void gtk_link_label_set_size(GtkLinkLabel *linklabel,const gchar *str_size) { // удаляем старый размер шрифта if(linklabel->size) free(linklabel->size); // запоминаем новый размер шрифта в структуре виджета linklabel->size = g_strdup(str_size); gtk_link_label_update_text(linklabel); }
// сменить тестовую метку void gtk_link_label_set_text(GtkLinkLabel *linklabel,const gchar *str) { // удаляем старую текстовую метку if(linklabel->str) g_free(linklabel->str); // запоминаем новую текстовую метку в структуре виджета linklabel->str = g_strdup(str); gtk_link_label_update_text(linklabel); }
|
В избранное | ||