Plugin Team for Customizing JavaFX Components in a Desktop Application

    It is always pleasant to communicate with an application that remembers your habits and feels like 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 an application in which it is used can hardly be called friendly. Fortunately, today you will not 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 annoy each time to set the position of the splitter in the SplitPane 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 Noderun 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:


    privatefinal 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 :


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

    And so - directly 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:


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

    It is only necessary on the collection of child elements of the Root element Scene once to register the listener, while the remaining subgraph he registers himself ...


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


    Also popular now: