How to consistently dictate size for nested JavaFX controls?

I’m working on developing my programming skills and am building a UI application in JavaFX because Java is my strongest language.

Unfortunately I’ve found building the UI tedious at best using FXML. I decided to make my window a fixed size, thinking that a non-responsive UI would be easier to build for my first time.

Adding elements is easy, but getting them to be properly sized has proven very difficult, especially when layouts are nested (IE a TiledPane within an HBox). I think I’m misunderstanding how children inherit properties from their parent, or vice versa.

In my application, I’ve nested frequently because the data served to the view can take several seconds to load, and I didn’t want to burden users with frequent load screens.

For example, this is the FXML for a screen which displays data based on which button you press. My window is 1600×900. I’d like the elements in the second HBox to fill the rest of the screen, but nothing I seem to adjust causes them to grow. There are other elements I’d like to resize but I think that will be easier once I understand whatever principle I’m missing.

<VBox fx:id="detachmentView" visible="false">
                <HBox alignment="CENTER">
                    <Button fx:id="detachmentRules" text="Rules" styleClass="medium_button" onAction="#detachmentRulesButton"/>
                    <Button fx:id="detachmentStratagems" text="Stratagems" styleClass="medium_button" onAction="#detachmentStratagemButton"/>
                    <Button fx:id="detachmentEnhancements" text="Enhancements" styleClass="medium_button" onAction="#detachmentEnhancementButton"/>
                </HBox>
                <Separator/>
                <HBox>
                    <HBox maxWidth="666">
                        <VBox>
                            <Label text="Detachment Name:" styleClass="detachment_header"/>
                            <ListView fx:id="detachmentList" onMouseClicked="#detachmentListSelect" styleClass="detachment_list" prefWidth="333"/>
                        </VBox>
                        <VBox fx:id="stratagemHeader" visible="false" managed="false">
                            <Label text="Stratagem Name:"  styleClass="detachment_header"/>
                            <ListView fx:id="stratagemList" onMouseClicked="#stratagemListSelect" styleClass="detachment_list" prefWidth="333"/>
                        </VBox>
                        <VBox fx:id="enhancementHeader" visible="false" managed="false">
                            <Label text="Enhancement Name:" styleClass="detachment_header"/>
                            <ListView fx:id="enhancementList" onMouseClicked="#enhancementListSelect" styleClass="detachment_list" prefWidth="333"/>
                        </VBox>
                    </HBox>
                    <StackPane>
                        <StackPane fx:id="detachmentRulesView">
                            <VBox>
                                <Label fx:id="detachmentLabel" styleClass="detachment_header_big"/>
                                <VBox fx:id="dynamicVBox"/>
                            </VBox>
                        </StackPane>
                        <StackPane fx:id="detachmentStratagemView" visible="false">
                            <BorderPane>
                                <center>
                                    <VBox>
                                        <Label fx:id="stratagemID" styleClass="detachment_header"/>
                                        <Label fx:id="stratagemType" styleClass="detachment_header"/>
                                        <Label fx:id="stratagemCost" styleClass="detachment_header"/>
                                        <Label fx:id="stratagemPhase" styleClass="detachment_header"/>
                                        <WebView fx:id="stratagemRules" style="-fx-pref-height: 250;"/>
                                        <TextArea fx:id="stratagemLegend" wrapText="true" editable="false"/>
                                    </VBox>
                                </center>
                            </BorderPane>
                        </StackPane>
                        <StackPane fx:id="enhancementView" visible="false">
                            <BorderPane>
                                <center>
                                    <VBox>
                                        <Label fx:id="enhancementName" styleClass="detachment_header"/>
                                        <Label fx:id="enhancementCost" styleClass="detachment_header"/>
                                        <WebView fx:id="enhancementRules" style="-fx-pref-height: 250;"/>
                                        <TextArea fx:id="enhancementLegend" wrapText="true" editable="false"/>
                                    </VBox>
                                </center>
                            </BorderPane>
                        </StackPane>
                    </StackPane>
                </HBox>
            </VBox>

It yields a result like this:
FXML ELement Sizing

I have read the JavaFX documentation, several websites dedicated to JavaFX, this forum, and ChatGPT. I’ve tried adding various modifiers like prefHeight, maxHeight, minHeight, VBox.vgrow on many different parents and children for the relevant elements to no avail. I’ve used these elsewhere successfully so I’m not sure what I’m doing wrong.

It is also entirely possible that this is a crappy way to build a UI and I’ll need to refactor.

New contributor

TheOrnithologist is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.

Fixes for the immediate problem

I’d like the elements in the second HBox to fill the rest of the screen

First note that the HBox already fills the rest of the screen. You can see this if you color its background, e.g. with <HBox style='-fx-background-color:skyblue;'>

The documentation for HBox tells you how the layout strategy for the HBox works:

HBox will resize children (if resizable) to their preferred widths … .
If an hbox is resized larger than its preferred width, by default it will keep children to their preferred widths, leaving the extra space unused. If an application wishes to have one or more children be allocated that extra space it may optionally set an hgrow constraint on the child. See “Optional Layout Constraints” for details.

The two child nodes of the HBox are another HBox and a StackPane. When there is more space than these need, the HBox will just size them to their preferred sizes and leave the rest of the space empty. You can allocate extra space to the child nodes by setting the hgrow constraint, but you need to specify which node(s) get the extra space. For example, to assign it only to the StackPane, you can add HBox.hgrow="ALWAYS" to the declaration of the StackPane:

<VBox fx:id="detachmentView">
    <HBox alignment="CENTER">
        <!-- ... -->
    </HBox>
    <Separator />
    <HBox>
        <HBox maxWidth="666">
            <!-- ... -->
        </HBox>
        <StackPane HBox.hgrow="ALWAYS">
            <!-- ... -->
        </StackPane>
    </HBox>
</VBox>

You can achieve the same using a BorderPane:

<VBox fx:id="detachmentView">
    <HBox alignment="CENTER">
        <!-- ... -->
    </HBox>
    <Separator />
    <BorderPane>
        <left>
            <HBox maxWidth="666">
                <!-- ... -->
            </HBox>
        </left>
        <center>
            <StackPane>
                <!-- ... -->
            </StackPane>
        </center>
    </BorderPane>
</VBox>

This works because the layout strategy for a BorderPane allocates extra space to the center. Again, referring to the documentation:

The top and bottom children will be resized to their preferred heights and extend the width of the border pane. The left and right children will be resized to their preferred widths and extend the length between the top and bottom nodes. And the center node will be resized to fill the available space in the middle. Any of the positions may be null.

In this case, the top, bottom, and right are all null, so they all take up zero space. The <HBox> in the left takes its preferred width and the rest of the space is allocated to the <StackPane>.

How the layout system works

The package documentation for javafx.scene.layout describes the general layout mechanism.

The scene graph layout mechanism is driven automatically by the system once the application creates and displays a Scene. The scene graph detects dynamic node changes which affect layout (such as a change in size or content) and calls requestLayout(), which marks that branch as needing layout so that on the next pulse, a top-down layout pass is executed on that branch by invoking layout() on that branch’s root. During that layout pass, the layoutChildren() callback method will be called on each parent to layout its children.

In a standalone desktop application written in JavaFX, a window contains exactly one Scene. The size of the Scene is determined by the window; essentially filling all of the space in the window except for the “decorations” (title bar, window buttons, border).

The Scene has exactly one root node, of type Parent, and the root is sized to fill the whole scene, regardless of the specific Parent subtype.

When the scene is laid out, the root is assigned its size (the size of the scene), and then its layout() method is invoked, which in turn invokes its layoutChildren() method. Layout proceeds in a “top down” manner. This means the root node will query its child nodes for their preferred, minimum, and maximum sizes (if they are resizable), and allocate size and position to each of them based on the layout strategy, available space, preferred size of the child node, and any settings (such as the hgrow setting used above).

Then for each child which is also a Parent instance, layout() (and consequently layoutChildren()) is invoked on each in turn.

The upshot of all of this is that the root is allocated a size, from which it positions and sizes each immediate child node. And then having been allocated a size, each child node performs its layout.

This is actually extremely well-suited to the “nested” design you describe, and is actually designed for this set up and for responsive UIs.

The key to using this successfully is to be aware of all the pre-defined layout panes and roughly how they work. All of these are in the javafx.scene.layout package (whose documentation is linked above). There is also a tutorial.

Typically, layout panes will attempt to resize their child nodes to their preferred sizes, and most of them will respect the minimum and maximum sizes whenever possible. The documentation for each layout pane describes how its min/pref/max sizes are computed and how it uses those of its child nodes to lay them out.

Specific comments on your question and the code

Unfortunately I’ve found building the UI tedious at best using FXML.

There is no need to use FXML in a JavaFX application if you don’t want. You can create the UI entirely in Java if you prefer. There are pros and cons to using FXML:

Pros:

  • FXML is hierarchical and more naturally represents the hierarchical structure of the scene graph than Java (effectively an imperative language) does. As a consequence, there’s really only one order to place the elements in an FXML document, whereas there are many different orders of operations in Java which result in the same scene graph.
  • As a consequence of the above, it’s much easier to create UI design tools such as SceneBuilder which leverage FXML than it is for tools which generate Java code. In FXML, there’s only one way to structure the code, so it’s going to generate code the programmer has a good chance of understanding, and since there’s only one structure for a given scene graph, hand-written FXML has a much better chance of being parsed by a tool than hand-written Java would.
  • At least in theory, using FXML can encourage division of labor in team settings, where a UI designer could work with FXML without needing to know Java

Cons:

  • Using FXML does not relinquish the programmer from the burden of understanding the layout panes, their properties, and how they work, even if using a UI tool such as SceneBuilder
  • FXML is not compiled, so there is no compile-time type checking or other form of validity checking (though some IDEs can do some rudimentary checks)
  • FXML is verbose
  • If you already know Java well, using FXML requires learning a new (albeit very simple) language

I decided to make my window a fixed size, thinking that a non-responsive UI would be easier to build for my first time.

This may not be true; as mentioned above the layout mechanism is specifically designed for responsive UIs, so by using a fixed window size you’re effectively working against the API.

Avoid any hard-coded sizes, such as maxWidth="666". Just occasionally you may have an element whose max size is set to its computed (preferred) size and you might set maxWidth="Infinity" to allow it to grow, if that is the desired effect. An example of this is shown here.

Avoid using unnecessary panes. Your StackPane contains three StackPanes, each of which contains just one child node. This makes the three child StackPanes redundant. Consider replacing this:

<VBox fx:id="detachmentView">
    <HBox alignment="CENTER">
        <!-- ... -->
    </HBox>
    <Separator />
    <HBox>
        <HBox maxWidth="666">
            <!-- ... -->
        </HBox>
        <StackPane HBox.hgrow="ALWAYS">
            <StackPane fx:id="detachmentRulesView">
                <VBox>
                    <!-- -->
                </VBox>
            </StackPane>
            <StackPane fx:id="detachmentStratagemView" >
                <BorderPane>
                    <!-- -->
                </BorderPane>
            </StackPane>
            <StackPane fx:id="enhancementView" >
                <BorderPane>
                    <!-- -->
                </BorderPane>
            </StackPane>
        </StackPane>
    </HBox>
</VBox>

with

<VBox fx:id="detachmentView">
    <HBox alignment="CENTER">
        <!-- ... -->
    </HBox>
    <Separator />
    <HBox>
        <HBox maxWidth="666">
            <!-- ... -->
        </HBox>
        <StackPane HBox.hgrow="ALWAYS">
            <VBox fx:id="detachmentRulesView">
                <!-- -->
            </VBox>
            <BorderPane fx:id="detachmentStratagemView">
                <!-- -->
            </BorderPane>
            <BorderPane fx:id="enhancementView">
                <!-- -->
            </BorderPane>
        </StackPane>
    </HBox>
</VBox>

2

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa

How to consistently dictate size for nested JavaFX controls?

I’m working on developing my programming skills and am building a UI application in JavaFX because Java is my strongest language.

Unfortunately I’ve found building the UI tedious at best using FXML. I decided to make my window a fixed size, thinking that a non-responsive UI would be easier to build for my first time.

Adding elements is easy, but getting them to be properly sized has proven very difficult, especially when layouts are nested (IE a TiledPane within an HBox). I think I’m misunderstanding how children inherit properties from their parent, or vice versa.

In my application, I’ve nested frequently because the data served to the view can take several seconds to load, and I didn’t want to burden users with frequent load screens.

For example, this is the FXML for a screen which displays data based on which button you press. My window is 1600×900. I’d like the elements in the second HBox to fill the rest of the screen, but nothing I seem to adjust causes them to grow. There are other elements I’d like to resize but I think that will be easier once I understand whatever principle I’m missing.

<VBox fx:id="detachmentView" visible="false">
                <HBox alignment="CENTER">
                    <Button fx:id="detachmentRules" text="Rules" styleClass="medium_button" onAction="#detachmentRulesButton"/>
                    <Button fx:id="detachmentStratagems" text="Stratagems" styleClass="medium_button" onAction="#detachmentStratagemButton"/>
                    <Button fx:id="detachmentEnhancements" text="Enhancements" styleClass="medium_button" onAction="#detachmentEnhancementButton"/>
                </HBox>
                <Separator/>
                <HBox>
                    <HBox maxWidth="666">
                        <VBox>
                            <Label text="Detachment Name:" styleClass="detachment_header"/>
                            <ListView fx:id="detachmentList" onMouseClicked="#detachmentListSelect" styleClass="detachment_list" prefWidth="333"/>
                        </VBox>
                        <VBox fx:id="stratagemHeader" visible="false" managed="false">
                            <Label text="Stratagem Name:"  styleClass="detachment_header"/>
                            <ListView fx:id="stratagemList" onMouseClicked="#stratagemListSelect" styleClass="detachment_list" prefWidth="333"/>
                        </VBox>
                        <VBox fx:id="enhancementHeader" visible="false" managed="false">
                            <Label text="Enhancement Name:" styleClass="detachment_header"/>
                            <ListView fx:id="enhancementList" onMouseClicked="#enhancementListSelect" styleClass="detachment_list" prefWidth="333"/>
                        </VBox>
                    </HBox>
                    <StackPane>
                        <StackPane fx:id="detachmentRulesView">
                            <VBox>
                                <Label fx:id="detachmentLabel" styleClass="detachment_header_big"/>
                                <VBox fx:id="dynamicVBox"/>
                            </VBox>
                        </StackPane>
                        <StackPane fx:id="detachmentStratagemView" visible="false">
                            <BorderPane>
                                <center>
                                    <VBox>
                                        <Label fx:id="stratagemID" styleClass="detachment_header"/>
                                        <Label fx:id="stratagemType" styleClass="detachment_header"/>
                                        <Label fx:id="stratagemCost" styleClass="detachment_header"/>
                                        <Label fx:id="stratagemPhase" styleClass="detachment_header"/>
                                        <WebView fx:id="stratagemRules" style="-fx-pref-height: 250;"/>
                                        <TextArea fx:id="stratagemLegend" wrapText="true" editable="false"/>
                                    </VBox>
                                </center>
                            </BorderPane>
                        </StackPane>
                        <StackPane fx:id="enhancementView" visible="false">
                            <BorderPane>
                                <center>
                                    <VBox>
                                        <Label fx:id="enhancementName" styleClass="detachment_header"/>
                                        <Label fx:id="enhancementCost" styleClass="detachment_header"/>
                                        <WebView fx:id="enhancementRules" style="-fx-pref-height: 250;"/>
                                        <TextArea fx:id="enhancementLegend" wrapText="true" editable="false"/>
                                    </VBox>
                                </center>
                            </BorderPane>
                        </StackPane>
                    </StackPane>
                </HBox>
            </VBox>

