Proposal: Add Skin.install() method
John Hendrikx
john.hendrikx at gmail.com
Sat Jul 23 12:48:42 UTC 2022
Configuration can be part of the factory or not?
Simple case:
control.installSkin(MySkin::new)
More complicated case:
control.installSkin(c -> {
MySkin s = new MySkin(c);
// configure stuff
return s;
});
--John
On 22/07/2022 17:58, Andy Goryachev wrote:
>
> > control.installSkin(MySkin::new);
>
> This is an interesting idea. Control.installSkin(Function<Control,Skin>).
>
> One of the requirements we ought to consider is maximizing the
> backward compatibility. If we were to add a new installSkin method it
> would not solve the problem with the old method, and replacing
> setSkin(Skin) with installSkin() would break compatibility with the
> existing code.
>
> There is one more reason to allow for creation of a skin outside of
> setSkin() - configuration. Imagine customer skins require
> configuration, in which case the sequence of events looks like this
>
> instantiation -> configuration -> uninstall old skin -> install new skin.
>
> with installSkin(MySkin::new) such a model will be impossible.
>
> Thank you
>
> -andy
>
> *From: *openjfx-dev <openjfx-dev-retn at openjdk.org> on behalf of John
> Hendrikx <john.hendrikx at gmail.com>
> *Date: *Thursday, 2022/07/21 at 15:49
> *To: *openjfx-dev at openjdk.org <openjfx-dev at openjdk.org>
> *Subject: *Re: Proposal: Add Skin.install() method
>
> Hi Andy,
>
> Was a single step install process considered, something like:
>
> control.installSkin(MySkin::new);
>
> This would also make it much more clear that Skins are single use
> only, where the API currently has to bend over backwards to make that
> clear and enforce it.
>
> Other than that, I think your suggestion would be a definite
> improvement over the current situation. Something never felt quite
> right about how skins where set up and attached to controls, it felt
> fragile and cumbersome -- possibly as the result of relying on a
> writable property as the means to install a skin.
>
> --John
>
> On 20/07/2022 23:39, Andy Goryachev wrote:
>
> Hi,
>
> I'd like to propose an API change in Skin interface (details
> below). Your feedback will be greatly appreciated!
>
> Thank you,
>
> -andy
>
> Summary
>
> -------
>
> Introduce a new Skin.install() method with an empty default
> implementation. Modify Control.setSkin(Skin) implementation to
> invoke install() on the new skin after the old skin has been
> removed with dispose().
>
> Problem
>
> -------
>
> Presently, switching skins is a two-step process: first, a new
> skin is constructed against the target Control instance, and is
> attached (i.s. listeners added, child nodes added) to that
> instance in the constructor. Then, Control.setSkin() is invoked
> with a new skin - and inside, the old skin is detached via its
> dispose() method.
>
> This creates two problems:
>
> 1. if the new skin instance is discarded before setSkin(), it
> remains attached, leaving the control in a weird state with two
> skins attached, causing memory leaks and performance degradation.
>
> 2. if, in addition to adding listeners and child nodes, the skin
> sets a property, such as an event listener, or a handler, it
> overwrites the current value irreversibly. As a result, either
> the old skin would not be able to cleanly remove itself, or the
> new skin would not be able to set the new values, as it does not
> know whether it should overwrite or keep a handler installed
> earlier (possibly by design). Unsurprisingly, this also might
> cause memory leaks.
>
> We can see the damage caused by looking at JDK-8241364
> <https://bugs.openjdk.org/browse/JDK-8241364> ☂/Cleanup skin
> implementations to allow switching/, which refers a number of bugs:
>
> JDK-8245145 Spinner: throws IllegalArgumentException when
> replacing skin
>
> JDK-8245303 InputMap: memory leak due to incomplete cleanup on
> remove mapping
>
> JDK-8268877 TextInputControlSkin: incorrect inputMethod event
> handler after switching skin
>
> JDK-8236840 Memory leak when switching ButtonSkin
>
> JDK-8240506 TextFieldSkin/Behavior: misbehavior on switching skin
>
> JDK-8242621 TabPane: Memory leak when switching skin
>
> JDK-8244657 ChoiceBox/ToolBarSkin: misbehavior on switching skin
>
> JDK-8245282 Button/Combo Behavior: memory leak on dispose
>
> JDK-8246195 ListViewSkin/Behavior: misbehavior on switching skin
>
> JDK-8246202 ChoiceBoxSkin: misbehavior on switching skin, part 2
>
> JDK-8246745 ListCell/Skin: misbehavior on switching skin
>
> JDK-8247576 Labeled/SkinBase: misbehavior on switching skin
>
> JDK-8253634 TreeCell/Skin: misbehavior on switching skin
>
> JDK-8256821 TreeViewSkin/Behavior: misbehavior on switching skin
>
> JDK-8269081 Tree/ListViewSkin: must remove flow on dispose
>
> JDK-8273071 SeparatorSkin: must remove child on dispose
>
> JDK-8274061 Tree-/TableRowSkin: misbehavior on switching skin
>
> JDK-8244419 TextAreaSkin: throws UnsupportedOperation on dispose
>
> JDK-8244531 Tests: add support to identify recurring issues with
> controls et al
>
> Solution
>
> --------
>
> This problem does not exist in e.g. Swing because the steps of
> instantiation, uninstalling the old ComponentUI ("skin"), and
> installing a new skin are cleanly separated. ComponentUI
> constructor does not alter the component itself,
> ComponentUI.uninstallUI(JComponent) cleanly removes the old skin,
> ComponentUI.installUI(JComponent) installs the new skin. We should
> follow the same model in javafx.
>
> Specifically, I'd like to propose the following changes:
>
> 1. Add Skin.install() with a default no-op implementation.
>
> 2. Clarify skin creation-attachment-detachment sequence in Skin
> and Skin.install() javadoc
>
> 3. Modify Control.setSkin(Skin) method (== invalidate listener in
> skin property) to call oldSkin.dispose() followed by newSkin.install()
>
> 4. Many existing skins that do not set properties in the
> corresponding control may remain unchanged. The skins that do,
> such as TextInputControlSkin (JDK-8268877), must be refactored to
> utilize the new install() method. I think the refactoring would
> simply move all the code that accesses its control instance away
> from the constructor to install().
>
> Impact Analysis
>
> -------------
>
> The changes should be fairly trivial. Only a subset of skins needs
> to be refactored, and the refactoring itself is trivial.
>
> The new API is backwards compatible with the existing code, the
> customer-developed skins can remain unchanged (thanks to default
> implementation). In case where customers could benefit from the
> new API, the change is trivial.
>
> The change will require CSR as it modifies a public API.
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/openjfx-dev/attachments/20220723/6f1e5c62/attachment-0001.htm>
More information about the openjfx-dev
mailing list