Изменение вида на панели: api - helper - 2
Оператор нажал кнопку, устройство ответило, и теперь на панели нужно что-то показать: подсветить кнопку, подвинуть ползунок, написать «Идёт разговор» на зелёной плашке, заполнить список. Для этого в U-Logic (редактор программы управления) есть узел (блок программы) api - helper - 2. Вы говорите ему «у элемента с таким именем измени вот это», а он собирает сообщение, понятное панели, и передаёт узлу UI - Panel out.
Главное: что выбираете вы и что приходит в сообщении
Узел делает работу в два приёма; не путайте, кто какой делает.
Что |
Где задаётся |
Пример |
|---|---|---|
Что менять — какой элемент и какое его свойство (вид кнопки, текст, цвет фона, положение ползунка, строки списка) |
в окне узла, в карточке «Объекты управления»: «Элемент:» и «Событие:» |
элемент |
Каким сделать — само значение |
в сообщении, по умолчанию в |
|
Значение не придумывают и не вписывают в карточку руками. Его готовит узел change из ответа устройства. Ответ пришёл, change взял из него нужное поле и положил в msg.topic в виде {"имя элемента": значение}. Узел api - helper - 2 по имени нашёл элемент в карточке и отправил панели готовую команду.
flowchart LR
DEV["Устройство"] --> RL["device - response - listener<br/>(ответ устройства)"]
RL --> SW["switch<br/>(какой это ответ?)"]
SW --> CH["change<br/>(готовит msg.topic)"]
CH --> AH["api - helper - 2<br/>(что менять)"]
AH --> OUT["UI - Panel out"]
OUT --> P["Панель"]
Здесь разобраны четыре таких пути на живых ответах двух устройств: звукового процессора и кодека видеоконференцсвязи:
состояние кнопки по ответу: «звук выключен» → вид кнопки;
ползунок и надпись: уровень громкости из ответа → положение ручки и подпись в дБ, а в обратную сторону — ручку отпустили → команда в дБ;
текст и цвет фона по состоянию звонка;
список из ответа кодека и выбор строки.
Каждый пример построен одинаково: (1) что пришло от устройства — сообщение из отладки; (2) разбор — узлы switch и change, поля окон, выражение по частям; (3) окно api - helper - 2 — какая карточка; (4) что получилось на панели. Затем идут проверка без устройства, сводная таблица, переход на другую страницу и смена оверлея (отдельной «подстраницы» со своим холстом), в конце — частые ошибки.
Что нужно заранее:
интерфейс сохранён и опубликован в UI-Designer (редактор интерфейсов): иначе узел не увидит элементов (см. «Связь интерфейса с программой»);
на вкладке (рабочем листе программы) есть развёрнутый узел
UI - Panel out(правки запущены в работу кнопкой «Развернуть»);вы прошли «Первую программу»: знаете
ui - switch,changeиdevice - response - listener. Примеры ниже — это блоки «Звук» и «ВКС» той же вкладки «Первая программа» и страница «Устройства» её интерфейса. Как их собрать по шагам, описано в блоках H и I на странице «Первая программа по шагам».
Примечание
Выражения в change ниже записаны на JSONata — коротком языке формул, который вычисляется над сообщением. Если он вам ещё не знаком, прочитайте блок F в «Первой программе»: там разобрано, что такое payload.value, фигурные скобки и сравнение.
Как узел работает
берёт данные — объект «имя элемента → значение» — из выбранного поля сообщения;
сверяет имена с элементами выбранного интерфейса;
кладёт в
msg.payloadготовое сообщение для панели; прежнее содержимоеmsg.payloadпри этом пропадает.
Поэтому данные для панели кладите в msg.topic, а не в msg.payload: после этого узла прежнего содержимого msg.payload уже не будет. Если оно нужно дальше, возьмите его до api - helper - 2.
В готовом сообщении два списка: payload.actions — все действия, по одному на событие, и payload.object — прежний формат для совместимости, где на один элемент остаётся одно событие. Если одному элементу вы задали два события (например, uiState и text), в payload.object виден только один из них: при отладке смотрите payload.actions.
Окно узла
Окно узла api - helper - 2: 1 — «Интерфейс (UI)», 2 — «Тип сообщения», 3 — «Источник входных данных», 4 — карточка элемента в списке «Объекты управления» с полями «Элемент:» и «Событие:»
«Интерфейс (UI)» — интерфейс, которому адресовано сообщение. Без него панель не поймёт, куда применить изменения. Список интерфейсов появляется после «Сохранить» и «Опубликовать» в UI-Designer.
«Тип сообщения» — выберите
uiState: это «изменить вид элементов». Второй тип,navigation, открывает страницу интерфейса (см. раздел «Переход на другую страницу из программы» ниже).«Источник входных данных» — откуда узел берёт объект с данными. По умолчанию это
msg.topic: оставьте так, и данные готовитchangeвmsg.topic. Можно указать другое поле сообщения (например,msg.payload) или переменную потока или общую память.«Объекты управления» — список элементов, которыми управляет узел. Элемент добавляют полем «Поиск элемента для добавления…» и кнопкой «+». В карточке элемента выбирают «Элемент:» и «Событие:» (что именно менять); поле «Значение:» — запасное значение, которое уйдёт, если данные не скажут другого.
Примечание
Список элементов необязателен. Если в «Объектах управления» пусто, узел принимает имена прямо из данных, но тогда для каждого элемента надо указать, что менять: {"Fp_Mute_b": {"uiState": "pressed"}}. Если элемент есть в списке, достаточно короткой записи: {"Fp_Mute_b": "pressed"}. Исключение — ползунок: ему карточка обязательна (там задаются Min и Max).
Пример 1. Состояние кнопки по ответу: «Звук в зале»
Зачем. Кнопка «Звук» на странице «Устройства» должна показывать не то, что оператор нажал, а то, что на самом деле сделал процессор: если звук выключили другим способом, кнопка тоже должна это показать. Состояний у кнопки четыре, каждое оформлено в UI-Designer по-своему (см. «Кнопки и состояния»):
Состояние |
Что значит |
|---|---|
|
обычное, ненажатое |
|
выбрана (в группе Interlock так подсвечена выбранная кнопка) |
|
нажата |
|
отключена: серая клавиша и серый текст, касания игнорируются |
Здесь кнопка — переключатель: нажата (pressed, зелёная, «Звук включён») или обычная (default, «Звук выключен»).
1. Что пришло от устройства
Процессор присылает уведомление при каждой смене состояния звука. В отладке (узел debug «Что прислал процессор», включите его кнопкой справа от узла) вы увидите сообщение с такими полями в payload:
{"publishToken": "fpHallMute", "value": true, "valueType": "bool", "type": "subscribeNotification"}
Отладка «Что прислал процессор»: 1 — ответ о звуке (publishToken fpHallMute, value), 2 — ответ об уровне (fpHallLevel, value в дБ)
publishToken— имя подписки: так программа узнаёт, что изменилось (о подписке — в блоке H «Первой программы»). Здесь это звук зала.value— новое состояние:true— звук выключен (mute включён),false— звук включён.valueType— тип значения (bool— «да или нет»,number— число).type— тип ответа; по немуdevice - response - listenerнаправил сообщение на нужный выход.
2. Разбор
Ответ проходит два узла.
switch «Какая подписка?». Процессор присылает по одной линии и звук, и громкость, поэтому сначала их надо разделить. Свойство — msg.payload.publishToken, два правила «==» (строка): fpHallMute и fpHallLevel. Сообщение с fpHallMute выходит из первого выхода — в наш пример, с fpHallLevel — из второго (пример 2).
Окно узла switch «Какая подписка?»: 1 — свойство msg.payload.publishToken, 2 — правило «== fpHallMute», 3 — правило «== fpHallLevel»
change «Mute → вид кнопки». Одно правило «Установить»: msg.topic, тип значения «выражение» (в окне он отмечен значком J: перед полем; слово «выражение» видно только в меню выбора типа), выражение
{"Fp_Mute_b": payload.value ? "default" : "pressed"}
Окно узла change «Mute → вид кнопки»: 1 — «Установить» msg.topic, 2 — тип «выражение», 3 — выражение
По частям:
{ … }— фигурные скобки собирают объект «имя: значение», ровно ту запись, которую ждётapi - helper - 2."Fp_Mute_b":— имя кнопки. Оно должно совпадать с именем в UI-Designer до буквы.payload.value ? "default" : "pressed"— «еслиpayload.valueистинно, взять"default", иначе"pressed"». Это условие в форме «вопрос ? если да : если нет».
Итого: value: true (звук выключен) → {"Fp_Mute_b": "default"}, value: false (звук включён) → {"Fp_Mute_b": "pressed"}. Результат лежит в msg.topic; в отладке «весь msg» вы увидите его рядом с прежним payload.
3. Окно api - helper - 2 «Кнопка: звук зала»
«Интерфейс (UI)» — «Первая программа».
«Тип сообщения» —
uiState.«Источник входных данных» —
msg.topic(по умолчанию).В «Объекты управления» — карточка: «Элемент:»
Fp_Mute_b, «Событие:» «Состояние кнопки» (группа «Состояние»), «Значение:»default.
Карточка узла api - helper - 2 «Кнопка: звук зала»: 1 — «Элемент:» Fp_Mute_b, 2 — «Событие:» «Состояние кнопки», 3 — «Значение:» (запасное)
Выбрано, что менять: состояние кнопки Fp_Mute_b. А каким оно станет, сказало сообщение: pressed или default.
Предупреждение
Значение из карточки узел отправляет на панель в каждом сообщении, где данные не называют этот элемент. Если в карточке кнопки стоит default, любое сообщение, не упоминающее эту кнопку, вернёт её в обычное состояние. Держите в списке только те элементы, которыми узел должен управлять, и не оставляйте в карточках значения, которые не должны уходить на панель при каждом сообщении.
4. Что на панели
Выход api - helper - 2 подключён к UI - Panel out. После ответа процессора кнопка «Звук» меняет вид: при value: false — зелёная «Звук включён», при value: true — обычная «Звук выключен». Если звук выключили другой панелью или с пульта процессора, кнопка поменяется так же, потому что вид ведёт не нажатие, а ответ.
Если у кнопки уже то же состояние, панели ничего не уходит, и вы ничего не увидите.
Как оператор меняет звук с панели — в блоке H «Первой программы»: кнопка — переключатель, программа получает value_changed и отправляет команду setMute, как в блоках E и F.
Пример 2. Ползунок и надпись: значение из ответа
Зачем. Громкость задают двигая ручку, но показывать надо то, что выставил процессор: ручка встаёт по ответу, а рядом надпись -20 дБ. А если ручку отпустил оператор, процессору нужна не доля 0…1, а децибелы. Здесь два направления, и в каждом работает узел change.
1. Что пришло от устройства
Тот же канал отладки, второй вид ответа (на снимке в примере 1 это сообщение под номером 2):
{"publishToken": "fpHallLevel", "value": -20, "valueType": "number", "type": "subscribeNotification"}
value — уровень в децибелах (дБ). Диапазон этого канала — от −60 до 0 дБ.
2. Разбор
Сообщение выходит из второго выхода switch «Какая подписка?» (правило «== fpHallLevel») и попадает в change «Уровень → ползунок и надпись»: одно правило, msg.topic, тип «выражение»:
{"Fp_Vol_sl": payload.value, "Fp_Vol_val_lb": $round(payload.value) & " дБ"}
Окно узла change «Уровень → ползунок и надпись»: 1 — «Установить» msg.topic с типом «выражение», 2 — выражение
По частям:
"Fp_Vol_sl": payload.value— ползунку отдаём уровень как есть, в дБ:-20. Пересчитывать в положение ручки не нужно — это сделаетapi - helper - 2(ниже)."Fp_Vol_val_lb":— надпись рядом с ползунком.$round(payload.value)— функция JSONata$roundокругляет число до целого: уровень, пришедший как-19.6, станет-20.& " дБ"— знак&склеивает строки (число перед этим превращается в строку). Получается"-20 дБ".
Один change готовит данные сразу для двух элементов: в msg.topic лежит {"Fp_Vol_sl": -20, "Fp_Vol_val_lb": "-20 дБ"}.
3. Окно api - helper - 2 «Громкость: ползунок и надпись»
В узле две карточки.
Карточка ползунка. «Элемент:» Fp_Vol_sl, «Событие:» «Числовое значение» (группа «Специальные»). Для этого события в карточке три поля:
Min —
-60: какое число соответствует нижнему краю ползунка;Max —
0: какое число соответствует верхнему краю;Steps —
60: на сколько шагов разбита шкала ползунка.
У пустых полей видны подсказки «Min (вход) — обязательно», «Max (вход) — обязательно» и «Steps (>=1, по умолчанию 100)»; когда вы впишете числа, подсказки пропадают, поэтому на снимке ниже видны только значения.
Поля Min и Max нужны: по ним узел пересчитывает число в положение ручки. Если поля оставить пустыми, при «Готово» окно узла впишет Min 0, Max 1 и Steps 100; тогда ползунок понимает только числа от 0 до 1. Если Min и Max равны, узел ползунок пропускает: ручка не двигается, а остальные элементы этого сообщения обновляются.
Карточка надписи. «Элемент:» Fp_Vol_val_lb, «Событие:» «Текст».
Карточки узла api - helper - 2 «Громкость: ползунок и надпись»: 1 — ползунок Fp_Vol_sl, «Числовое значение», 2 — поле Min (−60), 3 — поле Max (0), 4 — надпись Fp_Vol_val_lb, «Текст»
Зачем Min и Max и как узел пересчитывает. Панель принимает положение ручки как долю от 0 до 1: 0 — левый край, 1 — правый. Процессор же говорит в децибелах. Узел переводит одно в другое по вашим Min и Max:
положение = (значение − Min) / (Max − Min)
Для −20 дБ: (−20 − (−60)) / (0 − (−60)) = 40 / 60 ≈ 0,67 — ручка на две трети шкалы. Для −60 дБ получится 0 (край слева), для 0 дБ — 1 (край справа). Значение за пределами диапазона узел обрежет по краю. Steps округляет положение до ближайшего деления шкалы: при 60 шагах на диапазон в 60 дБ ручка стоит ровно на целом децибеле. Min и Max возьмите из свойств канала в самом устройстве (для процессора — его диапазон громкости), а не «на глаз»: иначе ручка и число разойдутся.
4. Что на панели
На странице «Устройства» ручка встаёт на две трети шкалы, надпись «Громкость:» показывает -20 дБ. Меняйте уровень любым другим способом: ручка и надпись последуют за ответом процессора.
Обратное направление: ручку отпустили → команда процессору
Оператор двигает ручку. Событие slide_end приходит, когда ручку отпустили; значение в нём — доля 0…1, как раз та, что панель использует внутри. Процессору нужен уровень в дБ, поэтому между ui - switch и device - command стоит ещё один change.
ui - switch. Правило на Fp_Vol_sl с событием slide_end, свой выход. У самого ползунка в UI-Designer поле «Отправлять команды после» стоит в положении «Отпускание» («Элементы интерфейса»). Событие slide_end выбрано не случайно: оно приходит один раз, когда ручку отпустили, и процессор получит одну команду, а не поток команд по ходу движения.
В отладке за ui - switch — сообщение с полями:
{"object": "Fp_Vol_sl", "event": "slide_end", "value": 0.25}
(0.25 — для примера: у вас будет то место, где оператор отпустил ручку.)
change «Громкость: 0…1 → дБ». Два правила «Установить»:
msg.command— «строка»setLevel;msg.parameters— тип «выражение»:
{"instanceTag": "DemoLevels", "channel": 1, "level": $round(payload.value * 60 - 60)}
Окно узла change «Громкость: 0…1 → дБ» (правило 1 — msg.command = строка setLevel): 1 — правило 2, msg.parameters с типом «выражение», 2 — выражение этого правила
instanceTagиchannel— адрес канала в процессоре; они остаются без изменений.payload.value * 60 - 60— обратный пересчёт: доля 0…1 умножается на ширину диапазона (60 дБ) и сдвигается на нижний край (−60). Доля 0,25 → −45 дБ, 0,9 → −6 дБ.$round(…)— округляет до целых децибел.
Это ровно та же формула, что делает api - helper - 2 по Min и Max, но в обратную сторону. Min и Max в карточке и числа 60 и −60 в этом выражении — один и тот же диапазон. Если вы смените диапазон в одном месте, поменяйте и в другом.
Выход change подключён к device - command «Звук: команда». После команды процессор присылает уведомление fpHallLevel, и ручка с надписью встают по факту: по тому уровню, который выставил процессор.
Отладка: 1 — событие slide_end за ui - switch (value — доля 0…1), 2 — msg.parameters за change «Громкость: 0…1 → дБ» (level — уровень в дБ)
Пример 3. Текст и цвет фона по состоянию звонка
Зачем. Показать оператору слова и цвета: «Идёт разговор» на зелёной плашке, «Нет звонка» — на белой. Текст и цвет приходят не из карточки, а из ответа кодека. Два свойства одного элемента меняются одним сообщением.
1. Что пришло от устройства
Кодек сам о звонке не сообщает, поэтому программа раз в 3 секунды спрашивает его командой getCallInfo (узел inject «Раз в 3 с» → device - command «Кодек: состояние звонка»). Ответ приходит в device - response - listener «Кодек: ответы», тип callInfo, на третий выход. В отладке (debug «Что прислал кодек») — два вида сообщения. Звонка нет:
{"inCall": false, "info": null, "value": false, "type": "callInfo"}
Идёт разговор:
{"inCall": true, "info": {"abonents": [{"name": "Филиал «Север»", "number": "2001"}], "time": 1}, "value": true, "type": "callInfo"}
Отладка «Что прислал кодек»: 1 — callInfo, звонка нет (inCall: false), 2 — callInfo, идёт разговор (inCall: true, в info — абонент), 3 — ответ contacts (массив list)
Нам нужно одно поле, inCall: true или false. Остальное (имя абонента, время) на этой странице не используется.
2. Разбор
Ответ сразу идёт в change «Звонок → текст и цвет»: проверять нечего, это единственный ответ на этом выходе. Правило «Установить» msg.topic, тип «выражение»:
{"Fp_Call_val_lb": {"text": payload.inCall ? "Идёт разговор" : "Нет звонка", "backgroundColor": payload.inCall ? "#DCFCE7" : "#FFFFFF"}}
Окно узла change «Звонок → текст и цвет»: 1 — выражение (правило «Установить» msg.topic, тип «выражение»)
По частям:
"Fp_Call_val_lb":— имя надписи-плашки.Внутри — вложенный объект:
"text": …и"backgroundColor": …. ИменаtextиbackgroundColor— это те же события «Текст» и «Цвет фона» в виде, который ждёт узел. С такой «полной записью» можно изменить сразу несколько свойств одного элемента.payload.inCall ? "Идёт разговор" : "Нет звонка"— условие, как в примере 1: если разговор идёт — одна строка, иначе другая.payload.inCall ? "#DCFCE7" : "#FFFFFF"— то же условие для цвета: светло-зелёный#DCFCE7при разговоре, белый#FFFFFFбез него. Цвет записывают как#DCFCE7илиRGB(220,252,231)— работают обе записи.
Результат в msg.topic при разговоре: {"Fp_Call_val_lb": {"text": "Идёт разговор", "backgroundColor": "#DCFCE7"}}.
3. Окно api - helper - 2 «Надпись: звонок»
Две карточки на один элемент Fp_Call_val_lb: событие «Текст» (группа «Текст и цвет») и событие «Цвет фона» (та же группа). Значения в карточках — запасные («Нет звонка» и #FFFFFF); данные из сообщения главнее.
Карточки узла api - helper - 2 «Надпись: звонок»: 1 — «Элемент:» Fp_Call_val_lb, «Событие:» «Текст», 2 — тот же элемент, «Событие:» «Цвет фона»
Если нужен цвет самого текста — событие «Цвет текста» (в полной записи — fontColor).
4. Что на панели
Плашка «Нет звонка» на белом фоне после звонка превращается в «Идёт разговор» на светло-зелёном; после завершения возвращается. Если сообщение придёт с тем же состоянием, панели ничего не уходит.
Страница «Устройства» во время звонка: 1 — «Идёт разговор» на светло-зелёном фоне, 2 — надпись «Кому звоним» с именем контакта, 3 — список контактов
Видимость
Событие «Видимость» (группа «Состояние»): значение true — скрыть, false — показать. Свойство элемента так и называется: hidden, поэтому true значит «скрыто». Данные: {"Fp_Call_val_lb": true}.
Пример 4. Список из ответа кодека и выбор строки
Зачем. Список (в UI-Designer — «ListBox») показывает перечень, из которого оператор выбирает строку: контакты, историю звонков, рецепты. Содержимое списка — это то, что прислало устройство.
1. Что пришло от устройства
Оператор нажал «Контакты» — программа послала кодеку команду getContacts. Ответ приходит в тот же device - response - listener «Кодек: ответы», тип contacts, на второй выход (на снимке отладки в примере 3 это сообщение под номером 3):
{"list": [{"id": 1, "name": "Переговорная 2", "number": "1002", "status": null, "type": "SIP"}, {"id": 2, "name": "Филиал «Север»", "number": "2001", "status": null, "type": "SIP"}, {"id": 3, "name": "Учебный класс", "number": "1003", "status": null, "type": "H323"}, {"id": 4, "name": "Дежурная служба", "number": "1100", "status": null, "type": "SIP"}], "value": 4, "type": "contacts"}
В list — массив контактов; у каждого есть name (имя) и number (номер), а остальное нам не нужно.
2. Разбор
Строка списка на панели — объект из одной пары «имя → значение», например {"Переговорная 2": "1002"}. Ключ — это то, что видит оператор, и то, что вернётся в программу при выборе строки. Весь список — массив таких пар. Значит, из ответа нужно сделать [{"Переговорная 2": "1002"}, {"Филиал «Север»": "2001"}, …].
change «Контакты → строки списка» делает это двумя правилами «Установить», обоим тип «выражение»:
msg.topic:{"Fp_Contacts_ls": [payload.list.{name: number}]}global.fpContacts:payload.list{name: number}
Окно узла change «Контакты → строки списка»: 1 — правило msg.topic (выражение), 2 — правило global.fpContacts (выражение)
Первое выражение:
payload.list— массив контактов из ответа;.{name: number}— для каждого контакта собрать объект «его имя: его номер». Получается по одной паре на контакт;[ … ]— квадратные скобки гарантируют, что результат будет массивом, даже если контакт один;{"Fp_Contacts_ls": … }— имя списка в интерфейсе.
Результат:
{"Fp_Contacts_ls": [{"Переговорная 2": "1002"}, {"Филиал «Север»": "2001"}, {"Учебный класс": "1003"}, {"Дежурная служба": "1100"}]}
Второе выражение, payload.list{name: number} (фигурные скобки сразу после list, без точки), собирает один объект со всеми парами сразу: {"Переговорная 2": "1002", "Филиал «Север»": "2001", …}. Его правило записывает в память программы (global.fpContacts): когда оператор выберет строку, программа достанет по имени номер для звонка. Память, ключи и подстановка — как в блоках A и C «Первой программы».
3. Окно api - helper - 2 «Список контактов»
Карточка: «Элемент:» Fp_Contacts_ls, «Событие:» «Список (JSON)» (группа «Списки»). В «Значении:» — JSON [] (пустой список, запасное значение).
Карточка узла api - helper - 2 «Список контактов»: 1 — «Элемент:» Fp_Contacts_ls, «Событие:» «Список (JSON)», «Значение:» — запасной пустой список
Каждое сообщение «Список (JSON)» заменяет весь список. Если вместо массива пришла строка с JSON, узел её разберёт; если пришло то, что нельзя разобрать как массив, список станет пустым.
4. Что на панели
Нажали «Контакты» — в списке появляются строки: имя слева, номер справа. Список и надпись «Кому звоним» видны на снимке страницы в примере 3 (пункты 3 и 2).
Выбор строки → надпись
Когда оператор выбирает строку, UI - Panel in получает событие item_selected, а в value — ключ выбранной строки (имя контакта — не номер и не позиция):
{"UI": {"Первая программа": {"object": "Fp_Contacts_ls", "event": "item_selected", "value": "Филиал «Север»"}}}
Боковая панель отладки: 1 — push кнопки, 2 — release той же кнопки, 3 — item_selected списка, в value — ключ выбранной строки
В ui - switch для этого — правило на Fp_Contacts_ls с событием item_selected (см. «Приём событий»). За ним — change «Строка → кому звоним» с двумя правилами «Установить»:
global.fpNumber— значение типаglobal.с ключомfpContacts[msg.payload.value]: из таблицы «имя → номер» берётся номер выбранного контакта и запоминается (кнопка «Позвонить» возьмёт его оттуда);msg.topic— «выражение»{"Fp_Target_val_lb": payload.value}: в надпись «Кому звоним» попадает имя контакта.
Дальше — api - helper - 2 «Надпись: кому звоним»: карточка Fp_Target_val_lb, событие «Текст».
Окно узла change «Строка → кому звоним»: 1 — правило global.fpNumber со значением fpContacts[msg.payload.value], 2 — правило msg.topic (выражение)
Выбрать строку из программы нельзя. В api - helper - 2 нет события «выбрать строку», и панель выбранную строку не подсвечивает. Поэтому показывайте выбор отдельной надписью, как здесь.
Другие действия со списком
Заполнение целиком — самое частое действие, но не единственное. Для остальных нужны другие события в карточке. Если один элемент нужно менять разными действиями, делайте для каждого отдельный узел api - helper - 2 с одной карточкой этого элемента: данные не спутаются.
Что нужно |
«Событие:» |
Что подать |
|---|---|---|
заполнить заново |
«Список (JSON)» |
|
очистить |
«Список (JSON)» |
|
добавить или заменить одну строку |
«Элемент списка» (в карточке поля «key» и «value») |
|
удалить строку |
«Удалить из списка» (поле «Item Key») |
|
Карточка строки списка: 1 — «Элемент:», 2 — «Событие:» «Элемент списка», 3 — поля «key» и «value»
Карточка удаления строки: 1 — «Элемент:», 2 — «Событие:» «Удалить из списка», 3 — поле «Item Key»
Ключи в одном списке должны быть разными: строка с уже существующим ключом заменит прежнюю.
Как проверить без устройства
Когда устройства под рукой нет или нужно проверить одну карточку, значение можно подать вручную: не из ответа, а из узла inject. Самая короткая цепочка — три узла: inject → api - helper - 2 → UI - Panel out.
Перетащите на рабочую область
inject,api - helper - 2иUI - Panel outи соедините по порядку. ЕслиUI - Panel outна вкладке уже есть, берите его.Откройте
inject. Дляmsg.payloadвыберите тип «JSON» и впишите данные: например,{"Fp_Mute_b": "pressed"}.Откройте
api - helper - 2. Выберите интерфейс, «Тип сообщения» —uiState, в «Источнике входных данных» вместоtopicвпишитеpayload, чтобы узел читал данные изmsg.payload.Добавьте карточку элемента (как в примерах выше).
Нажмите «Развернуть», затем кнопку слева от узла
inject.
Проверочная цепочка: 1 — inject с данными, 2 — api - helper - 2, 3 — UI - Panel out
Что вы увидите: на открытой панели элемент сразу меняется. Не меняется — раздел «Частые ошибки» в конце страницы.
Вручную проверяется только окно api - helper - 2. Чтобы проверить весь путь «ответ → разбор → панель», проверьте по очереди: приходит ли ответ в отладку (debug за device - response - listener), что лежит в msg.topic после change и что показывает панель.
Что можно изменить: коротко
События, которые вы выбираете в карточке («Событие:»). Значение подаётся в {"имя элемента": значение}.
Что менять |
«Событие:» |
Значение в данных |
|---|---|---|
вид кнопки |
«Состояние кнопки» |
|
текст (надпись или подпись кнопки) |
«Текст» |
строка |
цвет текста, цвет фона |
«Цвет текста», «Цвет фона» |
|
показать или скрыть |
«Видимость» |
|
положение ползунка |
«Числовое значение» |
число из диапазона Min…Max карточки |
строки списка |
«Список (JSON)», «Элемент списка», «Удалить из списка» |
см. таблицу выше |
оверлей во фрейме |
«Overlay» |
см. ниже |
положение и размер элемента |
«X», «Y», «Ширина», «Высота» (группа «Позиция (пиксели)») или «X %», «Y %», «Ширина %», «Высота %» (группа «Позиция (проценты)») |
число: в пикселях — от левого верхнего угла страницы или оверлея, на котором лежит элемент; у «%» — доля от 0 до 1 от размера страницы или оверлея (0,5 — половина), а не проценты. Для одного элемента берите одну группу — пиксели или «%» |
адрес и перезагрузка веб-элемента (Web URL) |
«URL (WebView)», «Перезагрузка (WebView)» |
адрес строкой; |
вид кнопки по состояниям |
«Расширенная кнопка» |
см. ниже |
Особенности кнопки:
Кнопка в группе Interlock. Если группа задана в UI-Designer и кнопке пришло
selected, остальные кнопки группы сами уходят вdefault. Состояниеdefaultснимает выбор только с этой кнопки. Подробнее про группы — «Переключатели и группы».Состояние
disabled. Кнопка выглядит неактивной (серая клавиша и серый текст) и не реагирует на касания: программа не получает от неё ни одного события, пока ей не вернут другое состояние.Тип обратной связи кнопки. Если в UI-Designer у кнопки «Тип обратной связи» — «Momentary Passed» или «None», она игнорирует команды программы (см. «Кнопки и состояния»).
Расширенная кнопка
Событие «Состояние кнопки» переключает кнопку между готовыми видами. Когда нужно изменить сам вид какого-то состояния (например, подпись и цвет в состоянии selected), выберите событие «Расширенная кнопка» (группа «Специальные»). Оно работает для кнопок типа «расширенная кнопка»; в списке элементов узла они собраны в группе «Расширенные кнопки». В карточке у него вместо одного поля три: какое свойство менять (backgroundColor, text, fontColor, icon, iconColor), для какого состояния (defaultState, selectedState, pressedState, disabledState) и значение. Если нужно изменить несколько свойств или состояний, добавьте карточку на каждое.
В данных то же задаётся вложенной записью: ключи — состояния, внутри — свойства.
{"Fp_Mute_b": {"defaultState": {"text": "ВЫКЛ", "backgroundColor": "#333"}, "selectedState": {"text": "ВКЛ", "fontColor": "#fff"}}}
Переход на другую страницу из программы
Зачем. Обычно страницы переключает оператор — кнопкой-ссылкой, которую вы настроили в UI-Designer. Но бывает, что страницу должна открыть программа: например, показать страницу с подсказкой или с ошибкой по событию устройства. Для этого служит тип «Тип сообщения» → navigation.
Ограничение: переход работает только со страницами интерфейса и только по имени страницы. Оверлей во фрейме открывается другим способом — см. ниже «Сменить оверлей во фрейме» (про фреймы — «Фреймы»).
Шаги
В UI-Designer создайте в интерфейсе вторую страницу (например, «Подсказка»); сохраните и опубликуйте интерфейс. Кнопку «Закрыть» на ней можно сделать ссылкой на главную страницу средствами UI-Designer: для возврата программа не нужна.
В U-Logic перетащите
api - helper - 2и соедините с ним узел, который запускает переход (например,ui - switchна кнопку «Открыть подсказку», событиеpush).Откройте
api - helper - 2. В «Интерфейс (UI)» выберите интерфейс, а в «Тип сообщения» —navigation. Ниже «Объектов управления» появятся поля «Поиск:» и «Страница:»: начните вводить имя страницы в поиске и выберите её в списке «Страница:».Нажмите «Готово». Подключите выход узла к
UI - Panel outи нажмите «Развернуть».
Окно узла api - helper - 2 «Перейти: Подсказка»: 1 — «Интерфейс (UI)», 2 — «Тип сообщения» navigation, 3 — «Страница:» «Подсказка»
Что вы увидите: когда сообщение дошло до узла, на панели вместо текущей страницы открывается «Подсказка». Входные данные для этого типа не нужны: узел использует страницу из настроек узла, а запускает его любое сообщение; только не кладите объект в msg.topic (см. «Частые ошибки»). Пример целиком — в «Первой программе», блок G.
Сменить оверлей во фрейме
Зачем. Фрейм в интерфейсе показывает оверлей-страницу поверх основной. Обычно оверлей показывает оператор, но программа тоже может его сменить или убрать: например, показать окно с предупреждением по событию устройства.
Здесь работает не navigation, а тот же тип «Тип сообщения» — uiState, что и для кнопок и надписей: оверлей задаётся событием «Overlay» (в списке событий — группа «Специальные»).
Шаги
В UI-Designer должны быть фрейм и оверлей-страница, которую он показывает; интерфейс сохранён и опубликован.
В U-Logic перетащите
api - helper - 2и соедините с ним узел, который запускает смену (например,ui - switchна кнопку, событиеpush).Откройте
api - helper - 2. В «Интерфейс (UI)» выберите интерфейс, «Тип сообщения» —uiState. Добавьте элемент в «Объекты управления» и задайте: в «Элемент:» выберите фрейм, в «Событие:» — «Overlay».В поле «Значение:» выберите оверлей, который нужно показать, либо пункт снятия оверлея — тогда оверлей скроется. В новой карточке этот пункт называется «Скрыть оверлей» и выбран по умолчанию; когда вы откроете окно снова, у сохранённой карточки он будет подписан «Убрать оверлей»; это одно и то же. Нажмите «Готово».
Подключите выход узла к
UI - Panel outи нажмите «Развернуть».
Окно узла api - helper - 2: 1 — «Событие:» Overlay, 2 — «Элемент:» — фрейм, 3 — «Значение:» — оверлей
Что вы увидите. Когда сообщение дошло до узла, во фрейме на панели появляется выбранный оверлей; со значением «Убрать оверлей» он скрывается.
Частые ошибки
Ничего не меняется на панели. Проверьте по порядку: выход
api - helper - 2подключён кUI - Panel out; выбран интерфейс; «Источник входных данных» указывает на то поле, кудаchangeположил данные (msg.topicпо умолчанию); имя элемента в данных совпадает с именем в UI-Designer до буквы; интерфейс сохранён и опубликован. Включитеdebug(«весь msg») заchangeи посмотрите, что лежит вmsg.topic.В
msg.topicпусто илиundefined. Выражение вchangeне нашло поле в ответе: сверьте имена полей (payload.value,payload.inCall,payload.list) с тем, что пришло в отладке.Узел игнорирует ключ. В короткой записи (
{"Fp_Mute_b": "pressed"}) узел берёт только элементы из своего списка «Объекты управления». Для элемента без карточки подайте полную запись{"Fp_Mute_b": {"uiState": "pressed"}}.Кнопка сама возвращается в
default. В списке узла осталась карточка этой кнопки со значениемdefault: оно уходит с каждым сообщением, которое кнопку не упоминает. Уберите карточку или замените её нужным значением.Ползунок не двигается. Если Min и Max в карточке «Числовое значение» равны, узел пропускает ползунок, а остальное из сообщения уходит. С включённым в узле флажком «Debug» в отладке видно предупреждение «некорректные min/max» с именем ползунка. Если Min и Max не заполняли, узел подставил 0 и 1: значения вне этого диапазона ставят ручку в край. Значение должно быть числом.
Ручка стоит не там. Min и Max в карточке не совпадают с диапазоном устройства: узел считает долю по вашим числам.
Ползунок отправляет команды сыпью. В правиле
ui - switchвыбраноvalue_changedвместоslide_end.Переход на страницу не срабатывает. Страница выбрана в узле, но интерфейс не сохранён и не опубликован после её создания; выбран не тот интерфейс; в
msg.topicперед узлом лежит объект (не кладите туда ничего). Оверлей и окно фрейма так не открыть: для них служит событие «Overlay» (см. выше).Список заменился, а нужно было добавить. «Список (JSON)» заменяет весь список; для одной строки берите «Элемент списка».
Строки списка выглядят не так, как ждали. Строка — объект из одной пары «ключ → значение». Запись
[{"key": "A", "value": "1"}]панель покажет как одну строку с ключомkey.Градиент в цвете списка. Панель не разбирает градиент в цвете строк и показывает ошибку вместо вкладки; задайте в UI-Designer сплошной цвет («Элементы интерфейса»).