[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