tag:blogger.com,1999:blog-1384568905914541279.post723606744783385753..comments2023-10-17T12:04:47.943+02:00Comments on John the coding Architect: Nested or dependant JavaFx PropertiesJohannes Rupprechthttp://www.blogger.com/profile/05105001725580078625noreply@blogger.comBlogger8125tag:blogger.com,1999:blog-1384568905914541279.post-45696778476230470022016-06-16T13:05:24.643+02:002016-06-16T13:05:24.643+02:00Hello,
you are completely right. We fixed that by ...Hello,<br />you are completely right. We fixed that by adding a instance reference to the listener:<br /><br />public class NestedObjectProperty extends SimpleObjectProperty {<br /> /**<br /> * Listener to the dependand property<br /> */<br /> @SuppressWarnings("FieldCanBeLocal") //mustn't be lokal due to the WeakChangeListener...<br /> private final ChangeListener listener;<br /> /**<br /> * The binding partner of this instance<br /> */<br /> private Property boundProperty;<br /><br /> /**<br /> * Creates a new instance<br /> * @param dependandProperty the property that delivers the property to bind against<br /> * @param getFunc a {@link java.util.function.Function} of D and ObjectProperty of T<br /> * @param bidirectional boolean flag, if the binding should be bidirectional or unidirectional<br /> */<br /> public NestedObjectProperty(ObservableValue dependandProperty, final Function> getFunc, boolean bidirectional) {<br /> bindDependandProperty(dependandProperty.getValue(), getFunc, bidirectional);<br /><br /> listener = (observable, oldValue, newValue) -> {<br /> if (boundProperty != null) {<br /> if (bidirectional) {<br /> unbindBidirectional(boundProperty);<br /> } else {<br /> unbind();<br /> }<br /> boundProperty = null;<br /> }<br /> bindDependandProperty(newValue, getFunc, bidirectional);<br /> };<br /> dependandProperty.addListener(new WeakChangeListener<>(listener));<br /> }<br /><br /> /**<br /> * Binds this instance to the dependant property<br /> * @param newValue D<br /> * @param getFunc Function> getFunc, boolean bidirectional) {<br /> if (newValue != null) {<br /> Property newProp = getFunc.apply(newValue);<br /> boundProperty = newProp;<br /> if (newProp != null) {<br /> if (bidirectional){<br /> bindBidirectional(newProp);<br /> }else{<br /> bind(newProp);<br /> }<br /> }else{<br /> set(null);<br /> }<br /> }else{<br /> set(null);<br /> }<br /> }<br />}<br /><br />Best regards,<br />JohnJohannes Rupprechthttps://www.blogger.com/profile/05105001725580078625noreply@blogger.comtag:blogger.com,1999:blog-1384568905914541279.post-53368112282416379242016-06-15T19:38:22.590+02:002016-06-15T19:38:22.590+02:00Hi,
thanks for your work. I know this post is old ...Hi,<br />thanks for your work. I know this post is old but it's still in the top google search results for "javafx nested properties" so I thought I'd point out a problem I encountered.<br />In line 35 you pass a WeakChangeListener with a lambda to the addListener method but nothing stops the GC from collecting the lambda because there is no strong reference to it. In my program the binding suddenly stopped working after a short period of time. So I ended up creating a change listener member method and passing a method reference instead of the lambda.<br /><br />public NestedObjectProperty(ObservableValue dependentProperty, final Function> getFunction, boolean bidirectional) {<br /> this.getFunction = getFunction;<br /> this.bidirectional = bidirectional;<br /> bindDependentProperty(dependentProperty.getValue());<br /> dependentProperty.addListener(this::onDependentPropertyChanged);<br />}<br /><br />private void onDependentPropertyChanged(ObservableValue observable, D oldValue, D newValue) {<br /> // ... <br />}<br /><br />For my program it's okay to keep the observer alive because the observer and the observable have the same lifetime. But one should probably add a close/dispose method that removes the change listener.Anonymoushttps://www.blogger.com/profile/01374722170290682724noreply@blogger.comtag:blogger.com,1999:blog-1384568905914541279.post-45849859921066571752013-12-10T11:03:09.811+01:002013-12-10T11:03:09.811+01:00Hi Johannes,
I had the same issue.
And I do not ...Hi Johannes,<br /><br />I had the same issue.<br /><br />And I do not want to work with select in production mode for the raison you said before.<br /><br />I work on a low level binding named FXBinding ( https://github.com/dooApp/FXBinding )<br /><br />Feel free to test.<br /><br />Christophe.Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-1384568905914541279.post-55714286144361639752013-11-26T12:26:15.015+01:002013-11-26T12:26:15.015+01:00You are right, I already tried this, it works, but...You are right, I already tried this, it works, but the constructor is not optimized for deeper nesting. The use case was a property of a property. Maybe you could optimize my class to do this more nicely for deeper nesting.Johannes Rupprechthttps://www.blogger.com/profile/05105001725580078625noreply@blogger.comtag:blogger.com,1999:blog-1384568905914541279.post-72447036994092241032013-11-26T08:20:22.757+01:002013-11-26T08:20:22.757+01:00Oh yeah, now it makes perfectly sens. Thanks.
But...Oh yeah, now it makes perfectly sens. Thanks.<br /><br />But something like “selectedCustomer.get().addressProperty().get().streetProperty()” would only be possible if I start to nest the “NestedObjectProperty” like this:<br /><br />ObjectProperty<Customer> selectedCustomer =...;<br />ObjectProperty<Address> selectedAddress = new NestedObjectProperty<>(selectedCustomer, (Customer customer)-> customer.addressProperty(), false);<br />ObjectProperty<String> selectedStreet = new NestedObjectProperty<>(selectedAddress, (Address address)-> address.streetProperty(), false);<br /><br />// or in one line:<br />ObjectProperty<String> selectedStreetOneLine = new NestedObjectProperty<>(new NestedObjectProperty<>(selectedCustomer, (Customer customer)-> customer.addressProperty(), false), (Address address)-> address.streetProperty(), false );<br /><br />Is this correct?JavaFX-Learnerhttps://www.blogger.com/profile/12235849505747961900noreply@blogger.comtag:blogger.com,1999:blog-1384568905914541279.post-46764025462625504012013-11-25T20:26:58.172+01:002013-11-25T20:26:58.172+01:00Good point. There are two reasons:
Using Bindings....Good point. There are two reasons:<br />Using Bindings.select returns a Binding implementation, no property. So you cannot make a bidirectional binding. <br />And the other disadvantage from my point of view is, that you pass the names of the properties as Strings. So if you make a refactoring, this may break. In my example you pass a Function which is implemented with direct use of the methods, no reflection is used. In my tests with JDK 8 it also logged a NullPointerException when setting one props in the chain to null. But of course you can use that, if it fits your needs!Johannes Rupprechthttps://www.blogger.com/profile/05105001725580078625noreply@blogger.comtag:blogger.com,1999:blog-1384568905914541279.post-70202692720144539242013-11-25T08:23:36.988+01:002013-11-25T08:23:36.988+01:00Hi,
nice idea, but why do you not use: javafx.bea...Hi,<br /><br />nice idea, but why do you not use: javafx.beans.binding.Bindings#select(ObservableValue, String ...) ?<br /><br />Regards<br /> JavaFX-LearnerJavaFX-Learnerhttps://www.blogger.com/profile/12235849505747961900noreply@blogger.comtag:blogger.com,1999:blog-1384568905914541279.post-70442950666126383722013-11-25T08:20:36.260+01:002013-11-25T08:20:36.260+01:00Dieser Kommentar wurde vom Autor entfernt.JavaFX-Learnerhttps://www.blogger.com/profile/12235849505747961900noreply@blogger.com