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

Назовём подсистему "Линейная функция", на вход подадим текущее время симуляции, а выход запишем и добавим в модуль "Визуализация сигналов":
.png)
Если мы попытаемся запустить эту модель, то конечно же увидим ошибку симуляции. Ведь переменные k и b не определены в рабочей области.
Маскирование подсистемы
Вместо того чтобы присваивать их в командной строке, в скрипте или в обратных вызовах модели, давайте кликнем правой кнопкой мыши по подсистеме и в разделе "Маска" нажмём "Добавить маску".
.png)
В результате в новом окне браузера откроется инструмент для настройки маски - "Редактор масок". Он состоит из редактора интерфейса и редактора кода.
Редактор интерфейса позволяет добавлять в окно настроек блока различные элементы управления, структурные элементы и действия.
.png)
По умолчанию в редакторе интерфейса создана вкладка с названием "Main tab" и секция для скрытия "Main group".
Вы можете переименовать их:
-
Либо два раза кликнуть по названию вкладки, изменить его и нажать клавишу Enter.
-
Либо выделить секцию и в панели "Настройки" изменить параметр "Название секции".
Нажатие на кнопку "+" приведёт к созданию ещё одной вкладки.
Добавление элементов управления
К элементам управления относятся:
-
Поля ввода;
-
Чекбоксы;
-
Выпадающие списки.
Вы можете перетягивать элементы из панели "Библиотека" в окно настроек точно также как делаете это при добавлении блоков на холст.
Если какой-то элемент нужно удалить, выделите его и нажмите клавишу Delete.
Если выделить элемент управления, например "поле ввода", на панели "Настройки" можно изменить его параметры.
Имя параметра - это название переменной, к которой вы обращаетесь в блоке. В нашем случае таких переменных две - k и b.
Зададим имя первого параметра - напишем k, изменим "Название поля" на "Угловой коэффициент" и определим значение по умолчанию равным 5.
.png)
Добавим ещё одно поле ввода. Имя параметра зададим как b, укажем, что это свободный член и определим значение по умолчанию:
.png)
Если теперь запустить симуляцию, то она завершится без ошибок, несмотря на отсутствие переменных k и b в рабочей области, ведь теперь они определены в маске.
Вы, в свою очередь, можете легко настраивать значения параметров, ведь для этого не придётся открывать командную строку или переходить в подсистему.
Обратные вызовы маски
После нажатия на вкладку "Редактор кода", откроется редактор обратных вызовов маски:
.png)
Обратные вызовы подразделяются на глобальные и локальные.
Глобальные обратные вызовы относятся ко всей маске:
iconDrawCallback- вызывается, когда нужно перерисовать иконку блока на основе актуальных значений параметров.blockChangedCallback- выполняется после того как изменился один или несколько параметров маски.
.png)
Локальные обратные вызовы привязаны к конкретному параметру маски, и срабатывают после того, как его значение изменится.
Выберем параметр k на панели слева и увидим, что можем задать две локальных функции обратного вызова:
valueChangedCallback- выполняется при изменении значения параметра;validateCallback- осуществляет валидацию параметра (т. е. проверяет корректность введённого значения).
.png)
Валидация параметров
Обратный вызов validateCallback обязательно должен начинаться с макроса @assert. Вы можете указать после него логическое выражение и текст ошибки. Например, сравнить значение параметра с нулём:
.png)
@assert value > 0 "Значение должно быть больше нуля"
Если теперь попытаться изменить значение углового коэффициента на отрицательное, будет выведена ошибка:
.png)
Сокрытие параметров
Давайте удалим валидацию и в редакторе интерфейса добавим ещё один элемент управления - чекбокс. Назовём переменную is_direct, в названии напишем "Прямая пропорциональность", и укажем, что чекбокс по умолчанию должен быть активирован.
.png)
Вернёмся в редактор кода и напишем функцию обратного вызова. При изменении значения чекбокса будем либо скрывать параметр b из маски, либо показывать его.
Для этого обратимся к специальному объекту mask.parameters, в котором хранятся параметры маски. Нас интересует параметр b, так что запишем его имя после точки.
Если бы мы хотели изменить значение b, то нужно было бы обратиться к свойству value. Например, мы могли бы написать mask.parameters.b.value = 42. После чего при каждом изменении состояния чекбокса, параметру b присваивалось бы указанное значение:
.png)
mask.parameters.b.value = 42
Но мы хотим не присваивать значение, а скрывать параметр из маски. Поэтому должны обратиться к свойству hidden и присвоить ему логическое значение. Если чекбокс is_direct принимает значение true, параметр b не должен отображаться:
.png)
mask.parameters.b.hidden = is_direct
Сохраним маску и убедимся, что теперь отображение свободного члена зависит от значения чекбокса. Но если мы запустим модель, то увидим, что параметр b просто пропадает из маски, но его значение продолжает учитываться во время симуляции.
Давайте это исправим:
-
Определим переменную с именем
constant_pathи сохраним в неё путь до блока "Константа". -
А также запишем следующее условие. Если чекбокс активен, установим значение константы равным нулю. В противном случае присвоим ему параметр
b.
.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
Этот пример, с одной стороны, показывает, что вы можете использовать в обратных вызовах маски методы программного управления. А с другой - демонстрирует один из способов применения атрибута "Скрытый".
.png)
Сохраним маску и убедимся, что теперь при активации чекбокса значение параметра b не оказывает влияния на результат симуляции. А при деактивации чекбокса, параметр "Свободный член" сохранит последнее введённое значение.
.png)
Настройка внешнего вида
И напоследок я хотел бы показать, как можно использовать обратный вызов iconDrawCallback. Для настройки внешнего вида маски используйте функцию engee.show.
В документации вы найдёте множество примеров настройки внешнего вида блока - можно вывести текст, формулы LaTeX, графики и изображения. Кроме того можно настроить горизонтальное и вертикальное выравнивание, вывести на блок несколько слоёв изображений, а также изменить подписи портов.
Давайте выведем на блок строку y = kx + b и подставим в неё значения параметров. Значение свободного члена будем отображать, только если чекбокс "Прямая пропорциональность" деактивирован:
.png)
text = "y = $(k)x"
if !is_direct
text = text * " + $(b)"
end
engee.show(text)
Сохраним маску и убедимся, что иконка блока обновляется при изменении параметров:
.png)
.png)
Вывод
В данном примере мы рассмотрели маскирование блоков, а также познакомились с различными типами обратных вызовов - научились валидировать параметры, скрывать их и настраивать внешний вид блока.