The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]

Каталог документации / Раздел "Программирование, языки" / Оглавление документа

GTK+ 2.0 Tutorial

<<< Previous

Scribble, A Simple Example Drawing Program

Next >>>


Обработка событий

Сигналы GTK для действий высшего уровня (high-level) мы уже обсудили, такие как выбор пункта меню. Но иногда полезно использовать сигналы низкого уровня (lower-level), такие как передвижение курсора мышки, или нажатие клавиши. Обработчики для этих сигналов имеют дополнительный параметр, который является указателем на структуру, содержащую информацию о событии. Например, обработчики события движения передают указатель на структуру GdkEventMotion, которая частично выглядит так:

struct _GdkEventMotion
{
  GdkEventType type;
  GdkWindow *window;
  guint32 time;
  gdouble x;
  gdouble y;
  ...
  guint state;
  ...
};

type - устанавливает тип события, в этом случае GDK_MOTION_NOTIFY, window - окно в котором произошло событие. x и y - координаты произошедшего события. state - определяет состояние модификатора, когда произошло событие ( то есть определяет, какие модифицирующие клавиши и кнопки мыши были нажаты). Это - поразрядное ИЛИ, как например:

GDK_SHIFT_MASK  
GDK_LOCK_MASK   
GDK_CONTROL_MASK
GDK_MOD1_MASK   
GDK_MOD2_MASK   
GDK_MOD3_MASK   
GDK_MOD4_MASK   
GDK_MOD5_MASK   
GDK_BUTTON1_MASK
GDK_BUTTON2_MASK
GDK_BUTTON3_MASK
GDK_BUTTON4_MASK
GDK_BUTTON5_MASK

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

void gtk_widget_set_events (GtkWidget *widget,
                            gint      events);

Вторая часть определяет события, которыми мы интересуемся. Это - поразрядное ИЛИ констант, которые определяют различные типы событий. Типы события:

GDK_EXPOSURE_MASK
GDK_POINTER_MOTION_MASK
GDK_POINTER_MOTION_HINT_MASK
GDK_BUTTON_MOTION_MASK     
GDK_BUTTON1_MOTION_MASK    
GDK_BUTTON2_MOTION_MASK    
GDK_BUTTON3_MOTION_MASK    
GDK_BUTTON_PRESS_MASK      
GDK_BUTTON_RELEASE_MASK    
GDK_KEY_PRESS_MASK         
GDK_KEY_RELEASE_MASK       
GDK_ENTER_NOTIFY_MASK      
GDK_LEAVE_NOTIFY_MASK      
GDK_FOCUS_CHANGE_MASK      
GDK_STRUCTURE_MASK         
GDK_PROPERTY_CHANGE_MASK   
GDK_PROXIMITY_IN_MASK      
GDK_PROXIMITY_OUT_MASK     

Есть несколько нюансов которые нужно соблюсти вызывая gtk_widget_set_events(). Первое - нужно вызвать эту функцию перед тем как будет создано окно X для виджета GTK. Практически вы должны вызвать функцию сразу после создания виджета. Во вторых - виджет должен иметь ассоциированное X окно(X window).  Для эффективности, многие типы виджетов не имеют собственного окна, а отображаются в окне их родителя. Вот эти виджеты:

GtkAlignment
GtkArrow
GtkBin
GtkBox
GtkImage
GtkItem
GtkLabel
GtkPixmap
GtkScrolledWindow
GtkSeparator
GtkTable
GtkAspectFrame
GtkFrame
GtkVBox
GtkHBox
GtkVSeparator
GtkHSeparator

Чтобы перехватывать события для этих виджетов, вы должны использовать виджет EventBox. См. раздел EventBox.

Для нашей программы рисования, мы должны знать, когда кнопка мыши нажата и мышь перемещена, таким образом мы определяем GDK_POINTER_MOTION_MASK и GDK_BUTTON_PRESS_MASK. Мы также должны знать, когда перерисовать наше окно, таким образом мы определяем GDK_EXPOSURE_MASK. Хотя нам необходимо уведомление об изменении размера нашего окна через конфигурацию события, мы не должны определять передачу флага GDK_STRUCTURE_MASK, потому что это автоматически определено для всех окон.

Однако, как оказывается есть проблема с определением GDK_POINTER_MOTION_MASK. Это заставит сервер добавлять новое событие передвижения в очередь событий каждый раз, когда пользователь перемещает мышь. Вообразите, что нам требуется 0.1 секунды, чтобы обработать событие движения, но в очередь X сервера поступает новое событие передвижения каждые 0.05 секунды. Если пользователь рисовал в течении 5 секунд, нам потребуется ещё 5 секунд для перехвата после освобождения кнопки мышки! Но нам нужно получить только одно событие движения для каждого случая, который мы обрабатываем. Это можно сделать определив GDK_POINTER_MOTION_HINT_MASK.

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

GdkWindow*    gdk_window_get_pointer     (GdkWindow       *window,
                                          gint            *x,
                                          gint            *y,
                                          GdkModifierType *mask);

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

Код установки событий для нашего окна выглядит так:

  gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
                      (GtkSignalFunc) expose_event, NULL);
  gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event",
                      (GtkSignalFunc) configure_event, NULL);
  gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event",
                      (GtkSignalFunc) motion_notify_event, NULL);
  gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event",
                      (GtkSignalFunc) button_press_event, NULL);
  gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
                         | GDK_LEAVE_NOTIFY_MASK
                         | GDK_BUTTON_PRESS_MASK
                         | GDK_POINTER_MOTION_MASK
                         | GDK_POINTER_MOTION_HINT_MASK);

Мы сохраним "expose_event" и "configure_event" обработчики позже. Обработчики "motion_notify_event" и "button_press_event" довольно просты:

static gint
button_press_event (GtkWidget *widget, GdkEventButton *event)
{
  if (event->button == 1 && pixmap != NULL)
      draw_brush (widget, event->x, event->y);
  return TRUE;
}
static gint
motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
{
  int x, y;
  GdkModifierType state;
  if (event->is_hint)
    gdk_window_get_pointer (event->window, &x, &y, &state);
  else
    {
      x = event->x;
      y = event->y;
      state = event->state;
    }
    
  if (state & GDK_BUTTON1_MASK && pixmap != NULL)
    draw_brush (widget, x, y);
  
  return TRUE;
}

<<< Previous

Home

Next >>>

Scribble, A Simple Example Drawing Program

Up

The DrawingArea Widget, And Drawing






Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2024 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру