среда, 22 мая 2013 г.

Gtk+. События окна на нажатие мыши


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

Первым делом нам необходимо подсоединить, определенную нами GCallback функцию с именем on_button_press, к сигналу button-press-event для объекта нашего окна с именем window.

g_signal_connect(window, "button-press-event", G_CALLBACK(on_button_press), NULL);

Данную функцию нужно разместить сразу после строчки:

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


Таким образом, когда мы нажимаем кнопкой мыши в окне, то возникает сигнал button-press-event и вызывает определенную нами функцию on_button_press. Ниже показана реализация функции on_button_press:

gboolean on_button_press (GtkWidget* widget, GdkEventButton * event)   
{  
   if (event->type == GDK_BUTTON_PRESS)
   {  
      if (event->button == 1)
      {
           g_print("Left button pressed\n");
           my_modal_dialog(GTK_WINDOW(widget), "Left button pressed\n");  
      }
      if (event->button == 2)  
      {
           g_print("Middle button pressed\n");
           my_modal_dialog(GTK_WINDOW(widget), "Middle button pressed\n");
       }
      if (event->button == 3)
      {  
           g_print("Right button pressed\n");
           my_modal_dialog(GTK_WINDOW(widget), "Right button pressed\n"); 
      } 
   }
return TRUE;  
}


Давайте, вкратце, рассмотрим функцию on_button_press. Данная функция имеет два параметра, первый параметр это указатель на объект по которому нажали мышкой (GtkWidget* widget), а второй это событие которое произошло, в данном случае нажата кнопка мыши (GdkEventButton * event). Внутри функции мы проверим тип события event->type (т.е. GDK_BUTTON_PRESS — нажата ли кнопка, GDK_BUTTON_RELEASE — отпущена ли кнопка, и другое). Далее мы проверяем какая кнопка мыши нажата event->button (1 — Левая кнопка мыши, 2 — Средняя кнопка мыши, 3 — Правая кнопка мыши), и в зависимости от того какая клавиша мыши нажата, то возникает модальный диалог с необходимым сообщением (например, my_modal_dialog(GTK_WINDOW(widget), "Left button pressed\n"), если нажата левая кнопка мыши). По окончанию работы функция on_button_press возвращает TRUE.
Теперь напишем функцию модального диалога void my_modal_dialog(GtkWindow* parent, gchar* str). Это функция имеет два параметра, первый это указатель на окно — родитель модального диалога (GtkWindow* parent), второй параметр, это строка, которую будет содержать наш модальный диалог (gchar* str).

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);  
}


Внутри функции мы создаем новое диалоговое окно, это простой диалог с иконкой и пользовательским сообщением. Функция, которая создает новый диалог с сообщением, показана ниже:


GtkWidget* modal_dialog = gtk_message_dialog_new(parent, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, str);

1) GtkWidget* modal_dialog указатель на виджет — диалог.
2) Теперь пройдемся по параметрам gtk_message_dialog_new
  • Первый параметр это указатель на окно — родитель, имя parent
  • Второй параметр, это флаги диалога, например флаг GTK_DIALOG_DESTROY_WITH_PARENT, который уничтожает диалог вместе с окном - родителем.
  • Третий параметр, это тип сообщения, например GTK_MESSAGE_INFO — информативное сообщение.
  • Четвертый параметр, это тип кнопки диалога, например GTK_BUTTONS_CLOSE — кнопка с надписью «Close».
  • Пятый параметр, это строка сообщения.

Дальше нам необходимо запустить наш, только что созданный, диалог. Сделать это можно следующей строчкой:

gtk_dialog_run(GTK_DIALOG(modal_dialog));

Данной функций мы отображаем диалог и все его виджеты, блокируем главный цикл обработки сообщений, до тех пор, пока диалог не будет уничтожен или пока пользователь не ответит на диалог, например нажав на кнопку «Close». Подробнее по функции gtk_dialog_run можно прочитать на официальном сайте.

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

gtk_widget_destroy(modal_dialog);

Теперь реализуем возможность нашего приложения закрываться по нажатию на клавишу «Esc» и выдавать диалоговое сообщение, если нажата любая другая клавиша.

Присоединим, определенную нами GCallback функцию с именем on_key_press, к сигналу key_press_event для объекта нашего окна с именем window.

g_signal_connect(window, "key-press-event", G_CALLBACK(on_key_press), NULL);

Данную функцию нужно разместить сразу после строчки:

g_signal_connect(window, "button-press-event", G_CALLBACK(on_button_press), NULL);

Таким образом, когда мы нажимаем любую клавишу в окне, то возникает сигнал key-press-event и вызывает определенную нами функцию on_key_press. Ниже показана реализация функции on_key_press:

gboolean on_key_press(GtkWidget *widget, GdkEventKey *event)  
{  
g_printerr("%s\n", gdk_keyval_name (event->keyval));
g_printerr("%d\n", event->keyval);

if (event->type == GDK_KEY_PRESS)
{  
   switch (event->keyval)  
   {  
      case GDK_KEY_Escape:
                 gtk_widget_destroy(widget);
                 break;  
      default:  
                 my_modal_dialog(GTK_WINDOW(widget), "Any Key pressed"); 
              break;
   }  
}
return TRUE;  
}


Перед тем как мы разберем функцию on_key_press, нам необходимо добавить еще один заголовочный файл gdk/gdkkeysyms.h, в котором определены все значения клавиш клавиатуры. Для этого разместите строчку: #include <gdk/gdkkeysyms.h> после строчки #include <gtk/gtk.h>.

Внутри функции on_key_press мы проверяем тип события нажатия event->type, например GDK_KEY_PRESS — нажата ли клавиша. Потом проверяем нажата ли клавиша «Esc» или любая другая клавиша, то уничтожаем главное окно программы или показываем диалог с сообщением, что нажата любая клавиша, соответственно.

И напоследок, добавим нашему контейнеру — сетке пробелы, по строчкам и по колонкам сетки. Этим мы сделаем так, чтобы между виджетами были интервалы. Разместите следующие две строчки после функции создания новой сетки grid = gtk_grid_new():

gtk_grid_set_row_spacing (GTK_GRID(grid), 10);

gtk_grid_set_column_spacing (GTK_GRID(grid), 10);


Рисунок 1. Пример события на нажатие кнопки мыши

Рисунок 2. Пример события на нажатия клавиши клавиатуры

#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.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);
}

gboolean
on_key_press(GtkWidget *widget,
          GdkEventKey *event)
{
    g_printerr("%s\n",
               gdk_keyval_name (event->keyval));
               
    g_printerr("%d\n", event->keyval);
    
    
    if (event->type == GDK_KEY_PRESS) {

  switch (event->keyval)
  {
   case GDK_KEY_Escape:
    gtk_widget_destroy(widget);
    break;
   default:
    my_modal_dialog(GTK_WINDOW(widget),
                                                "Any Key pressed");
    break;
  }
 
 }
 
    return TRUE;
}

gboolean on_button_press (GtkWidget* widget,
  GdkEventButton * event)
{
  if (event->type == GDK_BUTTON_PRESS)
  {
    if (event->button == 1) {
  g_print("Left button pressed\n");
  my_modal_dialog(GTK_WINDOW(widget),  
                                "Left button pressed\n");
    }
    if (event->button == 2) {
  g_print("Middle button pressed\n");
  my_modal_dialog(GTK_WINDOW(widget),  
                                "Middle button pressed\n");
 }
 if (event->button == 3) {
  g_print("Right button pressed\n");
  my_modal_dialog(GTK_WINDOW(widget),  
                                "Right button pressed\n");
 }
  }

  return TRUE;
}

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

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

 
 gtk_init(&argc, &argv);
 
 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 
 gtk_window_set_title (GTK_WINDOW (window), "Gtk_p3");
 
 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);
 
 g_signal_connect(window, "button-press-event",
      G_CALLBACK(on_button_press), NULL);
 
 g_signal_connect(window, "key-press-event",  
      G_CALLBACK(on_key_press), 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);

 gtk_widget_show_all(window);
 
 gtk_main();
 
 return 0;
 
}


syntax highlighted by Code2HTML, v. 0.9.1

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

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