It yields a result like this:
FXML ELement Sizing

I have read the JavaFX documentation, several websites dedicated to JavaFX, this forum, and ChatGPT. I’ve tried adding various modifiers like prefHeight, maxHeight, minHeight, VBox.vgrow on many different parents and children for the relevant elements to no avail. I’ve used these elsewhere successfully so I’m not sure what I’m doing wrong.

It is also entirely possible that this is a crappy way to build a UI and I’ll need to refactor.

New contributor

TheOrnithologist is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.

Fixes for the immediate problem

I’d like the elements in the second HBox to fill the rest of the screen

First note that the HBox already fills the rest of the screen. You can see this if you color its background, e.g. with <HBox style='-fx-background-color:skyblue;'>

The documentation for HBox tells you how the layout strategy for the HBox works:

HBox will resize children (if resizable) to their preferred widths … .
If an hbox is resized larger than its preferred width, by default it will keep children to their preferred widths, leaving the extra space unused. If an application wishes to have one or more children be allocated that extra space it may optionally set an hgrow constraint on the child. See “Optional Layout Constraints” for details.

The two child nodes of the HBox are another HBox and a StackPane. When there is more space than these need, the HBox will just size them to their preferred sizes and leave the rest of the space empty. You can allocate extra space to the child nodes by setting the hgrow constraint, but you need to specify which node(s) get the extra space. For example, to assign it only to the StackPane, you can add HBox.hgrow="ALWAYS" to the declaration of the StackPane:

<VBox fx:id="detachmentView">
    <HBox alignment="CENTER">
        <!-- ... -->
    </HBox>
    <Separator />
    <HBox>
        <HBox maxWidth="666">
            <!-- ... -->
        </HBox>
        <StackPane HBox.hgrow="ALWAYS">
            <!-- ... -->
        </StackPane>
    </HBox>
</VBox>

You can achieve the same using a BorderPane:

<VBox fx:id="detachmentView">
    <HBox alignment="CENTER">
        <!-- ... -->
    </HBox>
    <Separator />
    <BorderPane>
        <left>
            <HBox maxWidth="666">
                <!-- ... -->
            </HBox>
        </left>
        <center>
            <StackPane>
                <!-- ... -->
            </StackPane>
        </center>
    </BorderPane>
</VBox>

This works because the layout strategy for a BorderPane allocates extra space to the center. Again, referring to the documentation:

The top and bottom children will be resized to their preferred heights and extend the width of the border pane. The left and right children will be resized to their preferred widths and extend the length between the top and bottom nodes. And the center node will be resized to fill the available space in the middle. Any of the positions may be null.

In this case, the top, bottom, and right are all null, so they all take up zero space. The <HBox> in the left takes its preferred width and the rest of the space is allocated to the <StackPane>.

How the layout system works

The package documentation for javafx.scene.layout describes the general layout mechanism.

The scene graph layout mechanism is driven automatically by the system once the application creates and displays a Scene. The scene graph detects dynamic node changes which affect layout (such as a change in size or content) and calls requestLayout(), which marks that branch as needing layout so that on the next pulse, a top-down layout pass is executed on that branch by invoking layout() on that branch’s root. During that layout pass, the layoutChildren() callback method will be called on each parent to layout its children.

In a standalone desktop application written in JavaFX, a window contains exactly one Scene. The size of the Scene is determined by the window; essentially filling all of the space in the window except for the “decorations” (title bar, window buttons, border).

The Scene has exactly one root node, of type Parent, and the root is sized to fill the whole scene, regardless of the specific Parent subtype.

When the scene is laid out, the root is assigned its size (the size of the scene), and then its layout() method is invoked, which in turn invokes its layoutChildren() method. Layout proceeds in a “top down” manner. This means the root node will query its child nodes for their preferred, minimum, and maximum sizes (if they are resizable), and allocate size and position to each of them based on the layout strategy, available space, preferred size of the child node, and any settings (such as the hgrow setting used above).

Then for each child which is also a Parent instance, layout() (and consequently layoutChildren()) is invoked on each in turn.

