📜 ⬆️ ⬇️

Plugin Team for Customizing JavaFX Components in a Desktop Application

It is always pleasant to communicate with an application that remembers your habits and seems to feel you, what you want. Any UI library or platform has, alas, only basic functionality and a set of components. For example, if a column in a table does not move or cannot be sorted by it, then the application in which it is used can hardly be called friendly. Fortunately, today you won't surprise anyone with this functionality. However, not every program will remember the position of this column and in the next session will display it in exactly the same place. It may also be annoying to set the splitter position in the SplitPane each time or to enter the same filter parameters. As a rule, such conveniences have to be provided by the developers themselves.


There are only two examples of such minor improvements at first glance, but there are only two solutions offered by the platform, and in fact they are similar: create your component based on the base one, create your Skin to the base component, redefining the behavior. Neither method is simple to implement, moreover, each component will need to write its own adapter component. I met quite a few people to whom this method was more familiar and understandable.


But he is not the only one. What if we take the capabilities of a platform that supports the browser template for child Node , and when adding or removing a subgraph of Node, run through a set of plug-ins, each of which is engaged in its specific work? One is able to memorize and restore everything during a repeated session, the other changes the context menu to the specified components, adding the function of copying text. Some of them add three dots at the end of the text, if it does not fit, and when you hover the mouse shows a hint with the full text, only if it does not fit. The most important thing is that it does not matter from which library this component is, whether we can inherit from it and redefine the behavior we need. All we need in this case is to teach the plugin how to work with the necessary components, if necessary, in different ways.


This could be a listener for a collection of child elements:


private final ListChangeListener changeListener = (ListChangeListener<Node>) (ListChangeListener.Change<? extends Node> c) -> { if (c.next()) { c.getAddedSubList().forEach(this::applySettingsForNodeAndAddListenerForItsChild); } }; 

This would be the processing code for each modified Node :


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

And such is the call code of the plugin itself, which is registered to this type of component:


 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; } 

Here is the interface of the plugin itself:


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

It is necessary only to register the listener once on the Scene element's Root child element collection, and on the rest of the subgraph it will register itself ...


Recently, I am drawing an analogy on the capabilities of platforms for desktop and web applications. It would be interesting to learn how such functionality can be implemented on different frameworks.


')

Source: https://habr.com/ru/post/422693/


All Articles