Я пытаюсь создать настольный пользовательский интерфейс для схем, макетов, рисунков. Просто ищу советы высокого уровня от настоящих разработчиков программного обеспечения.
Предполагая, что «база данных» находится в памяти (карта clojure произвольной глубины для всех пользовательских данных и, возможно, еще одна для настроек приложения и т. д.), я изучаю, как сделать на них модель-представление-контроллер, где данные могут быть обработаны и изменены одним или несколькими из следующих способов:
- Отдельное текстовое поле, в котором отображается один параметр, например ширина поля.
- Представление типа «инспектор», которое показывает несколько параметров выбранного объекта, таких как ширина, высота, цвет, флажки и т. д.
- Представление в виде таблицы или электронной таблицы, в котором отображаются несколько параметров нескольких объектов, потенциально вся база данных.
- Графическое изображение всего объекта, например схематическое изображение и вид компоновки.
Изменение любого из них должно немедленно отображаться в любом другом активном представлении, как текстовом, так и графическом, а не после нажатия «ОК» ... поэтому модальные окна не разрешены. Если по какой-то причине отображаются табличное представление, инспекторское представление и графическая визуализация, графическое перетаскивание угла поля должно немедленно отображаться в тексте и т. д.
Рассматриваемой платформой является JavaFX, но я хотел бы четкого разделения между пользовательским интерфейсом и всем остальным, поэтому я хочу избежать bind
ing в смысле JFX, поскольку это очень тесно связывает мои проектные данные со свойствами JFX, увеличивает зернистость модели. , и вынуждает меня работать вне стандартных функций clojure для работы с данными и/или активно работать со всем миром getValue
/setValue
.
Я по-прежнему предполагаю, по крайней мере, некоторую возможность сохранения состояния/изменяемости и использование встроенных функций Clojure, таких как возможность add-watch
на атоме/var/ref и позволять среде выполнения сигнализировать зависимым функциям.
Взаимодействие, зависящее от платформы, будет тесно связано с фактическим пользовательским интерфейсом, таким как уточнение ActionListener
, работа с ObservableValue
и т. д., и будет предпринята попытка свести к минимуму зависимость от таких вещей, как JavaFX Property
, для реальных данных приложения. Я не развлекаюсь FRP для этого.
Я не возражаю против расширения интерфейсов JFX или создания собственных протоколов для использования специфичных для приложения defrecord
, но я бы предпочел, чтобы данные приложения оставались прямыми данными Clojure, незапятнанными платформой.
Вопрос в том, как все это настроить, максимально придерживаясь неизменяемой модели. Я вижу несколько вариантов:
- Мелкозернистый: каждое значение/примитив параметра (например, Long, Double, Boolean или String) является атомом, и каждое представление, которое может изменять значение, «достигает» настолько, насколько это необходимо в базе данных, чтобы изменить значение. Это может быть отстойно, так как потенциально могут быть тысячи отдельных значений (например, точки на нарисованной от руки кривой), и потребуется много
(deref...)
мусора. Я считаю, что именно так JFX хотел бы сделать это с гигантскими массивами свойств в листовых узлах и т. Д., Которые кажутся раздутыми. При таком подходе это не кажется намного лучше, чем просто кодирование на Java/C++. - Среднезернистый: каждый объект/запись в базе данных является атомом карты Clojure. Вся карта заменяется при изменении любого из ее значений. Меньше всего атомов, с которыми приходится иметь дело, и позволяет, например, длинные массивы прямых чисел для различных вещей. Но это усложняется, когда некоторые объекты в базе данных требуют большей вложенности, чем другие.
- Грубое зерно: есть только один атом: база данных. Каждый раз, когда что-то меняется, вся база данных заменяется, и каждое представление должно повторно отображать свою конкретную часть. Это немного похоже на использование молотка, чтобы прихлопнуть муху, и наивная реализация потребовала бы все время перерисовывать все. Но я по-прежнему считаю, что это лучший компромисс, поскольку любой примитив имеет четкий путь доступа от корневого узла, независимо от того, осуществляется ли доступ к нему на уровне отдельных примитивов или на уровне записей.
Мне также нужна возможность многократного создания экземпляра одного шаблона данных. Так, например, если пользователь изменяет символ или фигуру, которые используются в нескольких местах, одно и то же редактирование будет применяться везде. Я считаю, что это также требует некоторого типа поведения, подобного «указателю». Я думаю, что могу сохранить атом в модели, а затем создать экземпляр по мере необходимости, и он может работать в любой из приведенных выше моделей зерна.
Любые другие подходы? Попытка сделать инструмент, похожий на графический редактор, на функциональном языке просто глупа? Спасибо
ChangeListener
заменить атом и запустить часы Clojure. Неато. Я не видел SceneBuilderKit (хотя я играл с их настольным приложением SceneBuilder), но я посмотрю. Еще одно соображение заключается в том, разрешить ли JFX владеть всем графом сцены, используя свои собственные примитивы, или рисовать свои собственные фигуры на холсте в стандартном стиле OnPaint, но это не относится к этому вопросу SO. - person Sonicsmooth   schedule 13.01.2015