The upshot of all of this is that the root is allocated a size, from which it positions and sizes each immediate child node. And then having been allocated a size, each child node performs its layout.

This is actually extremely well-suited to the “nested” design you describe, and is actually designed for this set up and for responsive UIs.

The key to using this successfully is to be aware of all the pre-defined layout panes and roughly how they work. All of these are in the javafx.scene.layout package (whose documentation is linked above). There is also a tutorial.

Typically, layout panes will attempt to resize their child nodes to their preferred sizes, and most of them will respect the minimum and maximum sizes whenever possible. The documentation for each layout pane describes how its min/pref/max sizes are computed and how it uses those of its child nodes to lay them out.

Specific comments on your question and the code

Unfortunately I’ve found building the UI tedious at best using FXML.

There is no need to use FXML in a JavaFX application if you don’t want. You can create the UI entirely in Java if you prefer. There are pros and cons to using FXML:

Pros:

  • FXML is hierarchical and more naturally represents the hierarchical structure of the scene graph than Java (effectively an imperative language) does. As a consequence, there’s really only one order to place the elements in an FXML document, whereas there are many different orders of operations in Java which result in the same scene graph.
  • As a consequence of the above, it’s much easier to create UI design tools such as SceneBuilder which leverage FXML than it is for tools which generate Java code. In FXML, there’s only one way to structure the code, so it’s going to generate code the programmer has a good chance of understanding, and since there’s only one structure for a given scene graph, hand-written FXML has a much better chance of being parsed by a tool than hand-written Java would.
  • At least in theory, using FXML can encourage division of labor in team settings, where a UI designer could work with FXML without needing to know Java

Cons:

  • Using FXML does not relinquish the programmer from the burden of understanding the layout panes, their properties, and how they work, even if using a UI tool such as SceneBuilder
  • FXML is not compiled, so there is no compile-time type checking or other form of validity checking (though some IDEs can do some rudimentary checks)
  • FXML is verbose
  • If you already know Java well, using FXML requires learning a new (albeit very simple) language

I decided to make my window a fixed size, thinking that a non-responsive UI would be easier to build for my first time.

This may not be true; as mentioned above the layout mechanism is specifically designed for responsive UIs, so by using a fixed window size you’re effectively working against the API.

Avoid any hard-coded sizes, such as maxWidth="666". Just occasionally you may have an element whose max size is set to its computed (preferred) size and you might set maxWidth="Infinity" to allow it to grow, if that is the desired effect. An example of this is shown here.

Avoid using unnecessary panes. Your StackPane contains three StackPanes, each of which contains just one child node. This makes the three child StackPanes redundant. Consider replacing this:

<VBox fx:id="detachmentView">
    <HBox alignment="CENTER">
        <!-- ... -->
    </HBox>
    <Separator />
    <HBox>
        <HBox maxWidth="666">
            <!-- ... -->
        </HBox>
        <StackPane HBox.hgrow="ALWAYS">
            <StackPane fx:id="detachmentRulesView">
                <VBox>
                    <!-- -->
                </VBox>
            </StackPane>
            <StackPane fx:id="detachmentStratagemView" >
                <BorderPane>
                    <!-- -->
                </BorderPane>
            </StackPane>
            <StackPane fx:id="enhancementView" >
                <BorderPane>
                    <!-- -->
                </BorderPane>
            </StackPane>
        </StackPane>
    </HBox>
</VBox>

with

<VBox fx:id="detachmentView">
    <HBox alignment="CENTER">
        <!-- ... -->
    </HBox>
    <Separator />
    <HBox>
        <HBox maxWidth="666">
            <!-- ... -->
        </HBox>
        <StackPane HBox.hgrow="ALWAYS">
            <VBox fx:id="detachmentRulesView">
                <!-- -->
            </VBox>
            <BorderPane fx:id="detachmentStratagemView">
                <!-- -->
            </BorderPane>
            <BorderPane fx:id="enhancementView">
                <!-- -->
            </BorderPane>
        </StackPane>
    </HBox>
</VBox>

2

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật