Документация Engee
Notebook

Обратные вызовы в масках

Данный пример посвящён использованию обратных вызовов в маскированных блоках.

Маски в среде моделирования

Маска - это настраиваемый пользовательский интерфейс, упрощающий использование блока, а также его переиспользование. У маскированного блока есть собственное окно настроек, в котором можно изменять различные параметры.

С помощью маски можно:

  • Создать окно настроек для быстрого изменения параметров подсистемы или блока.

  • Скрыть содержимое подсистемы и защитить её от случайных изменений.

  • Изменить внешний вид блока, настроив его иконку.

Кроме того, маски очень часто используются в связке с пользовательскими библиотеками.

Создание подсистемы

Давайте создадим подсистему, перейдём в неё и добавим три блока - "Коэффициент усиления", "Сложение" и "Константа". Входы назовём x и y, умножим входной сигнал на коэффициент k и прибавим к нему константу b:

image.png

Назовём подсистему "Линейная функция", на вход подадим текущее время симуляции, а выход запишем и добавим в модуль "Визуализация сигналов":

image.png

Если мы попытаемся запустить эту модель, то конечно же увидим ошибку симуляции. Ведь переменные k и b не определены в рабочей области.

Маскирование подсистемы

Вместо того чтобы присваивать их в командной строке, в скрипте или в обратных вызовах модели, давайте кликнем правой кнопкой мыши по подсистеме и в разделе "Маска" нажмём "Добавить маску".

image.png

В результате в новом окне браузера откроется инструмент для настройки маски - "Редактор масок". Он состоит из редактора интерфейса и редактора кода.

Редактор интерфейса позволяет добавлять в окно настроек блока различные элементы управления, структурные элементы и действия.

image.png

По умолчанию в редакторе интерфейса создана вкладка с названием "Main tab" и секция для скрытия "Main group".

Вы можете переименовать их:

  • Либо два раза кликнуть по названию вкладки, изменить его и нажать клавишу Enter.

  • Либо выделить секцию и в панели "Настройки" изменить параметр "Название секции".

Нажатие на кнопку "+" приведёт к созданию ещё одной вкладки.

Добавление элементов управления

К элементам управления относятся:

  • Поля ввода;

  • Чекбоксы;

  • Выпадающие списки.

Вы можете перетягивать элементы из панели "Библиотека" в окно настроек точно также как делаете это при добавлении блоков на холст.

Если какой-то элемент нужно удалить, выделите его и нажмите клавишу Delete.

Если выделить элемент управления, например "поле ввода", на панели "Настройки" можно изменить его параметры.

Имя параметра - это название переменной, к которой вы обращаетесь в блоке. В нашем случае таких переменных две - k и b.

Зададим имя первого параметра - напишем k, изменим "Название поля" на "Угловой коэффициент" и определим значение по умолчанию равным 5.

image.png

Добавим ещё одно поле ввода. Имя параметра зададим как b, укажем, что это свободный член и определим значение по умолчанию:

image.png

Если теперь запустить симуляцию, то она завершится без ошибок, несмотря на отсутствие переменных k и b в рабочей области, ведь теперь они определены в маске.

Вы, в свою очередь, можете легко настраивать значения параметров, ведь для этого не придётся открывать командную строку или переходить в подсистему.

Обратные вызовы маски

После нажатия на вкладку "Редактор кода", откроется редактор обратных вызовов маски:

image.png

Обратные вызовы подразделяются на глобальные и локальные.

Глобальные обратные вызовы относятся ко всей маске:

  • iconDrawCallback - вызывается, когда нужно перерисовать иконку блока на основе актуальных значений параметров.
  • blockChangedCallback - выполняется после того как изменился один или несколько параметров маски.
image.png

Локальные обратные вызовы привязаны к конкретному параметру маски, и срабатывают после того, как его значение изменится.

