4.6 События, их обработка и карты событий
Учитывая спектр задач для которых может использоваться система OpenSCADA нужно предусмотреть и механизм управления интерактивными пользовательскими событиями. Это связано с тем, что при решении отдельных задач встраиваемых систем устройства ввода и управления могут значительно отличатся. Впрочем достаточно взглянуть на обычную офисную клавиатуру и клавиатуру ноутбука что бы снять любые сомнения о необходимости менеджера событий.
Менеджер событий должен работать используя карты событий. Карта событий это список именованных событий с указанием его происхождения. Происхождением события может быть клавиатура, манипулятор мыши, джойстик и т.д. При возникновении события менеджер событий ищет его в активной карте и сопоставляет с именем события. Сопоставленное имя события помещается в очередь на обработку. Виджеты, в этом случае, должны обрабатывать полученную очередь событий.
Активная карта событий указывается в профиле каждого пользователя или устанавливается по умолчанию.
В целом предусмотрены четыре типа событий:
- события образов СВУ (префикс: ws_), например событие нажатия кнопки примитива "FormEl" - ws_BtPress;
- клавишные события (префикс: key_), все события от клавиатуры и мыши в виде - key_presAlt1;
- пользовательские события (префикс: usr_), генерируются пользователем в процедурах обсчёта виджетов;
- мапированные события (префикс: map_), события полученные из карты событий.
Само событие представляет недостаточно информации, особенно если его обработка происходит на уровнях выше. Для однозначной идентификации события и его источника событие в целом записывается следующим образом: "ws_BtPress:/curtime". Где:
ws_BtPress -- событие;
/curtime -- путь к дочернему элементу, генерировавшего событие.
В таблице 4.6 приведён перечень стандартных событий, поддержка которых должна быть обеспечена в визуализаторах СВУ.
Таблица 4.6. Стандартные события
| Id | Описание |
| Клавиатурные события: key_[pres|rels][Ctrl|Alt|Shift]{Key} |
| *SC#3b | Скан код клавиши. |
| *#2cd5 | Код не именованной клавиши. |
| *Esc | "Esc". |
| *BackSpace | Удаления предыдущего символа - "<--". |
| *Return, *Enter | Ввод - "Enter". |
| *Insert | Вставка - "Insert". |
| *Delete | Удаление - "Delete". |
| *Pause | Пауза - "Pause". |
| *Print | Печать экрана - "Print Screen". |
| *Home | Дом - "Home". |
| *End | Конец - "End". |
| *Left | Влево - "<-". |
| *Up | Вверх - "^". |
| *Right | Вправо - "->". |
| *Down | Вниз - "\/". |
| *PageUp | Страницы вверх - "PageUp". |
| *PageDown | Страницы вниз - "PageDown". |
| *F1 - *F35 | Функциональная клавиша от "F1" до "F35". |
| *Space | Пробел - " ". |
| *Apostrophe | Апостраф - "`". |
| *Asterisk | Звёздочка на дополнительном поле клавиатуры - "*". |
| *Plus | Плюс на дополнительном поле клавиатуры - "+". |
| *Comma | Запятая - ",". |
| *Minus | Минус - "-". |
| *Period | Точка - ".". |
| *Slash | Наклонная черта - "\". |
| *0 - *9 | Цифра от "0" до "9". |
| *Semicolon | Точка с запятой - ";". |
| *Equal | Равно - "=". |
| *A - *Z | Клавиши букв латинского алфавита от "A" до "Z". |
| *BracketLeft | Левая квадратная скобка - "[". |
| *BackSlash | Обратная наклонная линия - "/". |
| *BracketRight | Правая квадратная скобка - "]". |
| *QuoteLeft | Левая кавычка - "'". |
| События клавиатурного фокуса. |
| ws_FocusIn | Фокус получен виджетом. |
| ws_FocusOut | Фокус утерян виджетом. |
| Мышиные события: |
| key_mouse[Pres|Rels][Left|Right|Midle] | Нажата/отпущена кнопка мыши. |
| key_mouseDblClick | Двойное нажатие левой кнопки мыши. |
| События примитива элементарной фигуры ElFigure: |
| ws_Fig{n}[Left|Right|Midle|DblClick] | Активация фигуры {n} клавишей мыши. |
| События примитива элементов формы FormEl: |
| ws_LnAccept | Установлено новое значение в строке ввода. |
| ws_TxtAccept | Изменено значение редактора текста. |
| ws_ChkChange | Состояние флажка изменено. |
| ws_BtPress | Кнопка нажата. |
| ws_BtRelease | Кнопка отпущена. |
| ws_BtToggleChange | Изменена вдавленность кнопки. |
| ws_CombChange | Изменено значение поля выбора. |
| ws_ListChange | Изменен текущий элемент списка. |
| ws_SliderChange | Изменение положения слайдера. |
| События примитива медиа-контента Media: |
| ws_MapAct{n}[Left|Right|Midle] | Активирована медиа-область с номером {n} клавишей мыши. |
События являются основным механизмом уведомления и активно используются для осуществления взаимодействия с пользователем. Для обработки событий предусмотрены два механизма: сценарии управления открытием страниц и вычислительная процедура виджета.
Механизм "Сценарии управления открытием страниц" основан на базовом атрибуте виджета "evProc", который содержит список сценариев операций открытия страниц с синтаксисом:
<event>:<evSrc>:<com>:<prm>. Где:
- event -- ожидаемое событие;
- evSrc -- путь вложенного виджета-источника события ('*' - указывается на обработку этим сценарием событий от любого источника);
- com -- команда сеанса;
- prm -- параметр команды.
Реализованы следующие команды:
- open -- Открытие страницы. Открываемая страница указывается в параметре <prm> как на прямую, так и в виде шаблона (например: /pg_so/1/*/*).
- next -- Открытие следующей страницы. Открываемая страница указывается в параметре <prm> в виде шаблона (например: /pg_so/*/*/$).
- prev -- Открытие предыдущей страницы. Открываемая страница указывается в параметре <prm> в виде шаблона (например: /pg_so/*/*/$).
Специальные символы шаблона расшифровываются следующим образом:
- pg_so -- прямое имя требуемой страницы с префиксом. Требует обязательного соответствия и используется для идентификации предыдущей открытой страницы;
- 1 -- имя новой страницы, в общем пути без префикса. Игнорируется при обнаружении предыдущей открытой страницы;
- * -- страница берётся из имени предыдущей открытой страницы или подставляется первая доступная страница, в случае если предыдущая открытая страница отсутствует;
- $ -- указывает на место открытой страницы, относительно которой необходимо искать следующую или предыдущую.
В качестве примера приведём сценарий обеспечения работы главной страницы интерфейса пользователя:
ws_BtPress:/prev:prev:/pg_so/*/*/$
ws_BtPress:/next:next:/pg_so/*/*/$
ws_BtPress:/go_mn:open:/pg_so/*/mn/*
ws_BtPress:/go_graph:open:/pg_so/*/ggraph/*
ws_BtPress:/go_cadr:open:/pg_so/*/gcadr/*
ws_BtPress:/go_view:open:/pg_so/*/gview/*
ws_BtPress:/go_doc:open:/pg_so/*/doc/*
ws_BtPress:/go_resg:open:/pg_so/rg/rg/*
ws_BtPress:/so1:open:/pg_so/1/*/*
ws_BtPress:/so2:open:/pg_so/2/*/*
ws_BtPress:/so3:open:/pg_so/3/*/*
ws_BtPress:/so4:open:/pg_so/4/*/*
ws_BtPress:/so5:open:/pg_so/5/*/*
ws_BtPress:/so6:open:/pg_so/6/*/*
ws_BtPress:/so7:open:/pg_so/7/*/*
ws_BtPress:/so8:open:/pg_so/8/*/*
ws_BtPress:/so9:open:/pg_so/9/*/*
ws_BtPress:*:open:/pg_control/pg_terminator
Механизм "Обработка событий с помощью вычислительной процедуры виджета" основан на атрибуте "event" и пользовательской процедуре вычисления на одном из языков пользовательского программирования OpenSCADA. События, по мере поступления, аккумулируются в атрибуте "event" до момента вызова вычислительной процедуры. Вычислительная процедура вызывается с указанной периодичностью вычисления виджета и получает значение атрибута "event" в виде списка событий. В процедуре вычисления пользователь может: проанализировать, обработать и исключить обработанные события из списка, а также добавить в список новые события. Оставшиеся, после исполнения процедуры события, анализируются на предмет соответствия условиям вызова сценарием первого механизма, после чего, оставшиеся события, передаются на верхний по иерархии виджет для обработки им, при этом осуществляется коррекция пути событий в соответствии с иерархией проникновения события.
Содержимое атрибута "event" является списком событий формата
<event>:<evSrc>, с событием в отдельной строке. Приведём пример процедуры обработки событий на Java-подобном языке пользовательского программирования OpenSCADA:
using Special.FLibSYS;
ev_rez = "";
off = 0;
while(true)
{
sval = strParse(event,0,"\n",off);
if( sval == "" ) break;
else if( sval == "ws_BtPress:/cvt_light" ) alarmSt = 0x1000001;
else if( sval == "ws_BtPress:/cvt_alarm" ) alarmSt = 0x1000002;
else if( sval == "ws_BtPress:/cvt_sound" ) alarmSt = 0x1000004;
else ev_rez+=sval+"\n";
}
event=ev_rez;