понедельник, 17 июня 2013 г.

Gtk+. События элементов управления


Продолжаем разбираться в Gtk+. Возьмем за основу наш проект, в котором мы создали главное окно и добавили элементы управления. Имя нового проекта будет Gtk_p4. Таким же образом, как было в предыдущих постах, создадим файл main.c.

Напишем в файле main.c главную функцию программы, создадим главное окно, добавим элементы управления (поле редактирование, кнопку, метку текста), разместим все эти виджеты в контейнере сетке. Ну вот, подошли к самому интересному.

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

1) Если вводимый текст пустая строка, по нажатию на кнопку покажем сообщение, что строка пуста.
2) Если длинна строки текста превышает 10-ти символом, по нажатию на кнопку покажем сообщение, что строка не должна превышать 10-ти символов.

Ну вот, пробуем написать код. Так как мы будем показывать сообщение, то в нашем проекте нам понадобится функция создания модального диалога. Данную функцию мы позаимствуем из проекта, где мы показывали сообщение по нажатию на кнопку мыши. Ниже показан код функции:

void my_modal_dialog(GtkWindow* parent, gchar* str)
{
  GtkWidget* modal_dialog = gtk_message_dialog_new(parent,
   GTK_DIALOG_DESTROY_WITH_PARENT,
   GTK_MESSAGE_INFO,
   GTK_BUTTONS_CLOSE,
   str);
  gtk_dialog_run(GTK_DIALOG(modal_dialog));
  gtk_widget_destroy(modal_dialog);
}

Так как мы должны при каждом нажатие на кнопку определять длину текста введенного в поле редактирования, то напишем для этого специальную функцию:

gint get_string_length(const gchar *str) {
  return strlen(str);
}

В самом начале кода проекта после строчки

#include <gtk/gtk.h>
подключите заголовочный файл с функциями для работы со строками

#include <string.h>

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

gpointer data[3];

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

gtk_grid_attach(GTK_GRID(grid), button, 1, 0, 1, 1);

разместите код добавления указателей в массив:

data[0] = (gpointer)label;
data[1] = (gpointer)entry;
data[2] = (gpointer)window;

Дальше разместим функцию, которая соединит кнопку с именем button и функцию с именем button_clicked, в которую мы и предадим массив указателей.

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

Ниже показан код функции с именем button_clicked:

gboolean button_clicked(GtkWidget* widget, gpointer data) {
  
  gpointer* data_t = (gpointer*)data;
  
  GtkWidget *label = (GtkWidget*)data_t[0];
  GtkWidget *entry = (GtkWidget*)data_t[1];
  GtkWidget *window = (GtkWidget*)data_t[2];

  const gchar *str = gtk_entry_get_text(GTK_ENTRY(entry));
  if (get_string_length(str) == 0) {
     my_modal_dialog(GTK_WINDOW(window), "The text is empty. Try  again.");
     gtk_widget_grab_focus(entry);
     return FALSE;
  }

  if (get_string_length(str) > 10) {
     my_modal_dialog(GTK_WINDOW(window), "The text of 10 characters. Try again.");
     gtk_entry_set_text(GTK_ENTRY(entry), "");
     gtk_widget_grab_focus(entry);
     return FALSE;
  }
  gtk_label_set_text(GTK_LABEL(label), str);
  return TRUE;
}

Рассмотрим данную функцию подробней:
1) Функция button_clicked возвращает булево значение, в качестве параметра передает указатель на виджет который вызвал данную функцию, в данном случае виджет с именем button. Второй параметр это массив указателей на виджеты.
2) Показанными ниже строчками мы получаем указатели на виджеты главного окна, метку текста и поля редактирования.

gpointer* data_t = (gpointer*)data;
GtkWidget *label = (GtkWidget*)data_t[0];
GtkWidget *entry = (GtkWidget*)data_t[1];
GtkWidget *window = (GtkWidget*)data_t[2];

3) Следующей строчкой мы получаем строку текста из поля редактирования:

const gchar *str = gtk_entry_get_text(GTK_ENTRY(entry));

4) Далее мы проверяем полученную строку пуста ли она, если пуста, то выводим сообщение, устанавливаем фокус ввода в поле редактирования и возвращаем FALSE из функции button_clicked:

if (get_string_length(str) == 0) {
   my_modal_dialog(GTK_WINDOW(window), "The text is empty. Try again.");
   gtk_widget_grab_focus(entry);
   return FALSE;
}

5) Дальше проверим превышает ли введенная строка 10-ти символов, если превышает, то выводим сообщение, очищаем поле редактирования, устанавливаем фокус на поле редактирования и возвращаем FALSE из функции button_clicked:

if (get_string_length(str) > 10) {
   my_modal_dialog(GTK_WINDOW(window), "The text of 10 characters. Try again.");
   gtk_entry_set_text(GTK_ENTRY(entry), "");
   gtk_widget_grab_focus(entry);
   return FALSE;
}

6) Если все проверки пройдены успешно, то устанавливаем текст метке.

gtk_label_set_text(GTK_LABEL(label), str);

7) По окончанию работы функция button_clicked возвращает булево значение TRUE.

Ниже размещены изображения работы программы:

 
Рисунок 1. Сообщение, если поле редактирования пустое

Рисунок 2. Сообщение, если введено больше десяти символов

Рисунок 3. Правильно введенный текст
  
Ниже показан код всей программы:

#include <gtk/gtk.h>
#include <string.h>

void my_modal_dialog(GtkWindow* parent, gchar* str)
{
 GtkWidget* modal_dialog = gtk_message_dialog_new(parent, 
 GTK_DIALOG_DESTROY_WITH_PARENT,
 GTK_MESSAGE_INFO,
 GTK_BUTTONS_CLOSE,
 str);
   
 gtk_dialog_run(GTK_DIALOG(modal_dialog));
 gtk_widget_destroy(modal_dialog);
}

gint get_string_length(const gchar *str) {
 return strlen(str);
}

gboolean button_clicked(GtkWidget* widget, gpointer data) {
 
 gpointer* data_t = (gpointer*)data;
 
 GtkWidget *label = (GtkWidget*)data_t[0];
 GtkWidget *entry = (GtkWidget*)data_t[1];
 GtkWidget *window = (GtkWidget*)data_t[2];
 
 const gchar *str = gtk_entry_get_text(GTK_ENTRY(entry));
 
 if (get_string_length(str) == 0) {
  my_modal_dialog(GTK_WINDOW(window)
"The text is empty. Try again.");
  gtk_widget_grab_focus(entry);
  return FALSE; 
 }
  
 if (get_string_length(str) > 10) {
  my_modal_dialog(GTK_WINDOW(window)
"The text of 10 characters. Try again.");
  gtk_entry_set_text(GTK_ENTRY(entry), "");
  gtk_widget_grab_focus(entry);
  return FALSE;
 }
 
 gtk_label_set_text(GTK_LABEL(label), str);
 
 return TRUE;
}

int main(int argc, char **argv) {

 GtkWidget *window = NULL; 
 GtkWidget *grid = NULL;
 GtkWidget *entry = NULL;
 GtkWidget *button = NULL;
 GtkWidget *label = NULL;

 gpointer data[3];
 
 gtk_init(&argc, &argv);
 
 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 
 gtk_window_set_title (GTK_WINDOW (window), "Gtk_p4");
 
 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);             
                  
 
 grid = gtk_grid_new();
 
 gtk_grid_set_row_spacing (GTK_GRID(grid), 10);
 
 gtk_grid_set_column_spacing (GTK_GRID(grid), 10);
 
 gtk_container_add (GTK_CONTAINER (window), grid);
 
 entry = gtk_entry_new();
 
 gtk_grid_attach(GTK_GRID(grid), entry, 0, 0, 1, 1);
 
 label = gtk_label_new("Some text");
  
 gtk_grid_attach(GTK_GRID(grid), label, 0, 1, 2, 1);
 
 button = gtk_button_new_with_label("Set text");
 
 gtk_grid_attach(GTK_GRID(grid), button, 1, 0, 1, 1);
 
 data[0] = (gpointer)label;
 data[1] = (gpointer)entry;
 data[2] = (gpointer)window;
 
 g_signal_connect(button, "clicked", G_CALLBACK(button_clicked)
 (gpointer)data);
 
 gtk_widget_show_all(window);
 
 gtk_main();
 
 return 0;
 
}


syntax highlighted by Code2HTML, v. 0.9.1

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

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