Хабрахабр

Команда плагинов для настройки JavaFX компонент в настольном приложении

Любая UI библиотека или платформа обладает увы лишь базовым функционалом и набором компонент. Всегда приятно общаться с приложением, которое запоминает твои повадки и словно чувствует тебя, того, что ты хочешь. К счастью, сегодня таким функционалом никого не удивишь. Например, если колонка в таблице не перемещается или по ней нельзя отсортировать, то такое приложение, в котором она используется сложно назвать дружелюбным. Возможно, также будет раздражать каждый раз устанавливать положение разделителя в SplitPane или вводить одни и те же параметры фильтра. Однако, не каждая программа запомнит положение этой колонки и в следующем сеансе отобразит ее именно на том же месте. Как правило, такие удобства приходится обеспечивать самим разработчикам.

Ни тот, ни другой способ не является простым в реализации, к тому же на каждый компонент необходимо будет писать свой компонент-адаптер. Примеров таких на первый взгляд маленьких доработок множество, но предлагаемых платформой решений всего два, и по сути они похожи: создать свой компонент на основе базового, создать свой Skin к базовому компоненту, переопределив поведение. Я встречал не мало людей, кому этот способ был более знаком и понятен.

Что, если взять возможности платформы, которая поддерживает шаблон обозреватель для дочерних Node, и при добавлении или удалении подграф Node прогонять через набор плагинов, каждый из которых занимается своей специфической работой? Но он далеко не единственный. Кто-то из них добавляет три точки в конце текста, если он не умещается, а при наведении мыши показывает подсказку с полным текстом, только если он не уместился. Один умеет все запоминать и восстанавливать при повторном сеансе, другой — указанным компонентам меняет контекстное меню, добавляя функцию копирования текста. Все что нам в таком случае надо — научить плагин работать с нужными компонентами при необходимости по разному. Самое главное, что не важно из какой библиотеки этот компонент, можем ли мы от него наследоваться и переопределить нужное нам поведение.

Таким мог бы быть слушатель коллекции дочерних элементов:

private final ListChangeListener changeListener = (ListChangeListener<Node>) (ListChangeListener.Change<? extends Node> c) -> };

Таким бы — код обработки каждой измененной Node-ы:

private void applySettingsForNodeAndAddListenerForItsChild(Node n) { if (!checkApplySettings(n)) { apply(n); ObservableList<Node> children = getChildren(n); if (children != null) { addListnerForUpdateChildren(children); } markNodePropertyApplied(n); } }

А таким — непосредственно код вызова самого плагина, который зарегистрирован на этот тип компонент:

public Node apply(Node node) { List<SettingsPlugin> settingsPlugins = settingsMap.get(Node.class); if (settingsPlugins != null) { for (SettingsPlugin plugin : settingsPlugins) { node = plugin.apply(node, userSettings.getSettings()); } } List<SettingsPlugin> settingList = settingsMap.get(node.getClass()); if (settingList != null) { for (SettingsPlugin plugin : settingList) { node = plugin.apply(node, userSettings.getSettings()); } } return node; }

Вот интерфейс самого плагина:

public interface SettingsPlugin { public Node apply(Node node, Map<String, Object> userSettings);
}

Необходимо только на коллекции дочерних элементов Root элемента Scene один раз зарегистрировать слушателя, а на остальном подграфе он зарегистрируется сам...

Было бы интересно узнать, как подобный функционал можно реализовать на разных фреймворках. Последнее время провожу аналогию по возможностям платформ для настольных и веб приложений.

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть