В этом уроке мы разберем каким образом обрабатываются события в Tizen. Рассмотрим какие существуют типы событий.
В конце мы добавим обработку события нажатия на кнопку, созданную в прошлом уроке.
Как уже говорилось разработка нативных приложений в Tizen основывается на библиотеках EFL. А в EFL все события обрабатываются при помощи связи сигналов с функциями обратного вызова.
В главном цикле приложения, на системном уровне, идет проверка некоторых параметров и в случае например события нажатия на кнопку, система вызывает зарегестрированную функцию обратного вызова для этого события, если такая функция-обработчик была зарегистрирована.
Зная, что вызов обработчика происходит из главного цикла приложения и работа самого обработчика происходит в главном потоке, необходимо максимально сокращать функционал таких обработчиков. Допустим по нажатию кнопки в вашем приложении вы должны будете отправить запрос на сервер, в таком случае ваш пользовательский интерфейс будет заблокирован, пока запрос не будет выполнен. В таком случае правильно будет вызывать запрос в параллельном потоке, для этого есть модуль Ecore_Thread для создания и управления потоками. В дальнейшем будет отдельный урок по работе с этим модулем, а сейчас достаточно помнить, что в реальных приложениях, тяжелая работа для процессора должна происходить в параллельных потоках, а не в обработчиках событий.
Общими словами, в системе могут происходить различные события, например, изменение языка интерфейса на устройстве. Для того что бы предпринять некоторые действия в нашем приложении после такого события, мы должны зарегестировать обработчик на событие вызовом нужной функции и реализовать саму функцию обработчик данного события, при этом сигнатура функции должна быть соответствующей.
В EFL существует 4 основных вида событий, рассмотрим их:
Ecore event – это события самого низкого уровня EFL приложения такие события приходят прямо от системы, их не советуется использовать.
Evas event – такие события привязаны к холсту на котором происходит прорисовка графического интерфейса, такие события являются тоже достаточно низко-уровневыми, и их тоже не советуется использовать, исключение если вы будете делать свою прорисовку.
Следующие типы событий мы рассмотрим подробнее, поскольку будем их часто использовать в дальнейшем в наших уроках.
Evas object event – эти события происходят для объектов находящихся на холсте, это могут быть примитивные объекты или полноценные виджеты.
Evas smart event – это события самого высокого уровня, относятся они к самим виджетам.
То что мы рассмотрели касается к событиям графического интерфейса, на подобии событий изменения размера или отображения некоторых графических элементов.
В модулях отвечающих за другую функциональность, отличную от графики, также используются события и функции-обратного вызова. Но для каждого модуля существуют свои типы событий и обработчики также выглядят по разному.
Так например при необходимости получения координат устройства вы не сможете вызвать какую-то функцию и тут же получить координаты. поскольку устройство для начала должно подготовить аппаратную часть, затем получить устойчивые сигналы от спутников, вычислить где находиться устройство относительно спутников, и только потом могут быть получены координаты. Такие процедуры могут занимать некоторое время иногда даже более минуты. В таком случае процесс будет следующим: вы вызовете функцию получения координат, и передадите функцию обратного вызова которая выполнится после всех процедур вычисления, и уже там вы сможете обработать полученные координаты.
События такого типа происходят для всех графических объектов размещенных на холсте, будь то прямоугольник, или кнопка. Вы можете отлавливать события одним и тем же образом для разных объектов.
Ниже представлен список наиболее часто используемых событий.
Следующие 3 события относятся к нажатию в области объектов одним пальцем.
EVAS_CALLBACK_MOUSE_DOWN - начало нажатия в области объекта.
EVAS_CALLBACK_MOUSE_UP - конец нажатия.
EVAS_CALLBACK_MOUSE_MOVE - точка указателя переместилась относительно предыдущей позиции.
Важно:
Событие перемещения указателя EVAS_CALLBACK_MOUSE_MOVE может быть вызвано раньше чем EVAS_CALLBACK_MOUSE_DOWN даже если вы нажимаете пальцем на экран. А также может быть вызвано без события нажатия если к устройству подключена компьютерная мышь.
Следующие 3 события относятся к касаниям объектов, вторым или более по-счету пальцем одновременно
EVAS_CALLBACK_MULTI_DOWN - новый палец прикоснулся в области объекта.
EVAS_CALLBACK_MULTI_UP - один из пальцев закончил касание
EVAS_CALLBACK_MULTI_MOVE - один из пальцев закончил касание
EVAS_CALLBACK_FREE - вызывается перед очисткой памяти выделенной для графического объекта.
Следующие события срабатывают после вызовов некоторых функций системой или из наших программ
EVAS_CALLBACK_SHOW - cрабатывает после вызова функции evas_object_show().
Важно:
Событие срабатывает именно после вызова функции evas_object_show(), а не после того как объект отобразился на экране.
EVAS_CALLBACK_HIDE - cрабатывает после вызова функции evas_object_hide().
EVAS_CALLBACK_MOVE - cрабатывает после вызова функции evas_object_move().
EVAS_CALLBACK_RESIZE - cрабатывает после вызова функции evas_object_resize().
EVAS_CALLBACK_DEL - cрабатывает после вызова функции evas_object_del().
Давайте рассмотрим как же использовать такие события.
Допустим у нас есть графический объект размещенный на холсте
Evas_Object *rect;
Зарегистрируем обработчик на событие удаления объекта следующим образом.
evas_object_event_callback_add(rect, EVAS_CALLBACK_DEL, del_callback, user_data);
И реализуем саму функцию обработчик del_callback которая должна вызваться при вызове удаления нашего объекта.
static void
del_callback(void *user_data, Evas *evas, Evas_Object *obj, void *event_info)
{
// Тело обработчика
}
Для всех событий типа Evas object event сигнатура обработчика одинаковая. Так первым параметром приходит указатель на пользовательские данные которые мы передаем при регистрации обработчика последним аргументом, второй параметр – объект холста на котором произошло событие, он не часто используется. Третьим параметром является объект над которым произошло событие, или вызов функции которая привела к событию, и последним параметром приходит указатель на структуру описывающую событие в деталях.
Последний параметр не всегда валидный, иногда параметр – NULL. Но например при событии нажатия туда приходит объект структуры из которой можно получить например координаты в которых произошло нажатие, это иногда бывает полезно. Мы будем описывать подробнее последний параметр при использовании в других уроках.
Умные события (evas smart event) имеют место только для полноценных виджетов библиотеки Elementary.
У каждого виджета имеется свой уникальный список поддерживаемых событий. Так например у кнопки одним из доступных событий является "отжатие".
В дальнейшем в уроках к конкретным виджетам мы будем описывать какие события доступны для них.
Для регистрации таких событий используется следующая функция.
evas_object_smart_callback_add(widget, "event", event_callback, user_data);
Обработчик умного события должен иметь следующую сигнатуру.
void smart_callback(void *user_data, Evas_Object *obj, void *event_info);
Первым параметром приходит указатель на пользовательские данные, вторым – объект для которого сработало событие, а третьим – дополнительная информация о событии, но последний параметр может быть и пустым.
Также стоит заметить, что в ваших приложениях вы сможете создавать собственные виджеты, неважно какие, но суть в том что вы сможете создавать свои новые события для вашего виджета.
К примеру вы создадите индикатор заряда батареи и хотите что бы при использовании вашего виджета можно было отлавливать событие когда значение заряда изменилось. Так для эмуляции события, назовем его "charge,value,changed", необходимо будет в нужный момент вызвать следующую функцию.
evas_object_smart_callback_call(battery_widget, "charge,value,changed", event_info);
В функции первый параметр – это виджет для которого необходимо сымитировать событие, второй – название события, третий – дополнительная информация о событии, можно передать NULL, а можно и создать структуру с информацией о событии, главное добавить коментарии по поводу использования вашего виджета.
Таким образом вы сможете создавать свои умные виджеты, и переиспользовать их.
Для виджета-кнопки доступны следующие умные события.
"clicked" – событие клика, происходит при быстром прикосновении и отжимании в области кнопки.
"pressed" – событие зажатия кнопки.
"unpressed" – событие отжатия кнопки.
"repeated" – настраиваемое событие, может неоднократно вызываться в случае зажатия кнопки. Для этого события возможно настроить начальную задержку перед срабатыванием, а также интервал между повторениями.
Теперь зная почти всё о событиях пользовательского интерфейса, давайте добавим обработку этих событий кнопки в нашем приложении.
Для начала зарегистрируем события.
static void
_button_create(Evas_Object *parent)
{
...
evas_object_smart_callback_add(ui->button, "pressed", press_cb, NULL);
evas_object_smart_callback_add(ui->button, "unpressed", unpress_cb, NULL);
evas_object_smart_callback_add(ui->button, "repeated", repeat_cb, NULL);
evas_object_smart_callback_add(ui->button, "clicked", click_cb, NULL);
}
Теперь реализуем сами обработчики в которых будем выводить в лог информацию о событии.
Для использования логгирования сначала включим следующий заголовочный файл.
#include <dlog.h>
И реализуем обработчики
static void
press_cb(void *data, Evas_Object *button, void *event_info)
{
dlog_print(DLOG_DEBUG, "lesson15", "Событие PRESS!");
}
static void
unpress_cb(void *data, Evas_Object *button, void *event_info)
{
dlog_print(DLOG_DEBUG, "lesson15", "Событие UNPRESS!");
}
static void
repeat_cb(void *data, Evas_Object *button, void *event_info)
{
dlog_print(DLOG_DEBUG, "lesson15", "Событие REPEAT!");
}
static void
click_cb(void *data, Evas_Object *button, void *event_info)
{
dlog_print(DLOG_DEBUG, "lesson15", "Событие CLICK!");
}
Как было сказано ранее, виджет поддерживает событие "repeated", но для его использования необходима активация у кнопки должен быть включен режим аutorepeat.
Для включения вызовите следующую функцию и передайте в нее вторым параметро EINA_TRUE для включения режима или EINA_FALSE для отключения.
elm_button_autorepeat_set(ui->button, EINA_TRUE);
Сейчас если кнопка будет зажата то событие "repeated" будет вызываться непрерывно (каждую итерацию главного цикла приложения), это поведение режима автоповторения по умолчанию. Существуют дополнительные функции для настройки интервалов (начального и промежуточного).
Зададим начальный интервал срабатывания 2 секунды, а промежуточный полсекунды. Для этого вызовем две следующие функции:
elm_button_autorepeat_initial_timeout_set(ui->button, 3);
elm_button_autorepeat_gap_timeout_set(ui->button, 0.5);
Давайте запустим наше приложение.
Как видно все наши события кнопки обрабатываются, время срабатывания события "repeated" можно оценить в окне логгирования, а также можно сделать вывод что событие клик это совокупность события нажатия и отпускания кнопки, как и должно быть.
В следующем уроке мы рассмотрим текстовый виджет и будем изменять текст в нем после нажатия на кнопку. Полный код этого урока вы можете скачать здесь WearLesson015.