среда, 17 июля 2013 г.

Gtk+. Создание панели состояния


Поставим перед собой задачу реализовать небольшое приложение, в котором размещены, сверху вниз, три кнопки. Имена кнопок будут Red, Green, Blue. По - нажатию на одну из кнопок, то главное окно программы закрашивается в соответствующий цвет, либо в красный, либо зеленый, либо синий. В самом низу программы мы расположим панель состояния, в которой мы будем показывать статус программы. Другими словами, если программа ожидает действий, то программа имеет статус «Ready», иначе если курсор мыши наведен на одну из кнопок, то в статусе программы пишется название выбранной кнопки (Red, Green, Blue).

Сразу скажу, что для трех кнопок нам придется написать девять CALLBACK — функций, по три на каждую кнопку. Три CALLBACK — функции для события «clicked» (событие, когда мы нажимаем на кнопку), три CALLBACK — функции для события «enter» (событие, когда мы наводим курсор мыши на кнопку), три CALLBACK — функции для события «leave» (событие, когда мы убираем курсор мыши с кнопки).

Запустите среду программирования Geany и создайте новый c — файл с именем main. Сохраните этот файл в заранее подготовленный каталог, например в каталог gtk_p6.

Начнем с подключения заголовочного файла библиотеки GTK+:


#include <gtk/gtk.h>
  
Дальше будут идти девять CALLBACK — функций, о которых кратко было написано выше, но их мы рассмотрим позже. Перейдем к написания кода главной функции программы.
  
int main(int argc, char** argv) {
  
В самом начале главной функции нам необходимо описать указатели на будущие объекты (окно, панель состояния, вертикальный контейнер, три кнопки), массив данных необходимых нашим кнопкам, массив данных панели состояния, строка изначального состояния панели и идентификатор панели состояния.
  
GtkWidget *window = NULL;
GtkWidget *statusbar = NULL;
GtkWidget *vbox = NULL;

GtkWidget *red_button = NULL;
GtkWidget *green_button = NULL;
GtkWidget *blue_button = NULL;

gpointer button_data[1];
gpointer statusbar_data[2];

const gchar *statusbar_str = "Ready";

guint context_id;


Дальше мы создадим окно и проведем инициализацию GTK+:


gtk_init(&argc, &argv);

window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);

gtk_window_set_default_size(GTK_WINDOW(window), 250, 200);

gtk_window_set_title(GTK_WINDOW(window), "GTK_p6");
  
Далее создадим вертикальный контейнер в котором разместим три кнопки:
  
vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
gtk_container_add(GTK_CONTAINER(window), vbox);


Подготовим массив данных для передачи его в CALLBACK — функцию одной из трех кнопок, в зависимости какая нажата. Данные будут содержать указатель на объект окна с именем window.


button_data[0] = (gpointer)window;


Далее создаем три кнопки и свяжем событие («clicked») нажатия на кнопку с функцией — обработчиком для конкретной кнопки. Потом запакуем кнопки в вертикальный контейнер.


red_button = gtk_button_new_with_label("Red");

gtk_box_pack_start(GTK_BOX(vbox), red_button, FALSE, FALSE, 1);

g_signal_connect(red_button, "clicked", G_CALLBACK(red_button_clicked), (gpointer)button_data);

green_button = gtk_button_new_with_label("Green");

gtk_box_pack_start(GTK_BOX(vbox), green_button, FALSE, FALSE, 1);

g_signal_connect(green_button, "clicked", G_CALLBACK(green_button_clicked), (gpointer)button_data);

blue_button = gtk_button_new_with_label("Blue");

gtk_box_pack_start(GTK_BOX(vbox), blue_button, FALSE, FALSE, 1);

g_signal_connect(blue_button, "clicked", G_CALLBACK(blue_button_clicked), (gpointer)button_data);
  
Создадим панель состояния, добавим панель в конец вертикального контейнера, получим идентификатор контекста панели и добавим первоначальную строчку в панель состояния:


statusbar = gtk_statusbar_new();

gtk_box_pack_end(GTK_BOX(vbox), statusbar, FALSE, FALSE, 0);

context_id = gtk_statusbar_get_context_id(GTK_STATUSBAR(statusbar), "status");

gtk_statusbar_push(GTK_STATUSBAR(statusbar), context_id, statusbar_str);


Теперь подготовим данные о панели состояния для передачи их в функции — обработчики кнопок. Первый элемент массива это указатель на объект панели состояния, второй элемент массива это идентификатор контекста панели состояния.

statusbar_data[0] = (gpointer)statusbar;
statusbar_data[1] = GINT_TO_POINTER(context_id);


Далее нам осталось связать событие «enter» с соответствующими CALLBACK функциями — обработчиками для трех кнопок и связать событие «leave» с соответствующими CALLBACK функциями — обработчиками, тоже для трех кнопок.


g_signal_connect(red_button, "enter", G_CALLBACK(red_button_enter), (gpointer)statusbar_data);

g_signal_connect(green_button, "enter", G_CALLBACK(green_button_enter), (gpointer)statusbar_data);

g_signal_connect(blue_button, "enter", G_CALLBACK(blue_button_enter), (gpointer)statusbar_data);

g_signal_connect(red_button, "leave", G_CALLBACK(red_button_leave), (gpointer)statusbar_data);

g_signal_connect(green_button, "leave", G_CALLBACK(green_button_leave), (gpointer)statusbar_data);

g_signal_connect(blue_button, "leave", G_CALLBACK(blue_button_leave), (gpointer)statusbar_data);


Потом мы должны установить сигнал на закрытие главного окна программы, отобразить все виджеты окна, передать управление библиотеки GTK+.


g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);

gtk_widget_show_all(window);

gtk_main();

return 0;
}


Теперь напишем CALLBACK — функции для события «clicked» для кнопок с именем Red, Green, Blue.

 
gboolean red_button_clicked( GtkWidget *widget, gpointer data ) {


gpointer* data_t = (gpointer*)data;

GdkRGBA color = {1.0, .0, .0, 1.0};


GtkWidget *window = (GtkWidget*)data_t[0];

gtk_widget_override_background_color(window, GTK_STATE_FLAG_NORMAL, &color);


return TRUE;
}


gboolean green_button_clicked( GtkWidget *widget, gpointer data ) {


gpointer* data_t = (gpointer*)data;

GdkRGBA color = {.0, 1.0, .0, 1.0};


GtkWidget *window = (GtkWidget*)data_t[0];

gtk_widget_override_background_color(window, GTK_STATE_FLAG_NORMAL, &color);


return TRUE;
}


gboolean blue_button_clicked( GtkWidget *widget, gpointer data ) {


gpointer* data_t = (gpointer*)data;

GdkRGBA color = {.0, .0, 1.0, 1.0};


GtkWidget *window = (GtkWidget*)data_t[0];

gtk_widget_override_background_color(window, GTK_STATE_FLAG_NORMAL, &color);


return TRUE;
}


В данных функциях, в зависимости от нажатой кнопки, установка необходимого цвета, получение переданных данных в CALLBACK — функцию и установка заднего фона главного окна в цвет (Красный, Зеленый, Синий).

Теперь напишем CALLBACK — функции для события «enter» для кнопок с именем Red, Green, Blue.


gboolean red_button_enter( GtkWidget *widget, gpointer data ) {


gpointer* data_t = (gpointer*)data;

GtkWidget *statusbar = (GtkWidget*)data_t[0];

guint context_id = GPOINTER_TO_INT(data_t[1]);

gtk_statusbar_push(GTK_STATUSBAR(statusbar), context_id, "Red");
return TRUE;
}


gboolean green_button_enter( GtkWidget *widget, gpointer data ) {


gpointer* data_t = (gpointer*)data;

GtkWidget *statusbar = (GtkWidget*)data_t[0];

guint context_id = GPOINTER_TO_INT(data_t[1]);

gtk_statusbar_push(GTK_STATUSBAR(statusbar), context_id, "Green");
return TRUE;
}


gboolean blue_button_enter( GtkWidget *widget, gpointer data ) {


gpointer* data_t = (gpointer*)data;

GtkWidget *statusbar = (GtkWidget*)data_t[0];

guint context_id = GPOINTER_TO_INT(data_t[1]);

gtk_statusbar_push(GTK_STATUSBAR(statusbar), context_id, "Blue");
return TRUE;
}


В данных функциях, в зависимости от того на какую кнопку наведен курсор мыши, мы в панели состояния размещаем строку с именем кнопки.

Последнее, мы напишем CALLBACK — функции для события «leave» для кнопок с именем Red, Green, Blue.
  
gboolean red_button_leave( GtkWidget *widget, gpointer data ) {


gpointer* data_t = (gpointer*)data;

GtkWidget *statusbar = (GtkWidget*)data_t[0];

guint context_id = GPOINTER_TO_INT(data_t[1]);

gtk_statusbar_push(GTK_STATUSBAR(statusbar), context_id, "Ready");
return TRUE;
}


gboolean green_button_leave( GtkWidget *widget, gpointer data ) {


gpointer* data_t = (gpointer*)data;

GtkWidget *statusbar = (GtkWidget*)data_t[0];

guint context_id = GPOINTER_TO_INT(data_t[1]);

gtk_statusbar_push(GTK_STATUSBAR(statusbar), context_id, "Ready");
return TRUE;
}


gboolean blue_button_leave( GtkWidget *widget, gpointer data ) {


gpointer* data_t = (gpointer*)data;

GtkWidget *statusbar = (GtkWidget*)data_t[0];

guint context_id = GPOINTER_TO_INT(data_t[1]);

gtk_statusbar_push(GTK_STATUSBAR(statusbar), context_id, "Ready");
return TRUE;
}


В данных функциях, когда мы убираем курсор мыши с кнопки, то, в зависимости от кнопки, надпись панели состояния меняется с названия кнопки на строку «Ready».

 
Рисунок 1. Результат работы программы
  
Код полностью:
#include <gtk/gtk.h>

/*
 * Some button clicked 
 * 
 */

gboolean red_button_clicked( GtkWidget *widget, gpointer data ) {

 gpointer* data_t = (gpointer*)data;
 
 GdkRGBA color = {1.0, .0, .0, 1.0};

 GtkWidget *window = (GtkWidget*)data_t[0];
 
 gtk_widget_override_background_color(window,  
GTK_STATE_FLAG_NORMAL, &color);

 return TRUE;
}

gboolean green_button_clicked( GtkWidget *widget, gpointer data ) {

 gpointer* data_t = (gpointer*)data;
 
 GdkRGBA color = {.0, 1.0, .0, 1.0};

 GtkWidget *window = (GtkWidget*)data_t[0];
 
 gtk_widget_override_background_color(window,  
GTK_STATE_FLAG_NORMAL, &color);

 return TRUE;
}

gboolean blue_button_clicked( GtkWidget *widget, gpointer data ) {

 gpointer* data_t = (gpointer*)data;
 
 GdkRGBA color = {.0, .0, 1.0, 1.0};

 GtkWidget *window = (GtkWidget*)data_t[0];
 
 gtk_widget_override_background_color(window
GTK_STATE_FLAG_NORMAL, &color);

 return TRUE;
}

/*
 * Some button entered
 * 
 */

gboolean red_button_enter( GtkWidget *widget, gpointer data ) {

 gpointer* data_t = (gpointer*)data;
 
 GtkWidget *statusbar = (GtkWidget*)data_t[0];
 
 guint context_id = GPOINTER_TO_INT(data_t[1]); 
 
 gtk_statusbar_push(GTK_STATUSBAR(statusbar), context_id, "Red");
 return TRUE;
}

gboolean green_button_enter( GtkWidget *widget, gpointer data ) {

 gpointer* data_t = (gpointer*)data;
 
 GtkWidget *statusbar = (GtkWidget*)data_t[0];
 
 guint context_id = GPOINTER_TO_INT(data_t[1]); 
 
 gtk_statusbar_push(GTK_STATUSBAR(statusbar), context_id, "Green");
 return TRUE;
}

gboolean blue_button_enter( GtkWidget *widget, gpointer data ) {

 gpointer* data_t = (gpointer*)data;
 
 GtkWidget *statusbar = (GtkWidget*)data_t[0];
 
 guint context_id = GPOINTER_TO_INT(data_t[1]); 
 
 gtk_statusbar_push(GTK_STATUSBAR(statusbar), context_id, "Blue");
 return TRUE;
}

/*
 * Some button leaved 
 * 
 */

gboolean red_button_leave( GtkWidget *widget, gpointer data ) {

 gpointer* data_t = (gpointer*)data;
 
 GtkWidget *statusbar = (GtkWidget*)data_t[0];
 
 guint context_id = GPOINTER_TO_INT(data_t[1]); 
 
 gtk_statusbar_push(GTK_STATUSBAR(statusbar), context_id, "Ready");
 return TRUE;
}

gboolean green_button_leave( GtkWidget *widget, gpointer data ) {

 gpointer* data_t = (gpointer*)data;
 
 GtkWidget *statusbar = (GtkWidget*)data_t[0];
 
 guint context_id = GPOINTER_TO_INT(data_t[1]); 
 
 gtk_statusbar_push(GTK_STATUSBAR(statusbar), context_id, "Ready");
 return TRUE;
}

gboolean blue_button_leave( GtkWidget *widget, gpointer data ) {

 gpointer* data_t = (gpointer*)data;
 
 GtkWidget *statusbar = (GtkWidget*)data_t[0];
 
 guint context_id = GPOINTER_TO_INT(data_t[1]); 
 
 gtk_statusbar_push(GTK_STATUSBAR(statusbar), context_id, "Ready");
 return TRUE;
}

int main(int argc, char** argv) {
 
 GtkWidget *window = NULL;
 GtkWidget *statusbar = NULL;
 GtkWidget *vbox = NULL;
 
 GtkWidget *red_button = NULL;
 GtkWidget *green_button = NULL;
 GtkWidget *blue_button = NULL;
 
 gpointer button_data[1];
 gpointer statusbar_data[2];
 
 const gchar *statusbar_str = "Ready";
 
 guint context_id;
 
 gtk_init(&argc, &argv);
 
 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 
 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
 
 gtk_window_set_default_size(GTK_WINDOW(window), 250, 200);
 
 gtk_window_set_title(GTK_WINDOW(window), "GTK_p6");
 
 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
 
 gtk_container_add(GTK_CONTAINER(window), vbox);
 
 button_data[0] = (gpointer)window;
 
 red_button = gtk_button_new_with_label("Red");
 
 gtk_box_pack_start(GTK_BOX(vbox), red_button, FALSE, FALSE, 1);  
 
 g_signal_connect(red_button, "clicked",  
G_CALLBACK(red_button_clicked), (gpointer)button_data);
 
 green_button = gtk_button_new_with_label("Green");
 
 gtk_box_pack_start(GTK_BOX(vbox), green_button, FALSE, FALSE, 1); 
 
 g_signal_connect(green_button, "clicked"
G_CALLBACK(green_button_clicked), (gpointer)button_data);
 
 blue_button = gtk_button_new_with_label("Blue");
 
 gtk_box_pack_start(GTK_BOX(vbox), blue_button, FALSE, FALSE, 1);
 
 g_signal_connect(blue_button, "clicked",  
G_CALLBACK(blue_button_clicked), (gpointer)button_data);  

 statusbar = gtk_statusbar_new();
 
 gtk_box_pack_end(GTK_BOX(vbox), statusbar, FALSE, FALSE, 0);
 
 context_id = gtk_statusbar_get_context_id(GTK_STATUSBAR(statusbar),
 "status");
 
 gtk_statusbar_push(GTK_STATUSBAR(statusbar), context_id,  
statusbar_str);
 
 statusbar_data[0] = (gpointer)statusbar;
 statusbar_data[1] = GINT_TO_POINTER(context_id);
 
 g_signal_connect(red_button, "enter",  
G_CALLBACK(red_button_enter), (gpointer)statusbar_data);
 
 g_signal_connect(green_button, "enter",  
G_CALLBACK(green_button_enter), (gpointer)statusbar_data);
 
 g_signal_connect(blue_button, "enter",  
G_CALLBACK(blue_button_enter), (gpointer)statusbar_data);
 
 g_signal_connect(red_button, "leave",  
G_CALLBACK(red_button_leave), (gpointer)statusbar_data);
 
 g_signal_connect(green_button, "leave"
G_CALLBACK(green_button_leave), (gpointer)statusbar_data);
 
 g_signal_connect(blue_button, "leave"
G_CALLBACK(blue_button_leave), (gpointer)statusbar_data);
 
 g_signal_connect(window, "destroy",  
G_CALLBACK(gtk_main_quit), NULL);
 
 gtk_widget_show_all(window);
 
 gtk_main();
 
 return 0;

}


syntax highlighted by Code2HTML, v. 0.9.1