Выберем параметр k на панели слева и увидим, что можем задать две локальных функции обратного вызова:

  • valueChangedCallback - выполняется при изменении значения параметра;
  • validateCallback - осуществляет валидацию параметра (т. е. проверяет корректность введённого значения).
image.png

Валидация параметров

Обратный вызов validateCallback обязательно должен начинаться с макроса @assert. Вы можете указать после него логическое выражение и текст ошибки. Например, сравнить значение параметра с нулём:

image.png
@assert value > 0 "Значение должно быть больше нуля"

Если теперь попытаться изменить значение углового коэффициента на отрицательное, будет выведена ошибка:

image.png

Сокрытие параметров

Давайте удалим валидацию и в редакторе интерфейса добавим ещё один элемент управления - чекбокс. Назовём переменную is_direct, в названии напишем "Прямая пропорциональность", и укажем, что чекбокс по умолчанию должен быть активирован.

image.png

Вернёмся в редактор кода и напишем функцию обратного вызова. При изменении значения чекбокса будем либо скрывать параметр b из маски, либо показывать его.

Для этого обратимся к специальному объекту mask.parameters, в котором хранятся параметры маски. Нас интересует параметр b, так что запишем его имя после точки.

Если бы мы хотели изменить значение b, то нужно было бы обратиться к свойству value. Например, мы могли бы написать mask.parameters.b.value = 42. После чего при каждом изменении состояния чекбокса, параметру b присваивалось бы указанное значение:

image.png
mask.parameters.b.value = 42

Но мы хотим не присваивать значение, а скрывать параметр из маски. Поэтому должны обратиться к свойству hidden и присвоить ему логическое значение. Если чекбокс is_direct принимает значение true, параметр b не должен отображаться:

image.png
mask.parameters.b.hidden = is_direct

Сохраним маску и убедимся, что теперь отображение свободного члена зависит от значения чекбокса. Но если мы запустим модель, то увидим, что параметр b просто пропадает из маски, но его значение продолжает учитываться во время симуляции.

Давайте это исправим:

  1. Определим переменную с именем constant_path и сохраним в неё путь до блока "Константа".

  2. А также запишем следующее условие. Если чекбокс активен, установим значение константы равным нулю. В противном случае присвоим ему параметр b.

image.png
mask.parameters.b.hidden = is_direct

constant_path = joinpath(engee.gcb(), "Константа")

if is_direct
    engee.set_param!(constant_path, "Value" => "0.0")
else
    engee.set_param!(constant_path, "Value" => "b")
end

Этот пример, с одной стороны, показывает, что вы можете использовать в обратных вызовах маски методы программного управления. А с другой - демонстрирует один из способов применения атрибута "Скрытый".

image.png

Сохраним маску и убедимся, что теперь при активации чекбокса значение параметра b не оказывает влияния на результат симуляции. А при деактивации чекбокса, параметр "Свободный член" сохранит последнее введённое значение.

image.png

Настройка внешнего вида

И напоследок я хотел бы показать, как можно использовать обратный вызов iconDrawCallback. Для настройки внешнего вида маски используйте функцию engee.show.

В документации вы найдёте множество примеров настройки внешнего вида блока - можно вывести текст, формулы LaTeX, графики и изображения. Кроме того можно настроить горизонтальное и вертикальное выравнивание, вывести на блок несколько слоёв изображений, а также изменить подписи портов.

Давайте выведем на блок строку y = kx + b и подставим в неё значения параметров. Значение свободного члена будем отображать, только если чекбокс "Прямая пропорциональность" деактивирован:

image.png
text = "y = $(k)x"

if !is_direct
    text = text * " + $(b)"
end

engee.show(text)

Сохраним маску и убедимся, что иконка блока обновляется при изменении параметров:

image.png
image.png

Вывод

В данном примере мы рассмотрели маскирование блоков, а также познакомились с различными типами обратных вызовов - научились валидировать параметры, скрывать их и настраивать внешний вид блока.