Search code examples
javajavafxresponsive-designfxml

How to create responsive desktop applications UI in JavaFx?


The problem is that i want to know how to make responsive Desktop applications in JavaFx or Java Swing (preferred in JavaFx) . When i try to resize my application frame it's components size does not grow or shrink and similar is the situation when i try to run this on different screen sizes with different screen resolutions. I have searched on this topic but could not find any solution to this. So, any reference material will also be very helpful.

I just want to know how can i add responsiveness in my desktop applications.

<?xml version="1.0" encoding="UTF-8"?>

<?import de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.PasswordField?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.text.Font?>

<StackPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="500.0" prefWidth="700.0" xmlns="http://javafx.com/javafx/20.0.1" xmlns:fx="http://javafx.com/fxml/1">
    <AnchorPane prefHeight="500.0" prefWidth="700.0">
        <AnchorPane layoutY="1.0" prefHeight="500.0" prefWidth="250.0" styleClass="left-form" stylesheets="@../../stylesheets/loginDesign.css">
            <FontAwesomeIcon fill="WHITE" glyphName="STETHOSCOPE" layoutX="68.0" layoutY="228.0" size="12em" tabSize="0" />
            <Label layoutX="11.0" layoutY="274.0" text="Pesticide Management System" textFill="WHITE">
                <font>
                    <Font name="Berlin Sans FB" size="18.0" />
                </font>
            </Label>
        </AnchorPane>
        <AnchorPane layoutX="250.0" layoutY="1.0" prefHeight="500.0" prefWidth="450.0" styleClass="right-form" stylesheets="@../../stylesheets/loginDesign.css">
            <Label layoutX="133.0" layoutY="148.0" text="Welcome, Admin!" textFill="#374151">
                <font>
                    <Font name="Berlin Sans FB" size="25.0" />
                </font>
            </Label>
            <TextField layoutX="114.0" layoutY="226.0" prefHeight="30.0" prefWidth="220.0" promptText="Username" styleClass="text-field" stylesheets="@../../stylesheets/loginDesign.css" />
            <PasswordField layoutX="115.0" layoutY="273.0" prefHeight="30.0" prefWidth="220.0" promptText="Password" styleClass="text-field" stylesheets="@../../stylesheets/loginDesign.css" />
            <Button layoutX="115.0" layoutY="334.0" mnemonicParsing="false" prefHeight="35.0" prefWidth="220.0" styleClass="login-button" stylesheets="@../../stylesheets/loginDesign.css" text="Login" />
            <FontAwesomeIcon fill="#14b8a6" glyphName="USER_MD" layoutX="191.0" layoutY="128.0" size="7em" />
         <Button layoutX="401.0" mnemonicParsing="false" prefHeight="22.0" prefWidth="50.0" styleClass="close" stylesheets="@../../stylesheets/loginDesign.css">
            <graphic>
               <FontAwesomeIcon glyphName="CLOSE" size="15" />
            </graphic>
         </Button>
        </AnchorPane>
    </AnchorPane>
</StackPane>

and here is my css file

.left-form {
    -fx-background-color: #14b8a6;
    -fx-border-color: #000;
    -fx-border-width: 0.4px 0px .4px .4px;
}

.right-form {
    -fx-background-color: #fff;
    -fx-border-color: #000;
    -fx-border-width: .4px .4px .4px 0px;
}

.close {
    -fx-background-color: transparent;
    -fx-cursor: hand;
}

.close:hover {
    -fx-background-color: #ef4444;
}

.text-field {
    -fx-border-color: #3e3d3d;
    -fx-border-width: 0.5px;
    -fx-border-radius: 4px;
    -fx-font-family: "Tahoma";
    -fx-font-size: 13px; /* Add 'px' unit to font size */
}

.text-field:focused {
    -fx-border-color: #14b8a6;
    -fx-border-radius: 4px;
    -fx-border-width: 1.5px;
}

.login-button {
    -fx-background-color: #14b8a6;
    -fx-background-radius: 15px;
    -fx-cursor: hand;
    -fx-font-size: 14px; /* Add 'px' unit to font size */
    -fx-text-fill: #fff;
    -fx-font-family: "SansSerif";
}

Solution

  • To manage layouts, you need to be familiar with JavaFX's built-in layout panes.

    There really is no shortcut to just experimenting with these layout panes and becoming familiar with how each of them manages layout and what properties they have.

    If you want the layout to be responsive (i.e. for components to move and resize according to how much space is available) you need to:

    1. Avoid hardcoding positions and sizes. This means you must not set layoutX, layoutY, prefWidth, prefHeight etc. Sometimes it may be helpful to set min/max sizes, but this can constrain the ability of the layout pane to respond to changes in available space.
    2. Use layout panes that perform responsive layout. This means you generally should not use StackPane or AnchorPane except for very small, specific parts of the UI. By contrast, BorderPane, HBox, VBox, GridPane, TilePane, FlowPane, etc. provide the most responsiveness. Focus on logical layout rather than specific positioning.
    3. Decide how you want the layout to respond. If there is extra space, how should it be used? If space is limited, what should shrink? This will determine which layout panes you decide to use.

    Here is an approximation to the layout you defined using responsive panes. I also added -fx-padding: 10; to the left-form and right-form style classes in the CSS.

    I could not get the FontAwesome parts to work, so I commented those out and made guesses as to how they should be. (In the version I found, FontAwesomeIcon is not a Node subclass. Not sure what is going on there.)

    <?xml version="1.0" encoding="UTF-8"?>
    
    <?import de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon?>
    
    <?import javafx.geometry.Insets?>
    <?import javafx.scene.control.*?>
    <?import javafx.scene.layout.*?>
    <?import javafx.scene.text.Font?>
    <BorderPane stylesheets="@loginDesign.css" xmlns="http://javafx.com/javafx/20.0.1" xmlns:fx="http://javafx.com/fxml/1">
        <left>
            <VBox alignment="CENTER" styleClass="left-form">
                <!--
                <FontAwesomeIcon fill="WHITE" glyphName="STETHOSCOPE" size="12em" tabSize="0" />
                -->
                <Label text="Pesticide Management System" textFill="WHITE">
                    <font>
                        <Font name="Berlin Sans FB" size="18.0" />
                    </font>
                </Label>
            </VBox>
        </left>
        <center>
            <BorderPane styleClass="right-form">
                <top>
                    <HBox alignment="TOP_RIGHT">
                        <padding><Insets topRightBottomLeft="10"/></padding>
                        <Button mnemonicParsing="false" styleClass="close" text="X">
                            <!--
                            <graphic>
                                <FontAwesomeIcon glyphName="CLOSE" size="15" />
                            </graphic>
                            -->
                        </Button>
                    </HBox>
    
                </top>
                <center>
                    <VBox alignment="CENTER" spacing="20" fillWidth="true">
                        <Label text="Welcome, Admin!" textFill="#374151">
                            <font>
                                <Font name="Berlin Sans FB" size="25.0" />
                            </font>
                        </Label>
                        <TextField promptText="Username" styleClass="text-field" maxWidth="Infinity"/>
                        <PasswordField maxWidth="Infinity" promptText="Password" styleClass="text-field"  />
                        <Button maxWidth="Infinity" styleClass="login-button" text="Login" />
                        <!--
                        <FontAwesomeIcon fill="#14b8a6" glyphName="USER_MD" size="7em" />
                        -->
                    </VBox>
                </center>
            </BorderPane>
        </center>
    </BorderPane>
    

    This produces

    enter image description here

    If I resize the screen, it responds reasonably well. You can tweak the code to make it respond differently, depending on your actual requirements.

    enter image description here