JavaFX object traits

John Hendrikx john.hendrikx at gmail.com
Fri Sep 8 09:30:49 UTC 2023


I think the interfaces may expose things that have been developed 
independently with different names but are the same thing.

For example, Window has the `showing` property, but effectively it works 
similar to `visible`.  The split between `Disable` and `Disabled` should 
be removed IMHO by making `MenuItem` implement `disabled` -- in other 
words, don't introduce two interfaces where one is desired.

The same goes for Properties and UserData; these serve a similar purpose 
and should IMHO be one interface.

Most of the names violate the "is-a" rule for interface naming, which 
will make code using it akward to read.  A suffic `Accessor` works 
pretty well, but for some there are perhaps nicer solutions; suggestions 
on that front:

     Disable/Disabled -> Disableable (dictionary: capable of being disabled)

     Properties/UserData -> UserPropertyAccessor

     Title -> Titled

     Text -> there's actually `Labeled` for that already, although done 
differently

     Visible -> tough one... Visualizable, Showable, VisibleAccessor

--John

On 08/09/2023 06:36, Michael Strauß wrote:
> So far, I've identified these interfaces for the javafx.graphics module:
>
> Visible:
> Node, MenuItem, TableColumnBase
>
> Disable:
> Node, MenuItem, Tab
>
> Disabled:
> Node, Tab
> (should MenuItem also have a "disabled" property? it doesn't currently)
>
> Properties:
> Window, Scene, Node, MenuItem, Tab, Toggle, ToggleGroup, TableColumnBase
>
> UserData:
> Window, Scene, Node, MenuItem, Tab, Toggle, ToggleGroup, TableColumnBase
>
> Visible, Disable, and Disabled are useful because it allows reading
> and managing some basic visual state of UI components.
> Properties and UserData provide a common interface for objects that
> can store arbitrary data.
>
> Here are some interfaces that I would find questionable for the
> javafx.graphics module:
>
> Title:
> Stage, DirectoryChooser, FileChooser
>
> Text:
> javafx.scene.text.Text, TextInputControl, Labeled, Tab, MenuItem,
> TableColumnBase, Tooltip, Legend
>
> Note: the "Text" interface might also belong to javafx.controls, but
> then javafx.scene.text.Text couldn't implement it.
>
>
> On Fri, Sep 8, 2023 at 3:07 AM Nir Lisker <nlisker at gmail.com> wrote:
>> I do something very similar in my own projects where I "decompose" my entities into such interfaces. I find it beneficial.
>>
>> We do need to figure out which makes sense and for what purpose.
>>
>> On Wed, Sep 6, 2023, 22:41 Andy Goryachev <andy.goryachev at oracle.com> wrote:
>>> I think this proposal makes a lot of sense.
>>>
>>>
>>>
>>> Having the trait interfaces inner classes of Trait clearly narrows down semantics.  "Trait" might be too generic, maybe FxTrait or something like that?  Just a thought.
>>>
>>>
>>>
>>> What other traits/properties should we include?
>>>
>>>
>>>
>>> Converting https://github.com/openjdk/jfx/pull/1215 to draft until this discussion comes to a resolution.
>>>
>>>
>>>
>>> -andy
>>>
>>>
>>>
>>>
>>>
>>> From: openjfx-dev <openjfx-dev-retn at openjdk.org> on behalf of Michael Strauß <michaelstrau2 at gmail.com>
>>> Date: Saturday, September 2, 2023 at 15:09
>>> To: openjfx-dev <openjfx-dev at openjdk.org>
>>> Subject: JavaFX object traits
>>>
>>> There's a proposal to add a common interface that identifies JavaFX
>>> objects that can hold an Observable<Object, Object> property map:
>>> https://github.com/openjdk/jfx/pull/1215
>>>
>>> The reason for this is obvious: allow JavaFX objects that can hold
>>> properties to be consumed by code without depending on brittle
>>> `instanceof` checks. The problem is real, but I think we can do much
>>> better than that.
>>>
>>> Why have a common interface at all? Well, of course it allows
>>> consumers to treat different objects in a uniform way. But there's
>>> more to it: the interface specifies the _meaning_ of the method; it
>>> guarantees that `Foo::getProperties` and `Bar::getProperties` are, in
>>> fact, not only methods with the same name, but the same semantics.
>>>
>>> `getProperties` and `hasProperties` is one example of such commonality
>>> between dissimilar classes like `Node` and `MenuItem`. But I've come
>>> across other examples in my own projects. For example, I'd like to
>>> consume JavaFX objects that have the `visible` and `disable`
>>> properties. Other applications will have different use cases, but
>>> since we don't know all possible use cases, it's hard to come up with
>>> a set of useful combinations of properties and methods.
>>>
>>> However, I think we can use the Java type system to allow applications
>>> to compose types that fit their unique use case.
>>>
>>> We begin by identifying common properties, and create trait interfaces
>>> that describe those properties:
>>>
>>>      public final class javafx.scene.Trait {
>>>          public interface Visible {
>>>              BooleanProperty visibleProperty()
>>>              default boolean isVisible()...
>>>              default void setVisible(boolean value)...
>>>          }
>>>          public interface Disable {
>>>              BooleanProperty disableProperty()
>>>              default boolean isDisable()...
>>>              default void setDisable(boolean value)...
>>>          }
>>>          public interface Properties {
>>>              ObservableMap<Object, Object> getProperties()
>>>              default boolean hasProperties()...
>>>          }
>>>          ...
>>>      }
>>>
>>> These interfaces can now be implemented by all relevant JavaFX
>>> classes. This includes `Node`, `MenuItem`, and `Tab`, but applications
>>> are free to implement these trait interfaces themselves.
>>>
>>> Applications can now consume objects that implement any combination of
>>> traits, which gives applications the much-needed flexibility to use
>>> shared code for all kinds of JavaFX objects:
>>>
>>> <T extends Trait.Properties & Trait.Visible>
>>> void doSomething(T node) {
>>>      node.getProperties().put("foo", "bar");
>>>      node.setVisible(true);
>>> }
>>>
>>> <T extends Trait.Text & Trait.Graphic>
>>> void doAnotherThing(T node) {
>>>      node.setText("hello");
>>>      node.setGraphic(myGraphic);
>>> }
>>>
>>> What do you think?


More information about the openjfx-dev mailing list