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 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