[ListView] `b.bind(a)` not behaviorally equivalent to `a.addListener(o -> b.set(a.get()))`

Tomas Mikula tomas.mikula at gmail.com
Fri Dec 13 11:17:21 PST 2013


I guess my main question is: should I file a bug on ListView?

Tomas

On Fri, Dec 13, 2013 at 8:15 PM, Tomas Mikula <tomas.mikula at gmail.com> wrote:
> I just came across a strange case when these two are not equivalent.
> Maybe that is no surprise to you, but it was to me. The case I
> stumbled upon most likely has to do with ListView internals.
>
> Substitute
> a := ListView.widthProperty()
> b := ListCell.prefWidthProperty()
>
> and the code that demonstrates the difference:
>
>
> public class Test extends Application {
>
>     private static class MyCell extends ListCell<String> {
>         public MyCell(ListView<String> lv) {
>             setMaxWidth(Region.USE_PREF_SIZE);
>
>             // !!! comment out exactly one of the following
>             // !!! two lines to demonstrate the difference
>             prefWidthProperty().bind(lv.widthProperty());
>             lv.widthProperty().addListener(o -> setPrefWidth(lv.getWidth()));
>         }
>
>         @Override
>         protected void updateItem(String item, boolean empty) {
>             super.updateItem(item, empty);
>             setGraphic(empty ? null : new TextFlow(new Text(item)));
>         }
>     }
>
>     @Override
>     public void start(Stage stage) {
>         ListView<String> listView = new ListView<>();
>         listView.setCellFactory(lv -> new MyCell(lv));
>         listView.getItems().add("This is a very long line that needs
> to be wrapped");
>
>         StackPane stack = new StackPane();
>         stack.getChildren().add(listView);
>         Scene scene = new Scene(stack, 200, 100);
>         stage.setScene(scene);
>         stage.show();
>     }
>
>     public static void main(String[] args) {
>         launch(args);
>     }
> }
>
>
> When I run the "bind" version, the text shows up wrapped.
> When I run the "addListener" version, the text shows up in one long line.
>
> Do you think this is a bug in ListView, or is there a reasonable explanation?
>
> Just for the record, I consider the "wrapping" behavior to be the correct one.
>
>
> My *speculation* about the possible cause follows:
>
> The only case I could come up with when
> A) b.bind(a)
> and
> B) a.addListener(o -> b.set(a.get()))
> are effectively different is when both of these conditions hold:
> 1) there is an invalidation listener set on b that causes b to become
> valid (e.g. calls b.get()); and
> 2) a is invalidated twice in a row, but recomputes to the same value each time.
>
> Now the scenarios for A) and B) differ:
>
> Scenario A (b.bind(a)):
>  - a is invalidated for the first time
>  - b's invalidation listener is called for the first time
>  - b is now valid
>  - a is invalidated for the second time
>  - b's invalidation listener is called for the *SECOND* time
>
> Scenario B (a.addListener(o -> b.set(a.get()))):
>  - a is invalidated for the first time
>  - b is set to a.get() = x and b's invalidation listener is called for
> the first time
>  - b is now valid
>  - a is invalidated for the second time
>  - b is set to a.get() = x and b's invalidation listener is *NOT*
> called for the second time, because b's value did not change
>
> In scenario A, b's invalidation listener is called twice, while in
> scenario B just once. If "weird things" are happening in this
> invalidation listener, this can result in different behavior.
>
> Now, if b is ListCell.prefWidthProperty(), scenario A and scenario B
> cause it to be invalidated different number of times, which, my
> *speculation*, could yield different behavior.
> This is how far I got.
>
> Cheers,
> Tomas


More information about the openjfx-dev mailing list