javafxscrollbarchatscenebuildervbox

How to make VBox inside of ScrollPane responsive (Chat Application)


I want my Chat Window to be reziable and scrollable, so far everything works except the ChatLog itself.

I need a scroll bar, that's why I put the VBox inside of a ScrollPane (which is child of an AnchorPane), but this way only the ScrollPane is responsive (thanks to Anchor Values). If I unwrap VBox I can set Anchor Values, then it works but I'm loosing my scroll bar.

How can I mantain the scroll bar for ChatLog AND make it responsive (attached on the right side)?

without resize

chatlog not resizable example

FXML:

<AnchorPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" style="-fx-background-color: #5b2529;" xmlns="http://javafx.com/javafx/17.0.2-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="de.lmu.jungejunkervp.ClientWindowController">
<children>
    <ScrollPane fx:id="scrollPane" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" prefHeight="265.0" prefWidth="592.0" AnchorPane.bottomAnchor="57.0" AnchorPane.leftAnchor="5.0" AnchorPane.rightAnchor="5.0" AnchorPane.topAnchor="5.0">
         <content>
          <VBox fx:id="chatLog" prefHeight="265.0" prefWidth="575.0" />
         </content></ScrollPane>
    <TextArea fx:id="messageBox" layoutX="5.0" layoutY="349.0" onKeyPressed="#onEnterSend" prefHeight="47.0" prefWidth="536.0" promptText="enter message..." AnchorPane.bottomAnchor="5.0" AnchorPane.leftAnchor="5.0" AnchorPane.rightAnchor="61.0" />
    <Button fx:id="sendButton" mnemonicParsing="false" onAction="#setSendButtonAction" onMouseClicked="#setSendButtonAction" prefHeight="47.0" prefWidth="52.0" text="Send" AnchorPane.bottomAnchor="5.0" AnchorPane.rightAnchor="5.0" />
</children>
</AnchorPane>
public void addLabel(String message, Pos position) {
    HBox hBox = new HBox();
    hBox.setAlignment(position);
    hBox.setPadding(new Insets(5, 5, 5, 10));

    Text text = new Text(message);
    TextFlow textFlow = new TextFlow(text);

    textFlow.setStyle("-fx-background-color: rgb(233,233,235);" +
                        "-fx-background-radius: 20px");
    textFlow.setPadding(new Insets(5, 10, 5, 10));

    hBox.getChildren().add(textFlow);
    Platform.runLater(new Runnable() {
        @Override
        public void run() {
            chatLog.getChildren().add(hBox);
        }
    });
}
public void setSendButtonAction() {
    String message = messageBox.getText().replaceAll("[\n\r]", "");
    try {
        if (!message.isEmpty()) {
            // show message on the sending client window
            addLabel(message, Pos.CENTER_RIGHT);
    }
}

Solution

  • To answer your actual question, below is what you need add to the ScrollPane (in fxml with your current layout).

    fitToHeight="true" fitToWidth="true" 
    

    The above code will make your VBox responsive with the ScrollPane.

    I also suggest to change your layout to get rid of AnchorPane (will all those hardcoded positions). You can use VBox/HBox in conjuction with vgrow/hgrow policies. The optimized fxml will be as below:

    <?import javafx.scene.control.ScrollPane?>
    <?import javafx.scene.layout.VBox?>
    <?import javafx.scene.control.TextArea?>
    <?import javafx.scene.control.Button?>
    <?import javafx.scene.layout.HBox?>
    <?import javafx.geometry.Insets?>
    <VBox style="-fx-background-color: #5b2529;" spacing="5" xmlns="http://javafx.com/javafx/17.0.2-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="de.lmu.jungejunkervp.ClientWindowController">
        <children>
            <ScrollPane fx:id="scrollPane" prefHeight="265.0" prefWidth="592.0" fitToHeight="true" fitToWidth="true" VBox.vgrow="ALWAYS">
                <content>
                    <VBox fx:id="chatLog"/>
                </content>
            </ScrollPane>
            <HBox spacing="5">
                <TextArea fx:id="messageBox" onKeyPressed="#onEnterSend" prefHeight="47.0" promptText="enter message..." HBox.hgrow="ALWAYS" />
                <Button fx:id="sendButton" mnemonicParsing="false" onAction="#setSendButtonAction" prefHeight="47.0" minWidth="52.0" text="Send"/>
            </HBox>
        </children>
        <padding>
            <Insets topRightBottomLeft="5"/>
        </padding>
    </VBox>
    

    enter image description here

    Having said that, I think you need to consider changing your layout to what @jewelsea mentioned in the provided example (using ListView).