On Thu, 15 Jan 2026 03:11:11 GMT, Michael Strauß <[email protected]> wrote:

> In the following program, resizing the window to be smaller than 300px should 
> start a transition for `-fx-scale-x` from 2 to 1, but instead the value 
> sometimes snaps back to 1 instantly:
> 
> 
> public class InterruptedTransitionBug extends Application {
>     @Override
>     public void start(Stage stage) throws Exception {
>         var root = new StackPane(new Button("My Button"));
>         var scene = new Scene(root, 600, 200);
>         scene.getStylesheets().add("data:text/css;base64," + 
> Base64.getEncoder().encodeToString("""
>             .button {
>                 transition: -fx-scale-x 2s;
>             }
> 
>             @media (width > 300px) {
>                 .button {
>                     -fx-scale-x: 2;
>                 }
>             }
>             """.getBytes(StandardCharsets.UTF_8)));
>         stage.setScene(scene);
>         stage.show();
>     }
> }
> 
> 
> ### Problem
> First, let's look at how `CssStyleHelper` works when the cascading style map 
> for a node changes:
> 1. When the style map for a node has changed, 
> `StyleHelper.createStyleHelper(Node)` determines that the style helper is no 
> longer any good, and a new `CssStyleHelper` for the new style map is created.
> 2. Before the old style helper is discarded, it calls 
> `CssStyleHelper.resetToInitialValues(Styleable)` and resets all properties 
> that were set by this style helper back to their initial values. This ensures 
> that the new style helper has a "clean slate" to work from.
> 3. The next `Node.applyCss()` pass will now set the properties that are 
> specified in the new style map to their new values.
> 
> However, when transitions come into play, this mechanism can break:
> 1. In our example, the `Button` starts with a style map that contains two 
> properties:
>    * `transition: -fx-scale-x 2s`
>    * `-fx-scale-x: 2`
> 2. Due to a changing media query, this is replaced with a style map that only 
> contains a single entry:
>    * `transition: -fx-scale-x 2s`
> 3. Before the new style map is applied, all properties affected by the old 
> style map are reset to their initial values. That means:
>    * `-fx-scale-x` is reset to `1`
>    * `transition` is reset to `null`
> 
> This is where it breaks: if `transition` is reset before `-fx-scale-x`, the 
> latter will see no transition when its value is set back to `1`.
> 
> ### Solution
> Simply resetting all properties back to their initial values when a style map 
> is changed is not necessary. We only need to reset the properties that are 
> set by the old style map, but are no longer set by the new style map. In our 
> example, si...

Marked as reviewed by angorya (Reviewer).

modules/javafx.graphics/src/main/java/javafx/css/StyleableBooleanProperty.java 
line 57:

> 55:         StyleablePropertyHelper.setBooleanAccessor(new 
> StyleablePropertyHelper.Accessor() {
> 56:             @Override
> 57:             public boolean 
> equalsAfterChangeStyleValue(StyleableProperty<?> property, Object value) {

minor: would it be slightly more organized to call a private instance method of 
the property class from each accessor?

I think the code is ok, it's just adds so much nearly identical code that 
bothers me, though I can't figure out a way to avoid the `Accessor` pattern 
here, package protected methods would not work, would they?

-------------

PR Review: https://git.openjdk.org/jfx/pull/2038#pullrequestreview-3667269954
PR Review Comment: https://git.openjdk.org/jfx/pull/2038#discussion_r2695711152

Reply via email to