Python в обработчиках¶
Приложения Simple UI могут использовать интерпретатор Python для выполнения кода обработчиков в любом режиме. Можно писать код обработчиков используя процедуры, классы, библиотеки. Перечень библиотек и актуальная версия интерпретатора может меняться от релиза к релизу и информация об этом будет обновляться.
- На текущий момент используется:
Версия Python - 3.11 (для сборки с OpenCV+PyTorch – версия 3.8)
- Подключены библиотеки:
Стандартные библиотеки
Requests
Lxml
pony
Pillow
Jinja2
python-barcode
pymongo
qrcode
tinydb
tinyrecord
zpl
escpos-gen
pelicandbms
python-dateutil
- Так как GooglePlay не позволяет публиковать пакеты больше 100 Мб, то периодически, в виде отдельных сборок apk публикуется сборка с:
Pandas
BeautifulSoup
OpenCV
Pytorch
torchvision
Взаимодействие Python-обработчиков с платформой и интерфейсом происходит через стек перменных (объект hashMap), слайсы, а также объекты напрямую – Датасеты, СУБД, файлы, прямой вызов функций платформы
- hashMap (стек переменных) – объект, через который передаются переменные и т.н. комманды-переменные (ShowScreen, FinishProcess и т.д.). Это не python-словарь, как можно было бы подумать, а Java-объект HashMap<String, String>. Обращение к нему происходит через указанные методы:
put(ключ,значение) – поместить переменную
get(ключ) – получить переменную
remove(ключ) – удалить переменную
containsKey(ключ) – проверить, есть ли такой ключ в коллекции
Причем с точки зрения выполнения, сам стек (и команды в нем) анализируются в конце обработчика, то есть интерпретируется обработчик (со всему put, remove), потом система читает ключи в стеке и выполняет комманды.
Есть несколько видов python-обработчиков с разным назначением.
Тип обработчика pythonscript¶
Самый простой обработчик. Выполняется как excec(<код обработчика>). Нигде не хранится, по сути, это строка, запускаемая на интерпретацию. Из этого исходит тот факт, что между вызовами этого обработчика также не хранятся и переменные. Это похоже на JavaScript. Это можно было бы сравнить с запуском скриптов в разных терминалах.
Отличительной особенность данного обработчика- сам скрипт в виде base64 храниться в массиве обработчиков в method и редактируется непосредственно в окне конструкторе. Это упрощает работу с небольшими скриптами и лучше структурирует архитектуру обработчиков. Все примеры написаны с использованием этого типа обработчиков
Примечание
Simple стремиться к простоте и минимальности кода, поэтому вместо нагромождения модулей, рекомендуется ограничиваться небольшими скриптами 10-15 строк на одно событие
- В обработчик заходят:
hashMap – стек перменных
process_slice – слайс процесса (на чтение)
screen_slice – слайс экрана (на чтение)
Также подключены:
Функция get_body которые позволяет в упрощенном режиме вырезать код из текущего обработчика для запуска обработчиков (например RunEvent или для download)
Пример
def after_download_1():
with open(hashMap.get("DownloadedFile"), encoding='utf-8-sig') as f:
toast("Загрузили файл : "+hashMap.get("DownloadedFile"))
hashMap.put("RestartScreen","")
postExecute = json_to_str([{"action": "run", "type": "pythonscript","method":get_body(after_download_1) }])
su.download(download_url,None,None,'goods.txt',postExecute)
2) функции **json_to_str** и **str_to_json** оберки для json.dumps(j,ensure_ascii=False, indent=4) и json.loads(s)
3) функции для работы с датасетами:
* CreateDataSet(name,options=None)
* GetDataSet(name)
* DeleteDataSet(name)
Функция GetDataSetData
Функция SendBus для отправки в шину
- Модули:
android – функции системы, такие как toast,beep,speak и т.д.
json
base64
Переменные:
_local – key-value СУБД (см. раздел Хранение)
_data_dir , _downloads_dir – папки конфигурации для внутреннего хранения
Общий модуль general¶
Также в конструкторе (в разделе Конфигурация) доступен для редактирования модуль general. Его поведение в системе несколько отличается. Он сохраняется в файл при загрузке конфигурации и доступен через import general. В этом модуле можно хранить общие функции и переменные.
Тип обработчика python¶
В отличии от pytonscript эти обработчики при загрузке в конфигурацию сохраняются в файл handlers_conf.py, далее из этого модуля идет вызов функций. Т.е. в method в массиве обработчиков храниться не сам текст скрипта, а имя функции, которая запускается из модуля. Обработчики такого типа (также как и pythonargs и pythonbytes) подключаются в конфигурацию в виде файлов. Должен быть как минимум файл обработчиков (это вызовы функций, объявляемых в массиве обработчиков), он пишется в конфигурацию в PyHandlers. Плюс может быть один или несколько подключаемых модулей. Они пишутся в массив PyFiles конфигурации
"PyFiles": [
{
"PyFileKey": "ext",
"PyFileData": "base64-содержимое файла"
}
]
Все файлы при загрузке конфигурации сохраняются в файлы в внутренней папке. Дополнительные файлы можно импортировать по ключу (они сохраняются в ту же папку с именем <key>.py
В пользовательском режиме все это сохранение происходит через конструктор. Это можно сделтаь на закладке Файлы модулей:
либо через обычную загрузку файлов (Загрузить основной py-файл, Добавить дополнительный Py-файл). При этом способе придется проделывать это действие при каждом изменении в файлах python
либо подключив GitHub(инструкция на странице конструктора). Доступно и открытый и закрытый репозиторий. Этот способ хорош тем, что также к репозиторию можно подключить ваше IDE и коммиты будут автоматически сохранться из IDE и при сохранении конфигурации. Кстати, саму конфигурацию (ui) также можно сохранять на GitHub (закладка Пользователь). Этот способ удобнее.
Когда нужно использовать python, а когда pythonscript? Приблизительно будет верным ответ, что python надо использовать в больших проектах, с более чем одним python-модулем. Для простых проектов всетаки предпочтительнее pythonscript.
Функции этого типа должны иметь определенный формат:
def foo(hashMap,_files=None,_data=None):
hashMap.put("toast",hashMap.get("barcode")) #пример записи в стек и чтения из стека
return hashMap
_data – для SUIP-файлов, данные, упакованные в файл
_files – устарело, но нужно указывать для совместимости
Функции, с произвольным числом аргументов pythonargs¶
картинка
Можно использовать функции с произвольным числом неименованных аргументов (обычно называют args). Для этого надо выбрать в настройке обработчика pythonargs
Пример кода такого обработчика:
def foo(hashMap,*args):
param1 = args[0]
param2 = args[1]
param3 = args[2]
return hashMap
Функция для работы с OpenCV pythonbytes¶
При захвате изображения для дальнейшего анализа в OpenCV в обработчик передается изображение в виде byte-массива. Обработчики имеют следующий формат:
def detect_face(hashMap,imageBytes):
np_data = np.asarray(imageBytes,np.uint8)
img = cv2.imdecode(np_data,cv2.IMREAD_UNCHANGED)
#Тут работа с изображением
return hashMap
Функции платформы, которые работают run-time (модуль android)¶
Все функции доступны через команды-переменные, но часто это не совсем удобно. Например, надо вывести тост внутри долгого обработчика или обновлять уведомление внутри цикла, а не после выполнения такта обработчика (а стек-машина выполняет команды-переменные по окончанию такта). Это именно run-time на уровне системы, т.е. выполняется непосредственно в момент вызова. Все подобные функции собраны в модуль вpython- модуль android и их можно использовать так:
import android
android.toast("hello")
Интерфейсные команды:
toast(String toast) – вывести сообщение Андроид
speak(String text) – произнести текст (TTS engine)
listen() – запустить ожидание распознавания речи
vibrate() и vibrate(int duration) – вибрация и вибрация заданной длительности
beep()/beep(int tone)/ beep(int tone,int beep_duration,int beep_volume) – звуковой сигнал, т.ч. с возможностью выбрать тон (от 1 до 99), продолжительность и громкость (по умолчанию – 100)
notification(String message)/ notification (String message,String title)/ notification(String message,String title,int number) – уведомление в шторке уведомлений. Number – идентификатор уведомления, по которому к нему можно потом обратиться, чтобы либо убрать, либо перезаписать (обновить)
notification_progress(String message,String title,int number,int progress) – уведомление с прогресс-баром (от 0 до 100) notification_cancel(int number) – скрыть уведомление
Управляющие команды:
refresh_screen() запускает рефреш экрана. Предполагается, что стек будет установлен рантайм методами работы со стеком
refresh_screen(hashMap) - запускает рефреш и передает стек.
RunEvent(String handlers) – запустить массив обработчиков
BackgroundCommand(command) – запустить фоновую команду
stop() или stop(hashMap) – точка останова для отладки
Работа со стеком:
get_process_hashmap() – получает стек переменных экрана из любого места
get_cv_hashmap() – получает стек переменных ActiveCV из любого места
get_service_hashmap() – получает стек переменных фонового сервиса из любого места
process_started() – получает признак, запущен ли процесс в данный момент
cv_started() – получает признак, запущено ли ActiveCV в данный момент
put_process_hashMap(key,value) помещает значение в стек процесса
remove_process_hashMap(key) – удаляет значение из стека процесса
Дополгнительные Java-модули, доступные из Python-обработчиков¶
Вообще, правильнее будет сказать что из Python-Обработчиков доступны люые Java-классы. Но практическую ценность имеют некоторые из них.
Класс ImportUtils (from ru.travelfood.simple_ui import ImportUtils as iu):
getView(String tag) – получить Java-объект виджета по его переменной (и после, делать все что хочется его методами)
getContext() – получить контекст (контекст может понадобится в других функциях SDK)
getRootLayout() – получить корневой контейнер экрана
Модуль SimpleUtilites(from ru.travelfood.simple_ui import SimpleUtilites as su):
get_stored_file(String key) – получить абсолютный путь к медиафайлу по ключу
download(String url,String user,String password,String filename,String postExecute) – запустить загрузку в воркере с прогресс-баром (пример выше). По окончании выполняется обработчик postExecute
deleteCache() – удаляет кеш приложения