Layouts with constraint classes

Daniel Zwolenski zonski at gmail.com
Sat Dec 1 02:57:37 PST 2012


I've slapped up two examples for you - they are pretty rough and could be
cleaned up, but it's just to demonstrate.


*Example 1* is basically how you requested it.

The FXML looks like this:


    <HBox fx:id="hbox1">
        <constraints>
            <HBoxConstraints forNode="myLabel" hgrow="ALWAYS"/>
        </constraints>
        <Label fx:id="myLabel" text="I'm a Label"
style="-fx-background-color:green" maxWidth="10000"/>
    </HBox>

    <HBox fx:id="hbox2">
        <constraints>
            <HBoxConstraints forNode="myLabel" hgrow="NEVER"/>
        </constraints>
        <!-- label will get moved here -->
    </HBox>


For the full FXML see:
http://code.google.com/p/zenjava-playtime/source/browse/trunk/layouts/src/main/resources/fxml/example1.fxml
(Note
that I defined the Animation in the FXML, but this is totally optional, you
could define it in the controller).

This needed a fair few support classes because you have to create new
builders for the layout manager. If this was a common use case then you
could put all the customised builders and constraint classes in something
like JFXtras for shared reuse.

Main support class is the HBoxBuilder:
http://code.google.com/p/zenjava-playtime/source/browse/trunk/layouts/src/main/java/com/playtime/layouts/example1/CustomHBoxBuilder.java

