[ListView] `b.bind(a)` not behaviorally equivalent to `a.addListener(o -> b.set(a.get()))`
Anthony Petrov
anthony.petrov at oracle.com
Mon Dec 16 11:37:53 PST 2013
Filing a bug never hurts. We'll either fix it, or close it and explain
why it's not a bug then.
--
best regards,
Anthony
On 12/13/2013 11:17 PM, Tomas Mikula wrote:
> 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