.. SimpleUI documentation master file, created by
sphinx-quickstart on Sat May 16 14:23:51 2020.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Экраны
===========================================
Экраны, общее
------------------
Экраны нужны для отрисовки визуальных элементов. По большей части визуальные элементы располагаются в контейнерах на экране и также есть элементы самого экрана.
Процессы – это просто набор экранов. Вся логика сосредоточена в экранах – обработчики, активные элементы и т.д.
Размещенные на экране элементы заполняются либо из констант либо из переменных стека либо из слайсов. Например вы разместили на экране кнопку. У нее есть Значение (Value), например «Записать»
Это выглядит так в конструкторе и на форме
.. image:: _static/2025_screen_1.png
:scale: 65%
:align: center
Но можно определить значение как @btn_caption, предварительно записав в переменную btn_caption значение «Записать Документ №1»
.. image:: _static/2025_screen_3.png
:scale: 75%
:align: center
Тогда при отрисовке, будет так
.. image:: _static/2025_screen_4.png
:scale: 70%
:align: center
Когда запускается процесс, всегда запускается первый в списке экран процесса. У экрана при запуске происходит отрисовка и выполнение 2х событий друг за другом - onStart и onPostStart.
Вообще видов событий у экрана всего 3:
* **onStart** – событие при запуске, но до начала отрисовки. Сюда можно поместить обработчик, который заполнит переменные экрана, связанные с визуальными элементами. Надо иметь ввиду такой нюанс: если обработчик быстрый, то можно использовать тип выполнения run. А если долгий, то runasync или runprogress (иначе открытие экрана будет зависать, что неэстетично и может привлечь внимание ОС). При этом, если вы используете асинхронный обработчик, то следует понимать, что он закончится, когда экран уже отрисован, и чтобы появились визуальные элементы, которые вы заполняли в таком обработчике (например вы заполняли большой список) нужно перерисовать экран командой RefreshScreen. В общем onStart в основном используется для заполнения визуальных элементов и инициализации переменных.
* **onPostStart** событие после отрисовки элементов. В некотрых случаях нужно обработься к элементу когда он уже размещен на экране
* **onInput** – любые события ввода: нажатия на кнопку, чтение штрихкода, выбор меню и т.д. За редким исключением, событие ввода влечет за собой **перерисовку экрана**. Соотвественно после onInput будут пересозданы элементы и запустятся обработчики onStart и onPostStart.
Как видно все многообразие событий ввода собрано в onInput, поэтому люое событие ввода имеет еще признак listener чтобы их можно было разделять.
Команды управления экранами и процессами
---------------------------------------------
**ShowScren, <имя экрана>** – переключает на другой экран в процессе. Т.е. если в процессе есть Экран1 и Экран2, то ShowScreen, Экран2 вызовет запуск Экран2 с соответствующими событиями onStart, onPostStart.
Пример (тут и далее примеры команд пишутся для python, если у вас другие обработчики, переводите их под свой стек)
.. code-block:: Python
hashMap.put("ShowScreen","Экран 2");
**ShowScreen,<ИмяПроцесса>|<ИмяЭкрана>** - команда заимствования экрана из любого процесса (не обязательно текущего). Хороша тем, что работает без перезапуска процесса, в отличии от StartProcess (а перезапуск довольно затратный процесс, при котром происходит инициализация оборудования и другие длительные вещи)
.. code-block:: Python
hashMap.put("ShowScreen","Общие формы|Экран 2");
**ResreshScreen, без параметра** – обновление (перерисовка экрана) без вызова onStart/onPostStart. Нужна для того, чтобы перерисовать элементы из заполненных переменных. Обязательно использовать с любым асинхроном. Также, см. далее команду UpdateLayout для частичного апдейта выбранного контейнера.
**RestartScreen, без параметров** – перезапуск экрана, с выполнением onStart/onPostStart
**StartProcess, <имя процесса>** – запуск процесса из процесса
**ShowProcessScreen, <имя процесса>** – запуск процесса из фона (когда ни один процесс не запущен)
**FinishProcess, без параметра** – завершение процесса
Общие функции экранов
--------------------------
Таймер экрана
~~~~~~~~~~~~~~~~~~
На экране можно определить таймер, который будет периодически генерировать событие ввода (частота таймера задается в общих настройках). Данная функция была введена до того, как в платформе появились асинхронные обработчики. Большинство сценариев для которых нужен таймер гораздо более эффективно реализуются на асинхроне и системе не нужно постоянно дергать экран, более того это еще и более быстрая реакция. Поэтому прежде чем использовать таймер, рекомендуется посмотреть в сторону асинхронных вызовов экранов или сервиса событий.
Скрыть верхнюю панель
~~~~~~~~~~~~~~~~~~~~~~~~
Скрывает тулбар в экране. Если предусмотрен поиск в тулбаре или меню, то лучше того не делать
Нижняя панель и свойство Скрыть нижнюю панель
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
В SimpleUI ввиду совместимости на экране по умолчанию присутствует панель с кнопками Вперед (listener- пустая строка), Назад и План-факт. Это устаревший рудимент и рекомендуется отключать его галкой «Скрыть нижнюю панель»
Отключить прокрутку корневого контейнера
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Все элементы экрана по умолчанию выводятся в бесконечный прокручиваемый по вертикали контейнер. Но в случае например списков (которые сами имею свою прокрутку) это создает некорректную ситуацию. Например нельзя разместить список «на весь экран» если этот экран – бесконечный. Значит нужно его ограничить(зафиксировать). Для этого существует опция Отключить прокрутку корневого контейнера.
Закрывать без вопроса
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
По умолчанию при закрытии экрана/процесса кнопкой назад (системной) пользователю задается вопрос. Этой галочкой можно отключить данный диалог.
Подключить обработчик клавиатуры
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
При включенном флаге, когда происходит нажатие одного из сочетаний клавиш генерируется событие listener= keyboard и в переменную keyboard возвращается считанная клавиша.
Список клавиш такой (в обычном режиме):
* сочетания с Ctrl
* сочетания с Alt
* сочетания с Shift
* F1-F12
Также можно в настройках приложения установить галку **«Перехватывать все клавиши»** тогда будут возвращаться абсолютно все клавиши причем еще в виде 2х событий - нажатие и отпускание. Важно помнить - в таком режиме коды клавиш пишутся в с префиксами #up и #down - это нужно учитывать в обработчиках.
Для того, чтобы понять какие коды у клавиш можно воспользоваться пунктом главного меню «Тест клавиатуры»
Элементы экрана
-----------------------
Далее перечисленные все актуальные элементы экрана (не упомянутые элементы оставлены для совместимости со старыми конфигурациями)
* **Контейнер** – элемент разметки и контейнер для других визуальных элементов. Подробнее в разделе «Разметка экрана контейнерами»
* **Штрихкод** – подключение к экрану обработчика чтения штрихкодов. Штрихкоды могут считываться через подключенное оборудование (подробнее в разделе Оборудование) либо через камеру. Если в экране подключен элемент штрихкод, то на экране появляется плавающая кнопка «Штрихкод», которая запускает считывание камерой. Если эта кнопка не нужна, ее можно скрыть в общих настройках приложения «Аппаратный сканер». Также штрихкоды могут считываться ActiveCV (описано в разделе ActiveCV) в более расширенном виде. Этот вариант (в случае с камерой) просто возвращает 1 штрикход на один запуск (нет потокового сканирования). В элменте нужно определить Переменную куда будет возвращаться штрихкод. При считывании (без разницы камерой или оборудованием) генерируется событие listener=barcode и в переменную Штрихкода пишется считанный штрихкод
* **Голос** Запускается распознавание голоса. У элемента надо определить Переменную, куда будет возвращен результат. В случае успеха возникает событие listener=voice и в переменную помещается результат. Также возможно запускать распознавание из кода, см в разделе Голос и синтез речи.
* **Подпись** Ввод подписи с экрана. Нужно определить переменную куда запишется base64-картинка подписи. При успешном вводе подписи генерируется событие listener=signature
* **Фото камерой**, **Фото из галереи**, **Горизонтальная галерея мультимедиа** и **Галерея слайдер** Подробнее об этих элементах написано в разделе Работа с мультимедиа
* **Элемент меню** Можно добавить элемент в меню опций (в тулбаре). У элемента нужно определить Значение – название пункта меню и Переменную – она будет возвращена в listener при выборе пункта меню. Причем если значение задать в виде иконки Awesome (см. пункт Awesome) то такой пункт меню будет в тулбаре
* **Плавающая кнопка** Можно размещать свои кнопки поверх экрана справа снизу. У элемента нужно определить Переменную и Значение. В Значении можно либо написать имя одной из предопределенных иконок либо использовать Awesome-иконку. Предопределённые: ``"forward","backward","run","cancel","edit","picture","info","settings","plus","save","search","send","done"``. Awesome описаны в разделе Awesome-иконки ниже. Ввиду того, что иконки генерируемые, они имеют разные пропорции. Поэтому именно в Плавающей кнопке желательно использовать сдвиги по x и y. Например, вот так определяется иконка «звездочка» но с сдвигом по X- 0, а по Y - -15: #f005;0;-15. Если не использовать сдвиг по y, то звездочка съезжает вниз.
* **NFC** Подключение считывания NFC. Описано в разделе NFC.
Разметка контейнерами
-----------------------
Высота, ширина, вес
~~~~~~~~~~~~~~~~~~~~~~~
Визуальные элементы находятся внутри контейнеров. В экране должен быть хотя бы один контейнер (корневой) в котором размещаются элементы, в т.ч. другие контейнеры. Контейнеры могут иметь **горизонтальную** и **вертикальную** ориентацию (свойство Ориентация(ключ orientation))
**Высота**("height") и **ширина**("width") контейнера может быть:
* **«На всю ширину»** (match_parent) – контейнер занимает по выбранной оси все пространство.
* **«По размеру элементов»** (wrap_content) – размер определяется соответствующим максимальным размером вложенных элементов
* **Определенную вручную** – числовое значение в относительных экранных единицах
Если мы хотим разбить экран на зоны (пополам или в других пропорциях) по вертикали, то прежде всего нужно **Отключить прокрутку корневого контейнера**. Т.е. мы работаем не в бесконечном прокручиваемом экране, а в рамках одного экрана с конечной высотой и шириной.
И контейнеры, и элементы внутри них подчиняются одним и тем же правилам размещения.
Если нужно распределить несколько элементов в рамках контейнера пропорционально ширине или длине, то нужно выполнить следующее (пример для распределения горизонтально, для вертикального распределения действует аналогичное правило):
1) Элементы должны быть включены в горизонтальный контейнер (type: LinearLayout, orientation:horizontal), с шириной match_parent
2) у элементов внутри должна быть ширина= 0
3) у элементов должен быть вес (ключ weight) в тех пропорциях, в которых нужно распределить элементы на экране.
Например, еcли два элемента должны делить ширину пополам, то у обоих должен быть вес 1, если один должен быть в два раза шире то у него должен быть вес 2, а у другого – 1. Т.е. вес это пропорция или вес элемента в рамках контейнера по оси.
.. image:: _static/2025_screen_5.png
:scale: 75%
:align: center
Еще один вариант часто встречающейся разметки: *нужно растянуть элемент, но оставить место для элементов сверху и снизу. Например, у вас сверху несколько элементов, а снизу вы хотите разместить блок кнопок. Между ними пространство может быть пустое, либо занято списком, как вариант.*
.. image:: _static/2025_screen_6.png
:scale: 75%
:align: center
.. warning:: Важно! Если вы что то хотите растягивать по верстикали - обязательно отключите прокрутку корневого контейнера!
Для этого элементы сверху имеют высоту по размеру элементов(wrap_content), снизу – тоже по размеру элементов, а элемент посередине имеет **высоту("height")=0 и вес(weight)=1**
Два вышеприведенных примера тут: https://disk.yandex.ru/d/JOJh0OtV1aAdig
Раздел конфигурации Контейнеры
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. image:: _static/2025_screen_7.png
:scale: 70%
:align: center
Контейнеры используются в экранах, в макетах элементов списка, диалогах и команде SetRootLayout. Во всех этих местах можно определять контейнер непосредственно в виде JSON-строки. Но часто, например со списками и диалогами хранить контейнеры в отдельном месте (раздел конфигурации Контейнеры (в структуре конфигурации массив Layouts)), а при определении списков или диалогов, либо в setRootLayout использовать ссылку на переменную контейнера.
В разделе Контейнеры действуют все те же самые принципы построения контейнеров, толкьо с одним условием – у контейнера (верхнего уровня) обязательно должна быть переменная, по которой к нему можно будет ссылаться.
Конфигурация с примерами использования такого подхода: https://disk.yandex.ru/d/v9ZYd8GlMH_03w
Прочие поля и свойства контейнера, методы
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**Переменная.** Необязательное для контейнера поле. Может использоваться для того, чтобы обратиться к контейнеру из какой либо функции.
Например есть команда-переменная **UpdateLayout, <переменная контейнера>** по которой обновиться только указанный контейнер. Т.е. это аналог RefreshScreen, но только для одного контейнера. Эту команду желательно использовать, когда на экране что то тяжелое, например ActiveCV
Замена контейнера экрана
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Макет экрана, определенный из кода, можно динамически заменить в экране командой-переменной **SetRootLayout** (из onStart например). В качестве параметра к ней, можно использовать как JSON-строку с нужным контейнером, так и ссылку на контейнер через префикс "^"
Общие для элементов и контейнеров свойства
-----------------------------------------------
**Цвет фона** (свойство BackgroundColor) – цвет, задаваемый в виде HEX-значения. Например #89f096
**Толщина окантовки** (ключ StrokeWidth) - рисует рамку вокруг контейнера или элемента с заданной толщиной в экранных единицах
**Внутренние отступы** (ключ Padding) – отступы вглубь контейнера в экранных единицах
**Радиус** (ключ Радиус) – если задана Толщина окантовки, то рисуется не прямые поля а закругление. Для элемента можно назначить радиус, равный -1. Тогда закругление будет в виде полного круга.
Cвойства и функции элементов экрана
--------------------------------------
Все элементы имеют поле **Переменная (ключ Variable)**. Это ИД элемента. Оно выполняет несколько функций:
1) как правило при генерации событий, имя переменной пишется в listener (Например на экране несколько кнопок и при нажатии в listener пишется переменная кнопки)
2) По переменной можно обратиться к элементу, например установить видимость (см. ниже)
3) по переменной можно получить Java-объект функцией getView чтобы проделать с ним низкоуровневые манипуляции на уровне AndroidSDK
**Значение (ключ Value)**. В зависимости от типа элемента – это различное значение, видимое в элементе. Для надписи – это текст надписи, для кнопки – текста кнопки, для таблицы – весь макет таблицы с данными и т.д. Значение может задаваться в виде константы, т.е. в виде просто текста в конфигурации, может быть в виде ссылки на переменную стека (через символ @) и может быть задано в виде ссылки на слайс (через символ #)
**Выравнивание по горизонтали** (gravity_horizontal) – выравнивание элемента отновительно контейнера. Может принимать значения left, right, center
**Размер текста (TextSize)**, **Цвет текста(TextColor)**, **текст жирный ("TextBold")**, **Наклонный ("TextItalic")** – задает параметры элементов, имеющих надписи (например Надпись): размер в виде относительного размера, цвет в виде HEX-значения, жирный и наклонный - булево
**Количество знаков(NumberPrecision)** – количество знаков после запятой для полей ввода типа число.
**Писать в слайс (Slice)** – для полей ввода информация будет писаться в слайс экрана/процесса в типизированном виде (без преобразования в строку ) – JSON-структуру доступную через переменные process_slice (слайс, существующий на протяжении всего процесса) и screen_slice (слайс экрана) в обработчике pythonscript
Подсветка обязательных полей и ошибок заполнения
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Возможны варианты:
* Галочка элемента Подсвечивать пустое. Это просто автоматическая подсветка незаполненного. Ни на что не влияет, убирается, когда происходит заполнение
* Галочка Не пропускать пустое. Выдаст визуальную ошибку на поле и не даст выполнится обработчику дальше.
* Проверка поля в обработчике и визуальная выдача ошибки, если поле не соответствует. Это уже проверка не просто на заполненность, а на значение самого поля. Выполняется с помощью команды **Stop_<переменная поля>**. Понятно, что и без этого достаточно вывести тост или что то подобное, но так нагляднее
Управление видимостью элементов
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Для управления видимостью отдельных элементов экрана следует использовать команду **Show_<Идентификатор элемента>**, например ``hashMap.put(«Show_left»,»-1») `` , где left - переменная элемента (переменная=идентификатор). Значения могут быть:
* "1" - виден
* "0" - не виден, без освобождения места,
* "1" - виден, с освобождением места
Отключение перерисовки экрана, генерации событий, подсветка краcным и зеленым
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Можно использовать команду **noRefresh**, которая отключает перерисовку элементов - т.е. обновление экрана при выполнении обработчика. Пример:
.. code-block:: Python
hashMap.put("noRefresh","")
Можно отключить события по полям ввода, котрые автоматически генерируют события при вводе (например Галочка, поля с отслеживание ввода символов) командой **disable_events**, без параметров.
Можно использовать подсветку полей ввода бледно-зеленым и бледно-красным цветом. Для того чтобы обозначить пользователю корректный или некорректный ввод можно выделить неярким красным или зеленым цветом поля ввода списком
* SetRed, <список переменных полей ввода через “;”> - выделяет список полей красным
* SetGreen, <список переменных полей ввода через “;”> - выделяет список полей зеленым
Фокусировка
~~~~~~~~~~~~~~~
Для поля ввода можно задать принудительную фокусировку – тогда при открытии экрана поле ввода будет активным (с курсором), командой **FocusField, <имя переменной поля>**. Можно выбрать только одно поле. Допустим у вас экран ввода штрихкода, а на следующем экране необходимо сразу
Html-строки
--------------
Все надписи, практических всех элементов (не только непосредственно элементы Надпись, но и прочие элементы, например текст в таблицах) можно размечать HTML-тегами. Это мощный и простой способ оживить интерфейс без усложнения лишними контейнерами, фоновыми цветами и т.д., Например можно выделить часть строки так. Это простой текст, а это жирный
.. image:: _static/2025_screen_8.png
:scale: 55%
:align: center
Вот примерный список поддерживаемых тегов:
* p
* ul
* li
* div
* span
* strong
* b
* em
* cite
* dfn
* i
* big
* small
* font
* blockquote
* tt
* a
* u
* del
* s
* strike
* sup
* sub
* h1
* h2
* h3
* h4
* h5
* h6
* img
* br
Awesome-иконки
-------------------
.. image:: _static/2025_screen_9.png
:scale: 55%
:align: center
В системе можно использовать растровые иконки (файлы подключаются через раздел Медиафайлы и потом используются через префикс ^). Но можно использовать набор шрифта Awesome. Это набор пиктограмм, с помощью которого можно сделать свои красивые кнопки, сделать иконки на карточках, экранах и т.д. Используется бесплатный набор из 1001 иконки (отбор по free + отбор по solid) https://fontawesome.com/v5.15/icons?d=gallery&p=2&s=solid&m=free Для того чтобы использовать, надо взять на сайте Unicode -код например f6be и присвоить переменной с префиксом # – т.е. #f6be, который потом указать в заголовке кнопки или надписи. Это можно использовать в элементах экранов, диалогов и т.д. Например:
* Кнопка
* Список кнопок
* Горизонтальный список кнопок
* Надпись
Упрощенная разметка полей ввода с заголовком помощью “|”
--------------------------------------------------------------
Все поля ввода (кроме современного поля ввода) можно разместить вместе с заголовком в упрощённом виде. Как это было бы в стандартном исполнении? Для этого надо сделать горизонтальный контейнер и разместить в нет два элемента – Надпись (заголовок поля) и поле ввода с весами у обоих =1. Тогда мы получим поле с заголовком. Это же действие можно выполнить, если разместить просто поле ввода:
.. image:: _static/2025_screen_10.png
:scale: 90%
:align: center
Элементы контейнера
------------------------
Надпись
~~~~~~~~~~~~~~~~
Надпись(TextView) – выволится надпись из переменной или константы.
Кнопка
~~~~~~~~~~~~
Кнопка(Button) – простая текстовая кнопка, но с помощью Awesome можно превратить ее в кнопку с иконкой. При нажатии генерирует событие с listener=переменная кнопки.
Простые поля ввода
~~~~~~~~~~~~~~~~~~~~~~
Поле ввода строка(EditTextText), Поле ввода число(EditText EditTextNumeric), Поле ввода пароль(EditTextPass), Многострочный текст(MultilineText) – простые текстовые поля ввода соответствующих данных(регулируется фильтром на ввод). Для пароля введенный текст скрывается.
Современное поле ввода
~~~~~~~~~~~~~~~~~~~~~~~~~~
.. image:: _static/2025_screen_11.png
:scale: 55%
:align: center
Поле ввода, в котором размещается заголовок/подсказка в зависимости от того, заполнено оно или нет. Если в поле присутствует информация, подсказка смещается в область заголовка. Таким образом достаточно размещать только один элемент, что экономит место и упрощает разработку.
Значение задается в виде JSON. Обязательными является hint – подсказка. Например
.. code-block:: JSON
{
"hint":"Логин",
"default_text":"default_login"
}
– задает подсказку, и если поле уже должно содержать предопределенные данные, то они задаются в **default_text** (можно передавать не константу, а ссылку на переменную через @)
По умолчанию – это текстовое поле, но можно задать любой тип, имеющийся на Андроиде через **input_type**. Варианты – тут: https://developer.android.com/reference/android/text/InputType
Также, можно задать **counter** – счетчик введенных символов внизу и counter_max – максимальное количество символов.
Ключом **events** можно подключить генерацию событий с каждым введенным символом в поле, чтобы например записывать в БД сразу же введенный текст. Значение должно быть «true»
Пример определения со всеми возможными опциями:
.. code-block:: JSON
{
"hint":"Пароль",
"default_text":"default_password",
"counter":"true",
"counter_max":15,
"input_type":145,
"password":true,
"events":true,
}
Поле ввода с событием
~~~~~~~~~~~~~~~~~~~~~~~~~~
Поле ввода с событием (EditTextAuto) – текстовое поле, при вводе каждого символа в котором генерируется событие и срабатывает обработчик
Галочка
~~~~~~~~~~~~~
Галочка (CheckBox) – поле чекбокса с событием изменения(генерируется событие с listener=имя переменно). Значение пишется в переменную стека (переменная определяется в Переменной(Variable)) (и читается также из переменной, а не из значения). В поле Значение (Value) - заголовок поля.
Дата
~~~~~~~~
Дата(DateField) поле выбора даты из календаря. При выборе даты в переменную даты пишется отформатированная в соответствии с региональными настройками выбранная пользователем дата, а в переменную <переменная_поля>_d пишется дата в ISO-формате. В слайсы, аналогично пишутся даты в двух форматах – представление и ISO.
DatePicker, NumberPicher, TimePicker
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. image:: _static/2025_screen_12.png
:scale: 55%
:align: center
Визуальные элементы для выбора числа, даты, времени. Выбранные значения записываются в переменную. Начальная установка определяется в Значении.
Формат Значения для элементов:
* Пикер числа: {"min":0,"max":10,"value":"@number"}, где min/max задают диапазон, value- установленное значение
* Пикер даты: {"year":@year,"month":@month,"day":"@day"} - значение пишется в виде года, месяца и дня
* Пикер времени: {"hour":@hour,"minute":@minute} – часы, минуты
Картинка (см. раздел «Работа с изображениями»)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Выпадающий список
~~~~~~~~~~~~~~~~~~~~~~~
Выпадающий список – простой выпадающий список. Элементы можно задать в виде строки с разделителем «;» через переменную или прямо в конструкторе. В списке всегда будет выбран первый элемент, поэтому если требуется чтобы по умолчанию было пусто , первым элементом следует определить пустую строку или что то подобное. Например "<Выберите значение>;Первый;Второй". В Переменную при этом возвращается выбранное значение. Можно указать значение по умолчанию - то значение, которое будет выбрано при открытии. Для этого нужно в стек переменных поместить переменную с именем переменной результата. Например, если переменная - res то помещаем в hashMap.put("res","Второй").
.. note:: Для выбора ссылочных объектов предназначены поля датасетов (см. Датасеты)
Список кнопок вертикальный и Список кнопок горизонтальный
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Размещение нескольких кнопок с помощью списка. В значении передается список заголовков кнопок, и они размещаются в ряд вертикально или горизонтально. При нажатии генерируется событие с listener=<переменная кнопки> и также в стек помещается переменная =перменной кнопки со значением, равным заголовком кнопки.
Индикатор(Gauge)
~~~~~~~~~~~~~~~~~~~
.. image:: _static/2025_screen_14.png
:scale: 55%
:align: center
стрелочная диаграмма для визуального представления какого то значения
В качестве значения передается JSON-строка с ключами Min(минимальное значение шкалы), Max (максимальное значение шкалы), Unit (единица измерения) и Value (текущее значение)
Пример:
.. code-block:: Python
tmenu['gauge_tasks'] = json.dumps({"Min":0,"Max":100,"Value":q,"Unit":" "})
Диаграммы. Линейная (Line), Столбчатая (Bar) и Круговая(Pie) вывод диаграмм в контейнер
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. image:: _static/2025_screen_15.png
:scale: 55%
:align: center
.. note:: Кстати, еще одним хорошим способом вывести диаграммы и вообще отчеты является HTML-поле + какая либо библиотека для диаграмм на python. См. HTML-поле и например пример подключения библиотеки pygal https://infostart.ru/1c/articles/1760354/
Пример Значения столбчатой диаграммы
.. code-block:: JSON
{"type":"Bar","Datasets":[{"name":"Оптовые продажи","values":[{"x":"2017","y":"100"},{"x":"2018","y":"210"},{"x":"2019","y":"260"}]},{"name":"Розничные продажи","values":[{"x":"2017","y":"55"},{"x":"2018","y":"40"},{"x":"2019","y":"75"}]}]}
Пример Значения линейной диаграммы
.. code-block:: JSON
{"type":"Line","Datasets":[{"name":"Оптовые продажи","values":[{"x":"2017","y":"100"},{"x":"2018","y":"210"},{"x":"2019","y":"260"}]},{"name":"Розничные продажи","values":[{"x":"2017","y":"55"},{"x":"2018","y":"40"},{"x":"2019","y":"75"}]}]}
Пример Значения круговой диаграммы
.. code-block:: JSON
{"type":"Pie","dataset_name":"по регионам","PieDataset":[{"value":35,"caption":"ЦФО"},{"value":20,"caption":"СЗФО"},{"value":45,"caption":"Прочие"}]}
Таблица и Список карточек
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Таблица и список карточек отличаются только дизайном и форматом значения. По сути это один и тот же элемент с одними и теми же свойствами и поведением.
Таблица не имеет границ строк по умолчанию, их надо задавать в контейнере если требуется. Тоже самое с чересстрочной разметкой.
.. image:: _static/2025_screen_17.png
:scale: 75%
:align: center
В Списке карточек элементы оформлены в виде карточек
.. image:: _static/2025_screen_16.png
:scale: 100%
:align: center
Существует несколько подходов к определению значения этих списков, поэтому укажем универсальный формат
Для списка карточек переменная будет иметь структуру:
.. code-block:: JSON
{ "customcards":{
"options":ОПЦИИ,
"layout": КОНТЕЙНЕР,
"cardsdata": ДАТАСЕТ
}
}
Для таблицы:
.. code-block:: JSON
{ "customtable":{
"options":ОПЦИИ,
"layout": КОНТЕЙНЕР,
"tabledata": ДАТАСЕТ
}
}
Где:
**ОПЦИИ** (необязательный) – объект с различным набором опций:
* **search_enabled**,булево – поиск в тулбаре. Для объектов без механизма датасетов – это поиск по вхождению строки по всем полям поиска. Для датасетов поиск настраиваемый см. Датасеты.
* **save_position**, булево – сохранение поизиции при перерисовке. Например при обновлении строки. Работает только для списков с конечным датасетом. При использовании пополнения порциями в настоящий момент не работает.
* **override_search**, булево – переопределить поиск в тулбаре. Будет срока поиска, но при вводе будет осуществляться не поиск, а генерация события ввода с переменной "SearchString" и listener=Search. Фильтрацию списка в данном случае осуществляет сам разработчик
* **search_submit** – поиск/генерация событий соуществляется не после каждого введенного символа, а после подтверждения ввода на клавиатуре
* **colorizing** использование выборочной раскраски элементов (см. далее)
* **horizontal** – горизонтальное направление списка
**КОНТЕЙНЕР** – либо JSON с текстом контейнера (текст можно скопировать, например из конструктора) непосредственно (что неудобно и громоздко), либо ссылка на контейнер определенный в конфигурации через символ ^. Например, "layout": "^item1" (см. пример ниже)
**ДАТАСЕТ** – либо JSON-массив, либо ссылка на датасет(механизм датасеты) через префикс ~. Данные в обоих случаях – массив JSON -объектов по одному на каждый элемент списка. В которых перечисляются переменные, отображаемые в контейнере (через @). Также могут быть добавлены любые другие(неотображаемые в интерфейсе).
Также в элементе датасета отдельно можно указать key – ключ, возвращаемый при нажатии в специальную переменную (в случае с механизмом датасетов это делать не имеет смысла, так как в датасете у каждой записи есть _id)
Пример определения списка карточек в Python (без использования механизма датасетов, с опциями поиска в тулбаре и сохранение позиции)
.. code-block:: Python
j = { "customcards": {
"options":{
"search_enabled":True,
"save_position":True
},
"layout": "^card1",
"cardsdata":[]}
}
j["customcards"]["cardsdata"].append({"text1":"Какой то заголовок 1","text2":"Подзаголовок №1"})
j["customcards"]["cardsdata"].append({"text1":"Какой то заголовок 2","text2":"Подзаголовок №2"})
hashMap.put("cards",json_to_str(j))
Пример Таблицы с использование датасетов, без опций:
.. code-block:: Python
j = { "customtable": {
"layout": "^item",
"tabledata":"~goods"}
}
При нажатии на элемент списка генерируется событие CardsClick. В переменных появляется:
* **selected_card_key** – ключ, если, а записи есть key
* **selected_card_position** – позиция списка
* **selected_card_data** (если это датасет, либо если не датасет, то если заранее включен флаг "return_selected_data") – целиком запись в виде JSON-элемента массива
Переопределение макета любого элемента списка
""""""""""""""""""""""""""""""""""""""""""""""""""
С релиза 10.35 можно для любого элемента customcards и customtable сделать свой дизайн на основе отдельного контейнера (например выделить цветом), абсолютно любого содержания. Для этого в rows в конкретном элементе надо использовать _layout и передать туда нужный макет. Таким образом, можно сделать каждый элемент со своим дизайном.
.. code-block:: Python
j = { "customtable": {
"layout": "^card1",
"tabledata":[]}
}
j["customtable"]["tabledata"].append({"text1":"Какой то заголовок 1","text2":"Подзаголовок №1"})
j["customtable"]["tabledata"].append({"_layout":"^card2","text1":"Какой то заголовок 2","text2":"Подзаголовок №2"})
j["customtable"]["tabledata"].append({"text1":"Какой то заголовок 3","text2":"Подзаголовок №3"})
hashMap.put("cards",json_to_str(j))
Выборочная раскраска элементов списка
""""""""""""""""""""""""""""""""""""""""
В списках можно делать произвольный макет каждого элемента (через "_layout"), в том числе и раскраску, но это затратная технология (на больших списках и медленных устройствах сказывается на быстродействии). Поэтому добавлена просто «раскраска» (меняется только цвет фона, а не весь макет)
В опциях таблицы должно быть включено **"colorizing"**, и тогда на элементы можно использовать свойство **_background** с указанием цвета в HEX-формате.
Использование активных элементов в списках
""""""""""""""""""""""""""""""""""""""""""""
.. image:: _static/2025_screen_18.png
:scale: 90%
:align: center
В элементах списков доступно использование активных элементов: Кнопки, Меню и Флажки. Для этого их нужно разместить в контейнере в любом количестве и любом месте. При нажатии они будут порождать отдельное от нажатия на саму карточку событие с **listener=LayoutAction**, также помещается переменные **layout_listener** и card_data. В первой содержится переменная элемента, породившего событие (кнопки, пункта меню, флажка). Во второй - данные карточки, включая позицию в виде JSON-строки. Для добавления меню нужно поместить в контейнер элемент **PopupMenuButton**, в качестве значения передать список пунктов меню, разделенных точкой с запятой. Например "Первый;Второй"
Флажок ведет себя как обычный флажок, плюс выполняет необходимое действие - при изменении состояния, он прописывает значение состояния в датасет переменной списка, чтобы при обновлении списка показать текущее состояние.
Использование поиска, переопределение поиска
"""""""""""""""""""""""""""""""""""""""""""""""""""
.. note:: Для датасетов поиск устроен по-другому. См. главу "Датасеты".
Для того, чтобы на экране появился автоматический поиск по таблице в тулбаре, необходимо добавить в JSON списка в раздел «options» поле **search_enabled** с значением True. Также по желанию, можно передать поле, по котору будет вестись поиск **search_string** - это ключ, в который для каждой карточки можно поместить строку с данными поиска. Поиск будет вестись по вхождению подстроки поиска в эту строку. Если такого поля нет в карточке, то будет вестись поиск по всем полям объекта данных. Этот поиск можно переопределить - пустить вводимый текст на события. Для этого в раздел «options» необходимо добавить **override_search** с значением True, тогда при вводе текста в поле поиска будет генерироваться событие **Search**, а в переменную **SearchString** будет попадать введенный текст
Горизонтальные списки
""""""""""""""""""""""""
.. image:: _static/2025_screen_19.png
:scale: 75%
:align: center
Опция **horizontal**:True делает список горизонтальным. Также, если требуется чтобы карточка была не на всю ширину экрана, а допустим на какую то его часть, нужно указать опцию "width_ratio" – с процентом от ширины экрана, например 50 - будет половина экрана. Если не указать, то карточка будет на всю ширину
Сохранение позиции в списке
"""""""""""""""""""""""""""""
Для того, чтобы на экране появился автоматический поиск по таблице в тулбаре, необходимо добавить в JSON списка в раздел "options" поле «save_position» с значением True. При наступлении события и перерисовке списка, список останется на том же месте.
Использование групп
""""""""""""""""""""""""
Можно сгруппировать список карточек (работает только со списком карточек). Для этого в нужных местах датасета нужно вставить объекты с полем «group» (предопределенное поле)
Догрузка данных при промотке
"""""""""""""""""""""""""""""""
Для больших списков можно сделать догрузку – получение порций данных, когда пользователь промотал до конца. При промотке дальше возникает событие LoadMoreItems, оформленное прогресс баром, в котором разработчик может определить обработчик добавления новой порции строк в переменную AdditionalItemsData.
Позиционирование на позицию в списке карточек и таблице
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
Теперь можно мгновенно или плавно переместиться на выбранную позицию двумя простыми командами:
* **ListGoTo**, номер позиции – мгновенное перемещение на позицию
* **ListGoToSmooth**, номер позиции – анимированное перемещение на позицию
Поля датасетов
~~~~~~~~~~~~~~~~~~
.. image:: _static/2025_screen_20.png
:scale: 75%
:align: center
Можно разместить на экране ссылочные поля ввода данных, содержащие ссылки на записи датасетов
Вы просто указывает переменную в которой храниться или будет храниться значение поля в виде ссылки и датасет в значении. И всё. Пользователь просто выбирает запись из списка, пользуется поиском если надо. При выборе в переменную также попадает универсальная ссылка.
Для такого случая у датасета желательно в опциях определить 2 вещи:
* Представление записи – опция view_template. Можно использовать html. Имена полей указываются в фигурных скобках. Можно разместить в представлении несколько полей. Например {name}, {barcode}. Можно использовать html. Например {name}:{article}
* Можно указать форму элементов списка list_layout – имя контейнера (по умолчанию AUTO)
Пример создания и указания опций датасета:
.. code-block:: Python
datasrv = CreateDataSet("goods")
datasrv.setOptions(json_to_str({"list_layout":"item","view_template":"{name} , {article}"}))
Можно использовать конструкцию с | чтобы разместить поле с заголовком
Для задания настройки полей есть упрощенный вариант и вариант с настройками. Упрощенный вариант приведен выше, а для настроек необходимо указать JSON-настройки (обычно - через переменную)
* dataset (обязательно) – имя датасета
* inline – поиск по строке непосредственно в поле
* select – кнопка выбора из списка
* spinner – выбор из списка (аналог выпадающего списка) заменяет опцию inline
* hint - подсказка
.. image:: _static/2025_screen_22.png
:scale: 75%
:align: center
Выбранные и предустановленные значения
""""""""""""""""""""""""""""""""""""""""""
Везде используется универсальная ссылка - как результат пользовательского выбора, так и для установки предопределенных значений.
Например, создадим датасет nds
.. code-block:: Python
datasrv = CreateDataSet("nds")
datasrv.setOptions(json_to_str({"view_template":"Ставка - {name}"}))
nds_list = []
nds_list .append({"name":"10%","_id":"НДС10"})
nds_list .append({"name":"20%","_id":"НДС20"})
nds_list .append({"name":"0%","_id":"НДС0"})
datasrv.put(json_to_str(nds_list))
И на экране в onStart установим НДС по умолчанию
.. code-block:: Python
hashMap.put("nds","nds$НДС20")
Тогда, при открытии, увидим результат:
.. image:: _static/2025_screen_21.png
:scale: 55%
:align: center
ActiveCV
~~~~~~~~~~~
.. image:: _static/2025_screen_23.png
:scale: 55%
:align: center
CV-возможности подробно разобраны в разделе ActiveCV
Поле карты
-------------
Векторные карты подробно разобраны в разделе Векторный редактор
HTML-поле
~~~~~~~~~~~~~
.. image:: _static/2025_screen_24.png
:scale: 55%
:align: center
.. note:: В данном разделе речь идет о элементе экрана HTML, но по большей части это справедливо и для команды PrintPreview которая открывает HTML-поле для предпросмотра и печати.
На экране можно разместить HTML-поле. В значение нужно передать HTML-документ, тогда отобразится в виде HTML.
Также этот элемент содержит поддержку Javascript и может выполнять cкрипты в документе. Связь с Андроид-приложением (генерация события в SimpleUI) происходит через функцию onInput
Пример реализации обработчиков кнопок.
.. code-block:: HTML
Для подготовки HTML можно использовать, например шаблонизатор Jinja. Подробнее о приемах разработки написано тут https://infostart.ru/1c/articles/1760354/
Кстати, файлы макетов необязательно хранить в виде строк в обработчиках, для этой цели вполне хорошо подходят Медиафайлы. Можно прицепить несколько макетов к конфигурации и использвоать их.
Произвольная разметка экранов (XML-разметка)
-----------------------------------------------
Альтернатива конструктору и контейнерам - произвольная разметка экранов, в том виде, в котором она существует в нативной разработке. С соответствующими инструментами работы. Подробно описана в статье https://infostart.ru/1c/articles/1983895/