(strangely extending the default HBoxBuilder didn't work with FXML - not
sure if I was just doing something dumb, I didn't look into it deeper)

Other support classes are all in the same package:
http://code.google.com/p/zenjava-playtime/source/browse/trunk/layouts/src/main/java/com/playtime/layouts/example1/


*Example 2* is where the animation itself defines the constraints (as per
my suggestion). This one feels more natural to me as the animation knows
context and could decide to use a different layout depending on what action
was picked. In the animation dance there is the source parent, the target
parent and the node being moved. All of these are 'passive' and only the
animation does the "action" and really knows that there is a move happening
and why it is happening so in my book it is the one that should make
decisions about how the node looks when it is moved. That's a subjective
opinion though and you have both options to choose from.

The FXML looks like this

    <HBox fx:id="hbox1">
        <Label fx:id="myLabel" text="I'm a Label"
style="-fx-background-color:green" HBox.hgrow="ALWAYS" maxWidth="10000"/>
    </HBox>

    <HBox fx:id="hbox2">
        <!-- label will get moved here -->
    </HBox>

    <fx:define>
        <MoveAnimation fx:id="moveForwardAnimation" node="$myLabel"
newParent="$hbox2">
            <HBoxConstraints hgrow="NEVER"/>
        </MoveAnimation>
        <MoveAnimation fx:id="moveBackAnimation" node="$myLabel"
newParent="$hbox1">
            <HBoxConstraints hgrow="ALWAYS"/>
        </MoveAnimation>
    </fx:define>

There are considerably fewer/simpler support classes for this. The only
really interesting one is this:

http://code.google.com/p/zenjava-playtime/source/browse/trunk/layouts/src/main/java/com/playtime/layouts/example2/MoveAnimation.java

As a side note, the JFX animation/transition classes being final make the
code a little messier. This is one area where I would vote for relaxing the
use of 'final' - extending transitions makes as much sense as extending
Nodes in my book. We can already extend Transition so I don't see why we
can't extend SequentialTransition for example.

I hope this time I got it right and that solves your use case. My main
point though is that pretty much all of this sort of stuff *should* be
possible through the use of builders and support classes. The glue may not
always be the nicest but the driving force should be to keep the FXML and
Java clean without compromising each other - the mess should be in the glue
because only the glue author sees that, not the end user of the API, that's
why the glue exists in the first place.





On Sat, Dec 1, 2012 at 6:47 PM, Tom Eugelink <tbee at tbee.org> wrote:

> Yes, correct :-)
>
> The approach where the constraint is set in the animation feels procedural
> and not declarative to me. Like you say yourself, I think it should be
> define like: when node X is part of this layout, use these constraints. In
> this way it is not relevant where the animation is defined or how the node
> got there.
>
> Tom
>
>
>
> On 2012-12-01 08:38, Daniel Zwolenski wrote:
>
>> Ah ok, so in the first hbox you are saying when the "arrow" node is moved
>> into here use these new constraints. I think I've got you now.
>>
>> That should be do-able using some more helper classes. I can knock some
>> up but my first thought would be to do it as part of the animation since
>> its the thing that has the most knowledge about what's going on and why.
>>
>> How/where do you define and trigger your animation - are you specifying
>> it in the FXML? If so the constraints could be part of that eg. (made up
>> pseudo FXML):
>>
>> <MoveAnimation nodeToMove="arrow" moveTo="hbox1">
>>     <NewConstraints>
>>
>>> <HBox.C vgrow="NEVER" valignment="RIGHT"/>
>>>
>>     </NewConstraints>
>> </MoveAnimation>
>>
>> (also slightly confusing is that the constraints you are using aren't
>> applicable to HBox)
>>
>> If you don't like that approach I can knock up the alternative?
>>
>>
>>
>> On 01/12/2012, at 6:17 PM, Tom Eugelink <tbee at tbee.org> wrote:
>>
>>  Because of animation the label may move from one HBox to the other. This
>>> is the reason why the current approach stores constraints inside the node,
>>> so that when it moves from layout A to B, the constraints also move. My
>>> approach allows to specify different constraints for the same node in each
>>> layout.
>>>
>>> You are right that there should be a parent layout, I left it out to not
>>> confuse things, but apparently that is confusing :-)
>>>
>>> <VBox>
>>>     <HBox>
>>>        <HBox.C for="arrow" vgrow="NEVER" valignment="RIGHT"/>
>>>     </HBox>
>>>
>>>     <HBox>
>>>        <Label  fx:id="arrow"  alignment="center" text="">
>>>            <HBox.C vgrow="ALWAYS"  valignment="LEFT"
>>> maxWidth="Infinity"/>
>>>        <Label>
>>>     </HBox>
>>> </VBox>
>>>
>>>
>>>
>>> On 2012-12-01 08:01, Daniel Zwolenski wrote:
>>>
>>>> You've lost me. What are you expecting  the actual view to look like
>>>> with this FXML?
>>>>
>>>> If I interpret it literally you've defined two HBox's one after the
>>>> other. The first one has no children and an unused constraint, the second
>>>> one has a Label in it with a constraint on it. I'm guessing you are trying
>>>> to do something more but it's not real clear what that more is?
>>>>
>>>>
>>>>
>>>> On 01/12/2012, at 5:28 PM, Tom Eugelink <tbee at tbee.org> wrote:
>>>>
>>>>  Not variables, but references. There are constraints specified for
>>>>> nodes that are not yet part of a layout (or even exist at that time,
>>>>> because they are declared further down). Note the absense of a label in the
>>>>> first HBox.C.
>>>>>
>>>>> <HBox>
>>>>>     <HBox.C for="arrow" vgrow="NEVER"  valignment="RIGHT"/>
>>>>> </HBox>
>>>>>
>>>>> <HBox>
>>>>>     <Label  fx:id="arrow"  alignment="center" text="">
>>>>>         <HBox.C vgrow="ALWAYS"  valignment="LEFT" maxWidth="Infinity"/>
>>>>>     <Label>
>>>>> </HBox>
>>>>>
>>>>>
>>>>> Tom
>>>>>
>>>>>
>>>>> On 2012-11-30 14:11, Daniel Zwolenski wrote:
>>>>>
>>>>>> Ah ok, from your example code it looks like you want to use variables
>>>>>> in FXML to define your constraints - getting into that territory of
>>>>>> CSS-like style definitions that Richard was talking about?
>>>>>>
>>>>>> Assuming this is what you want, this can be done in the current setup
>>>>>> using the ridiculously under-documented <fx:define> thing.
>>>>>>
>>>>>> I knocked up a very rough sample for you quickly. The FXML looks like
>>>>>> this:
>>>>>>
>>>>>>   <BorderPane xmlns:fx="http://javafx.com/**fxml<http://javafx.com/fxml>
>>>>>> ">
>>>>>>
>>>>>>     <fx:define>
>>>>>>         <HBoxConstraints fx:id="noGrow" hgrow="NEVER"/>
>>>>>>         <HBoxConstraints fx:id="growLots" hgrow="ALWAYS"/>
>>>>>>     </fx:define>
>>>>>>
>>>>>>     <center>
>>>>>>         <HBox>
>>>>>>             <Label text="I don't grow" style="-fx-background-color:**green"
>>>>>> Constraints.constraints="$**noGrow"/>
>>>>>>             <Label text="I grow big" style="-fx-background-color:**yellow"
>>>>>> Constraints.constraints="$**growLots"/>
>>>>>>         </HBox>
>>>>>>     </center>
>>>>>>
>>>>>>   </BorderPane>
>>>>>>
>>>>>> (see https://code.google.com/p/**zenjava-playtime/source/**
>>>>>> browse/trunk/layouts/src/main/**resources/fxml/example.fxml<https://code.google.com/p/zenjava-playtime/source/browse/trunk/layouts/src/main/resources/fxml/example.fxml>
>>>>>> )
>>>>>>
>>>>>> I made a base Constraints class with a static helper method on it
>>>>>> (called via "Constraints.constraints" in the FXML above):
>>>>>> https://code.google.com/p/**zenjava-playtime/source/**
>>>>>> browse/trunk/layouts/src/main/**java/com/playtime/layouts/**
>>>>>> Constraints.java<https://code.google.com/p/zenjava-playtime/source/browse/trunk/layouts/src/main/java/com/playtime/layouts/Constraints.java>
>>>>>>
>>>>>> And then a specific instance of HBoxConstraints:
>>>>>> https://code.google.com/p/**zenjava-playtime/source/**
>>>>>> browse/trunk/layouts/src/main/**java/com/playtime/layouts/**
>>>>>> HBoxConstraints.java<https://code.google.com/p/zenjava-playtime/source/browse/trunk/layouts/src/main/java/com/playtime/layouts/HBoxConstraints.java>
>>>>>>
>>>>>> Obviously you would add others, like VBoxConstraints,
>>>>>> GridPaneConstraints, etc. All pretty trivial. These helper classes could
>>>>>> easily be included in something like JFXtras.
>>>>>>
>>>>>> So I stick with the stance that FXML is more or less OK here (not to
>>>>>> say I wouldn't improve it lots in other areas), and really your
>>>>>> conversation is about the Java API which is nicely decoupled to what
>>>>>> can/can't be done in FXML. Kudos to Richard and the JFX team for designing
>>>>>> the builders right.
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>> On Fri, Nov 30, 2012 at 9:20 PM, Tom Eugelink <tbee at tbee.org <mailto:
>>>>>> tbee at tbee.org>> wrote:
>>>>>>
>>>>>>     On 2012-11-30 10:59, Daniel Zwolenski wrote:
>>>>>>
>>>>>>         It just doesn't do it the exact way you suggest where you
>>>>>> specify multiple possibilities directly in the child in case it ends up in
>>>>>> a different parent - not an approach I agree with anyway (see my previous
>>>>>> comments), but that's just my opinion.
>>>>>>
>>>>>>
>>>>>>     Just to make sure my suggestion is not misunderstood, it does not
>>>>>> specify multiple possibilities in the child, but in the layout.
>>>>>>
>>>>>>     <HBox>
>>>>>>         <HBox.C for="arrow" vgrow="NEVER"  valignment="RIGHT"/>
>>>>>>     </HBox>
>>>>>>
>>>>>>     <HBox>
>>>>>>         <Label  fx:id="arrow"  alignment="center" text="">
>>>>>>             <HBox.C vgrow="ALWAYS"  valignment="LEFT"
>>>>>> maxWidth="Infinity"/>
>>>>>>         <Label>
>>>>>>     </HBox>
>>>>>>
>>>>>>
>>>>>>
>


More information about the openjfx-dev mailing list