Re: [ListView] `b.bind(a)` not behaviorally equivalent to `a.addListener(o - b.set(a.get()))`
Never mind, b.bind(a); should not be equivalent to a.addListener(o - b.set(a.get())); in the first place, but rather to a.addListener(o - b.set(a.get())); b.set(a.get()); // don't forget this! When I fixed my example, I'm not observing any difference in behavior. I'm still not getting the behavior I want, but due to https://javafx-jira.kenai.com/browse/RT-34897. Thanks, Tomas On Mon, Dec 16, 2013 at 8:37 PM, Anthony Petrov anthony.pet...@oracle.com wrote: 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.mik...@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 ListCellString { public MyCell(ListViewString 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) { ListViewString 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
[ListView] `b.bind(a)` not behaviorally equivalent to `a.addListener(o - b.set(a.get()))`
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 ListCellString { public MyCell(ListViewString 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) { ListViewString 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
Re: [ListView] `b.bind(a)` not behaviorally equivalent to `a.addListener(o - b.set(a.get()))`
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.mik...@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 ListCellString { public MyCell(ListViewString 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) { ListViewString 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