пятница, 21 июня 2013 г.

Gtk+. Перемещение элементов управления


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

Разобьем наши дальнейшие действия:
1) Создадим главное окно. Здесь все как обычно, подключаем заголовочный файл gtk:

#include <gtk/gtk.h>

Потом создадим главную функцию программы:

int main(int argc, char **argv) {
return 0;
}

В теле главной функции определим указатель на главное окно:
GtkWidget *window;

Проведем инициализацию gtk:
gtk_init(&argc, &argv);

Создадим окно:
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);

Присвоим заголовок окну:
gtk_window_set_title (GTK_WINDOW (window), "Gtk_p5");

Разместим в центре рабочего стола:
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);

Установим размер окна:
gtk_window_set_default_size(GTK_WINDOW(window), 200, 200);

Установим границу окна:
gtk_container_set_border_width (GTK_CONTAINER (window), 10);

Установим сигнал закрытия окна:
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);

Отобразим все виджеты окна:
gtk_widget_show_all(window);

Передадим управление библиотеки GTK:
gtk_main();

Необходимый минимум для создания главного окна мы рассмотрели. Пойдем дальше и добавим кнопку.
Чтобы добавить кнопку в окно, мы должны создать контейнер и разместить его в главном окне. Для позиционирования элементов управления в определенных координатах существует контейнер GtkFixed.

Объявим указатель на наш будущий контейнер, его нужно разместить в начале главной функции программы, напишем следующую строчку кода:

GtkWidget *fixed;

после строчки

GtkWidget *button;

а указатель на кнопку после объявления указателя на главное окно:

GtkWidget *window;

Далее определим массив указателей который мы передадим в функцию обработки нажатия на виджет кнопки.

gpointer data[3];
Теперь ниже, там где мы подключили Gtk заголовочный файл #include <gtk/gtk.h>, объявим две структуры:

1) Одна структура описывает размер кнопки

struct button_size {
gint width;
gint height;
};

2) Вторая структура описывает позицию кнопки

struct button_position {
gint x;
gint y;
};

После объявления структур, ниже объявим булеву переменную которая будет «переключать» положение кнопки:

gboolean f_switch = FALSE;

В главной функции программы, там где мы объявили массив указателей

gpointer data[3];

ниже мы должный объявить переменную на структуру с именем button_size и две переменные на структуру с именем button_position и присвоить всем этим структурам значения:

struct button_size bs = { 80, 35 };
struct button_position bp1 = { 55, 10 };
struct button_position bp2 = { 55, 135 };

Ниже, после этих строчек, объявим два указателя на структуру типа button_position:

struct button_position *p_bp1;
struct button_position *p_bp2;

Теперь давайте создадим контейнер, после строчки:

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

напишем следующую строчку:

fixed = gtk_fixed_new();

Функция gtk_fixed_new создаст для нас контейнер GtkFixed.

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

gtk_container_add(GTK_CONTAINER(window), fixed);

Дальше создадим кнопку с надписью «Move»

button = gtk_button_new_with_label("Move");

Теперь подготовим массив указателей, с именем data, для дальнейшей передачи его в функцию — обработчик нажатия кнопки.

Присвоим указателям на структуру button_position адреса переменных типа button_position:

p_bp1 = &bp1;
p_bp2 = &bp2;

Присвоим каждому элементу массива типа gpointer преобразованные указатели (тип gpointer) на структуру типа button_position (с именами p_bp1 и p_bp2) и преобразованный указатель (тип gpointer) на контейнер GtkFixed (с именем fixed).
data[0] = (gpointer)p_bp1;
data[1] = (gpointer)p_bp2;
data[2] = (gpointer)fixed;

Далее напишем сигнал который свяжет событие («clicked») нажатия на кнопку (с именем button) с функцией — обработчиком (с именем button_clicked).

g_signal_connect(button, "clicked", G_CALLBACK(button_clicked), (gpointer)data);

Далее добавим нашу кнопку (с именем button) в контейнер GtkFixed (с именем fixed) в определенную позицию (55, 10) в пикселях:

gtk_fixed_put(GTK_FIXED(fixed), button, bp1.x, bp1.y);

Установим размер кнопки в (85, 35) пикселях:

gtk_widget_set_size_request(button, bs.width, bs.height);

Теперь рассмотрим функцию — обработчик для нашей кнопки:

gboolean button_clicked( GtkWidget *widget, gpointer data ) {
gpointer* data_t = (gpointer*)data;
struct button_position *p_bp1 = (struct button_position*)data_t[0];
struct button_position *p_bp2 = (struct button_position*)data_t[1];
GtkWidget *fixed = (GtkWidget*)data_t[2];
if (!f_switch) {
g_print("%d\n%d\n", p_bp2->x, p_bp2->y);
gtk_fixed_move(GTK_FIXED(fixed), widget, p_bp2->x, p_bp2->y);
f_switch = TRUE;
}
else {
g_print("%d\n%d\n", p_bp1->x, p_bp1->y);
gtk_fixed_move(GTK_FIXED(fixed), widget, p_bp1->x, p_bp1->y);
f_switch = FALSE;
}
return TRUE;
}

1) В качестве параметров функция передает указатель на виджет (GtkWidget *widget), в данном случае виджет — кнопка (с именем button), который вызвал функцию — обработчик, и указатель на данные (с именем data). Функция возвращает булево значение.

2) Далее мы получаем указатели на структуру типа button_position и указатель на контейнер GtkFixed:

gpointer* data_t = (gpointer*)data;
struct button_position *p_bp1 = (struct button_position*)data_t[0];
struct button_position *p_bp2 = (struct button_position*)data_t[1];
GtkWidget *fixed = (GtkWidget*)data_t[2];

3) Дальше мы проверяем значение переменной f_switch, если она равна FALSE, то мы перемещаем кнопку на новую позицию и меняем значение f_switch на TRUE, иначе если f_switch равна TRUE, то мы перемещаем кнопку в изначальное положение и меняем f_switch на FALSE.

if (!f_switch) {
g_print("%d\n%d\n", p_bp2->x, p_bp2->y);
gtk_fixed_move(GTK_FIXED(fixed), widget, p_bp2->x, p_bp2->y);
f_switch = TRUE;
}
else {
g_print("%d\n%d\n", p_bp1->x, p_bp1->y);
gtk_fixed_move(GTK_FIXED(fixed), widget, p_bp1->x, p_bp1->y);
f_switch = FALSE;
}

Таким образом, нажимая на кнопку, мы перемещаем кнопку на другую позицию.

 
Рисунок 1. Изначальное положение кнопки

Рисунок 2. Измененное положение кнопки

 
Код полностью:

#include <gtk/gtk.h>

struct button_size {
  gint width;
  gint height;
 };

struct button_position {
  gint x;
  gint y;
 };
 
gboolean f_switch = FALSE;

gboolean button_clicked( GtkWidget *widget, gpointer data ) {
  
gpointer* data_t = (gpointer*)data;
struct button_position  
                *p_bp1 = (struct button_position*)data_t[0]; 
struct button_position 
                *p_bp2 = (struct button_position*)data_t[1];
GtkWidget *fixed = (GtkWidget*)data_t[2];
  
if (!f_switch) {
 g_print("%d\n%d\n", p_bp2->x, p_bp2->y); 
 gtk_fixed_move(GTK_FIXED(fixed), widget, p_bp2->x, p_bp2->y);
 f_switch = TRUE;
}
else {
 g_print("%d\n%d\n", p_bp1->x, p_bp1->y);
 gtk_fixed_move(GTK_FIXED(fixed), widget, p_bp1->x, p_bp1->y);
 f_switch = FALSE;
}
  
return TRUE;
}

int main( int argc, char **argv )
{
 GtkWidget *window;
 GtkWidget *button;
 GtkWidget *fixed;
    
 gpointer data[3];
    
 struct button_size bs = { 80, 35 };
 struct button_position bp1 = { 55, 10 };
 struct button_position bp2 = { 55, 135 };
    
 struct button_position *p_bp1;
 struct button_position *p_bp2;
   
 gtk_init (&argc, &argv);
    
 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    
 gtk_window_set_title (GTK_WINDOW (window), "Gtk_p5");
 
 gtk_window_set_position(GTK_WINDOW(window)
                        GTK_WIN_POS_CENTER);
 
 gtk_window_set_default_size(GTK_WINDOW(window), 200, 200);
 
 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
 
 g_signal_connect(window, "destroy"
         G_CALLBACK(gtk_main_quit), NULL);
    
 fixed = gtk_fixed_new();
 
 gtk_container_add(GTK_CONTAINER(window), fixed);
 
 button = gtk_button_new_with_label("Move");
 
 p_bp1 = &bp1;
 p_bp2 = &bp2;
 
 data[0] = (gpointer)p_bp1;
 data[1] = (gpointer)p_bp2;
 data[2] = (gpointer)fixed;
 
 g_signal_connect(button, "clicked",  
            G_CALLBACK(button_clicked), (gpointer)data); 
 
 gtk_fixed_put(GTK_FIXED(fixed), button, bp1.x, bp1.y);
 
 gtk_widget_set_size_request(button, bs.width, bs.height); 
 
 gtk_widget_show_all(window);
 
 gtk_main();   
    
 return(0);
}

Комментариев нет:

Отправить комментарий