Для меня идеальный графический интерфейс — это приложение, которое не требует затрат на программирование, дизайн и обслуживание и способно одинаково работать на любом языке и на любой платформе без каких-либо корректировок.
Попробуем разобраться, возможно ли это при нашей жизни.
Нетрудно самостоятельно освоить некоторые из Vue/React, JavaFX, Python PyQt. но получать данные и взаимодействовать с множеством программного обеспечения простым и элегантным способом, не думая о пользовательских ОС/браузерах/платформах, — это неразрешимая задача для таких инструментов.
Я не хочу лезть в новый фреймворк (даже старый, забытый), менять язык программирования, разгребать вещи и забивать голову мусором.
Я хочу программировать именно свою задачу, не отвлекаясь на борьбу со всякими GUI-фреймворками.
И я нашел для себя решение.
В качестве протокола обмена мы будем использовать Json как топовый формат по популярности/понятности/читабельности/поддержке всех языков ПО в той или иной степени.
Сервер отправляет данные Json, согласно которым графический интерфейс нашего приложения должен создать изображение, удовлетворяющее требованиям красивого графического интерфейса.
Google с его Material Design сегодня является стандартом, поэтому мы его принимаем.
Требования к современному графическому интерфейсу включают наличие стандартных элементов, таких как кнопки, поля ввода, таблицы и т. д. Давайте разберемся, как использовать минимальный набор соглашений, чтобы сообщить графическому интерфейсу, что нам нужны определенные элементы на экране.
Вот основные из них:
- Кнопка без гражданства {'имя': 'Нажми меня'}.
Если элемент содержит только имя, то это кнопка.
- Поле ввода {'имя': 'Редактировать меня', 'значение': ''}, поскольку тип значения — строка.
- Кнопка переключателя {'name': 'My state', 'value': false}, потому что тип false является логическим.
- Выберите из списка {'имя': 'Переключить что-нибудь', значение: 'выбор1', options=['выбор1', 'выбор2','выбор3']}
- Изображение {'имя':'Изображение, 'url'': '.
', 'ширина': .
, 'высота':… }
- Table {'name':'My table', 'headers'=['Name', 'Synonym'], rows = [
['молодой', 'молодой'],
['маленький', 'скудный'],
.
] }
Это возможно, когда один и тот же JSON можно сопоставить более чем одним способом.
Например, «Выбрать из списка» может быть представлено как поле ввода с выпадающим списком, а может и как горизонтальный набор кнопок, одна из которых активна и соответствует текущему значению.
Если количество опций невелико, имеет смысл автоматически использовать опцию кнопки; если их большое количество (более 3), имеет смысл использовать поле ввода-выбора.
Наш GUI сам выбирает оптимальный метод рендеринга, но если вам это действительно нужно, наберите:.
может помочь.
Обычно тип не нужен и автоконструктор должен разобраться с этим сам.
Дополним картину подробно:
- если имя не должно отображаться на экране, оно должно начинаться с _;
- если вам нужно где-то нарисовать иконку, добавьте «icon»: «любое имя стандартной иконки Material Design»; кнопка-значок соответственно будет описываться как {'name': '_Check', 'icon': 'check'}
- сложные элементы управления, такие как таблицы, средства просмотра, могут иметь дополнительные параметры, такие как «цвета», «параметры» и т. д., которые можно использовать для конкретного рендеринга или выбора доступных параметров редактирования/поиска/выбора для таблицы.
По умолчанию - максимальный набор опций, стандартные цвета для текущей темы.
{'name': 'Блок 1', 'elems': [ {'name': '_Check', 'icon': 'check'}, .
]} Внутри блока все элементы должны иметь уникальные имена, поскольку они также имеют идентификаторы.
Обычно блоки строятся горизонтально; если они не могут все поместиться на экране (например, мы запустили графический интерфейс приложения на мобильном устройстве), автоконструктор скрывает их, но добавляет на панель инструментов значки, которые позволяют открывать их одним касанием.
Это дает возможность работать со сложным графическим интерфейсом даже на маленьких экранах.
Верхний уровень описания — «Экран».
Выглядит как {'name': 'Screan', блоки: [.
], меню: [{'name': 'Screen','icon': .
, }, .
], 'toolbar': [набор JSON — элементы (кнопки, поля и т. д.)]} Давайте добавим детали реализации условного uniGUI, поддерживающего наш протокол JSON. Это отдельный процесс, который связывается с сервером данных через Websocket и обеспечивает отображение его данных, а затем сообщает обо всех обновлениях этих данных, важных для сервера.
При подключении к серверу uniGUI ожидает получить Screen. Получив ее, он оформляет и прорисовывает полученную информацию оптимальным образом для текущего экрана пользователя, затем ждет реакции от пользователя и сервера.
Из созданного изображения данных сервер получает поток сообщений JSON, полностью описывающих действия пользователя.
Они имеют вид ['Блок','Элем','тип действия','значение'], где «Блок» и «Элем» — названия блока и элемента, значение — значение события.
Сервер может либо принять изменения, либо откатить их, отправив информационное окно о несоответствии.
Может вызвать диалоговое окно, которое описано как блок и имеет доп.
Параметр 'buttons', описывающий кнопки диалога.
Клиент моментально отображает последние данные сервера и их изменения.
Отправляются только объекты, измененные сервером.
Для получения событий и обеспечения их обработки мы создадим слой Websocket (фреймворк), который будет автоматически переводить сообщения в вызовы обработчиков, привязанных к нашим данным (объектам).
Вся магия на сервере сводится к тому, что наши отображаемые данные должны быть связаны со слоем таким образом, чтобы без какого-либо кодирования их можно было автоматически перевести в JSON и вызывать уведомления об активности пользователя.
Поскольку это зависит от возможностей конкретного языка, то слой может иметь разные варианты для каждого языка, как архитектурно, так и конкретно.
Например, в одном случае в слое есть папка скриншотов, каждый из модулей в которой имеет описание одного экрана на Python. При запуске слой считывает экраны и отдает пользователю экран с глобальным приоритетом = 0. Все данные автоматически переводятся с помощью jsonpickle. Сложные элементы обладают собственным «разумом», избавляющим программиста от необходимости беспокоиться о деталях.
Например, таблица получает набор строк, которые по умолчанию могут не содержать строк с идентификаторами, когда количество данных в строке == количеству элементов в заголовках.
В этом случае, когда пользователь выбирает строку или редактирует ее содержимое, сервер отправит индекс строки в качестве идентификатора.
Если количество данных в строке на один больше, чем в заголовках, последний элемент в строках интерпретируется как id и именно он отправляется на сервер.
Такая автоматизация значительно упрощает жизнь, где не нужна никакая специфика, но если вдруг понадобится, то доступна наименее трудоемким способом.
Задача обеспечения автоматического перевода в JSON в формате, занимающем одну-две страницы, вполне решаема на любом языке (надеюсь на это).
Чтобы не обсуждать применимость этого подхода для сложных приложений, ниже я привожу скриншоты uniGUI, написанного на flutter, как описано.
Выбор пал на него из-за его мультиплатформенности и отсутствия дополнительных слоев типа JS/chrome. К недостаткам флаттера можно отнести отвратительную поддержку рабочего стола и низкое качество кода верхнего слоя (элементов GUI), неприятную архитектуру точечного обновления и управления элементами как данными, с которыми, впрочем, можно обращаться.
Поток сообщений GUI приложения -> сервер выглядит примерно так:
флаттер: [Глоссарий, Термины, =, 658]
флаттер: [_Подробности, Ссылки, @, @Folliculitis]
флаттер: [_Подробности, Ссылки, @, @Adolescent]
флаттер: [панель инструментов, _Back, =, _Back]
флаттер: [панель инструментов, _Forward, =, _Forward]
флаттер: [панель инструментов, _Back, =, _Back]
флаттер: [_Details, _Status, =, Virtual]
флаттер: [_Details, _Status, =, Стабильный]
флаттер: [_Подробности, Ссылки, @, Воспаление ]
флаттер: [_Details, _Status, =, Virtual]
флаттер: [_Details, _Status, =, Стабильный]
флаттер: [панель инструментов, _Back, =, _Back]
флаттер: [_Подробности, Ссылки, @, @Folliculitis]
А не будет ли такой GUI тормозить при ожидании событий от сервера? Нет, потому что графический интерфейс работает в режиме уведомлений сервера, реагируя на все действия пользователя, как обычный локальный графический интерфейс.
По умолчанию молчание сервера при действиях пользователя рассматривается как «ОК».
При смене экранов понятно, что должно прийти его описание.
Возможна задержка по сравнению с обычным приложением со встроенным графическим интерфейсом.
Нижняя граница.
Сегодня возможно, используя текущие инструменты, сделать GUI, убирающий 90% стандартного утомительного кода сопровождения и не заморачиваться над тем, где и как он будет работать.
По крайней мере, для деловых/научных приложений.
Эта статья является доказательством концепции того, что создание условный браузер приложений не только можно, но и нужно.
Теги: #программирование #Технологии #интерфейсы #ИТ-стандарты #мобильная разработка #GUI #веб-программирование
-
Тизер «Бэтмен Против Супермена»
19 Oct, 24 -
Векторная Карта Москвы.
19 Oct, 24 -
Миграции Прибыли В Yii
19 Oct, 24 -
В Рунете Появился Новый Виртуальный Город
19 Oct, 24