0

I wrote a javafx program(use maven + java17 + javafx17.0.1 + jfoenix9.0.10), which generates a window 1035 wide and 680 high. I made a black box on the left side of the window. The black box is a ButtonsBox component, and the height of the component is 680, too. But when I tried to add a button at the bottom of the component, the button was blocked by the window. Why is the height of the component the same as that of the scene, but the button was blocked by the window ?
Here are the codes of drawing class. When the application starts, the "start" method in the main class will call the "draw" method in "Draw" class.


package io.github.ctimet.lieinbedapp.gui;

import io.github.ctimet.lieinbedapp.gui.ui.ButtonsBox;
import io.github.ctimet.lieinbedapp.gui.util.CSSStyle;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
import javafx.scene.control.TextArea;
import javafx.scene.image.Image;
import javafx.scene.layout.AnchorPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.awt.*;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.URI;
import java.util.Objects;
import java.util.Optional;

public class Draw {
    private static final Logger logger = LoggerFactory.getLogger(Draw.class);

    private static final AnchorPane pane = new AnchorPane();

    public static void draw(Stage stage) {
        ButtonsBox box = new ButtonsBox(0, 0, 162, 680)
                .setSidesSpace(0)
                .setTopSpace(5)
                .setDownSpace(5)
                .setChildrenHeight(48)
                .setEachSpace(5)
                .setTextFill(Color.valueOf("#f5f5f5"))
                .setButtonStyle("/node.css", "button")
                .addTopButton("label", null, event -> {
                    System.out.println("Label");
                })
                .addTopButton("label2", null, event -> {
                    System.out.println("Label2");
                })
                .addDownButton("label3", null, event -> {
                    System.out.println("1");
                });
        CSSStyle.addDefaultStyle(box, "box");

        pane.getChildren().add(box);

        pane.setStyle("-fx-background-color: #f5f5f5;");

        Scene scene = new Scene(pane, 1035, 680);
        stage.setScene(scene);
        stage.setTitle("Lie In Bed");

        Image icon = new Image(Objects.requireNonNull(Draw.class.getResourceAsStream("/icon.png")));
        stage.getIcons().add(icon);
        stage.show();
    }
    
}

And here are the codes of ButtonsBox class

package io.github.ctimet.lieinbedapp.gui.ui;

import com.jfoenix.controls.JFXButton;
import io.github.ctimet.lieinbedapp.gui.util.CSSStyle;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Cursor;
import javafx.scene.Node;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;

public class ButtonsBox extends Pane {
    private double childrenHeight;
    private double sidesSpace;
    private double topSpace;
    private double downSpace;
    private double eachSpace;
    private String cssFile;
    private String cssClass;

    private Paint textFill = Color.WHITE;
    private int topButtonsQuantity = 0;
    private int downButtonsQuantity = 0;

    public ButtonsBox(double layoutX, double layoutY, double prefWidth, double prefHeight) {
        setLayoutX(layoutX);
        setLayoutY(layoutY);
        setPrefWidth(prefWidth);
        setPrefHeight(prefHeight);
    }

    public ButtonsBox setTopSpace(double topSpace) {
        this.topSpace = topSpace;
        return this;
    }

    public ButtonsBox setDownSpace(double downSpace) {
        this.downSpace = downSpace;
        return this;
    }

    public ButtonsBox setChildrenHeight(double childrenHeight) {
        this.childrenHeight = childrenHeight;
        return this;
    }

    public ButtonsBox setSidesSpace(double sidesSpace) {
        this.sidesSpace = sidesSpace;
        return this;
    }

    public ButtonsBox setEachSpace(double eachSpace) {
        this.eachSpace = eachSpace;
        return this;
    }

    public ButtonsBox setTextFill(Paint paint) {
        this.textFill = paint;
        return this;
    }

    public ButtonsBox setButtonStyle(String cssFile, String cssClass) {
        this.cssFile = cssFile;
        this.cssClass = cssClass;
        return this;
    }

    public ButtonsBox addTopButton(String label, Node graphic, EventHandler<ActionEvent> handler) {
        JFXButton child = new JFXButton(label);
        child.setLayoutX(getLayoutX() + sidesSpace);
        child.setLayoutY(topButtonsQuantity * (childrenHeight + eachSpace) + topSpace);
        child.setPrefWidth(getPrefWidth() - 2*sidesSpace);
        child.setPrefHeight(childrenHeight);
        child.setTextFill(textFill);
        child.setCursor(Cursor.HAND);
        if (graphic != null)
            child.setGraphic(graphic);
        if (cssClass != null && cssFile != null)
            CSSStyle.addStyle(child, cssClass, cssFile);
        child.setOnAction(handler);

        getChildren().add(child);
        topButtonsQuantity += 1;
        return this;
    }

    public ButtonsBox addDownButton(String label, Node graphic, EventHandler<ActionEvent> handler)  {
        JFXButton child = new JFXButton(label);
        child.setLayoutX(getLayoutX() + sidesSpace);
        System.out.println(getPrefHeight() - downButtonsQuantity * (childrenHeight + eachSpace) - downSpace);
        child.setLayoutY(getPrefHeight() - downButtonsQuantity * (childrenHeight + eachSpace) - downSpace);
        child.setPrefWidth(getPrefWidth() - 2*sidesSpace);
        child.setPrefHeight(childrenHeight);
        child.setTextFill(textFill);
        child.setCursor(Cursor.HAND);
        if (graphic != null)
            child.setGraphic(graphic);
        if (cssFile != null && cssClass != null)
            CSSStyle.addStyle(child, cssClass, cssFile);
        child.setOnAction(handler);

        getChildren().add(child);
        downButtonsQuantity += 1;
        return this;
    }
}

When I start this Application, It will show this. As you can see. The Button "Label3" does not appear in the window.But when I maximize the window, the button Label3 appears in the lower left corner of the window. this
What should I do to make the button Label3 display normally instead of being blocked?

I tried to set the width and height of the stage manually, but it didn't work. Only when I change the height of ButtonsBox, can the button be displayed normally, but I don't understand why the height of ButtonsBox is the same as that of scene, but the button Label3 is blocked.
I hope the button Label3 can be displayed normally, and I also want to know why the button Label3 is blocked

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
CTimet
  • 1
  • 3
    Most likely there's an error in the math somewhere. But as an aside, but why not just use a `VBox` for this? If you want stuff to appear at the top and the bottom, then place an empty `Region` / `Pane` with its `vgrow` set to `ALWAYS` between the top buttons and the bottom buttons. Note `VBox` has a spacing property and, given it inherits `Region`, has a padding property; it also has an `alignment` property. And you may also want to look at e.g., `BorderPane` to layout the button box on the left. – Slaw Jan 08 '23 at 11:46
  • 3
    Why are we seeing this so often now? People using Pane, Group and AnchorPane and then manually positioning Nodes with setLayoutX/setLayoutY all kinds of complicated math? Just use an appropriate layout class. In this case, VBox would do the trick. – DaveB Jan 08 '23 at 14:30
  • 3
    Don't import `awt` classes into a JavaFX app. Use [MaterialFX](https://github.com/palexdev/MaterialFX), not JFoenix (my opinion). – jewelsea Jan 08 '23 at 15:44
  • 1
    When you call `addDownButton()`, `downButtonsQuantity` is zero, so you set `layoutY` of the button to the height of the pane, minus 5 pixels (the value of `downSpace`). This means there is only 5 pixels of vertical space for the button, which is nowhere near enough, especially as you have set the preferred height of the button to 48 pixels. As others have commented, you should use predefined layout panes for this, instead of reinventing the wheel. (If you really did need to write your own layout code, which you don’t, this is not the way to do it.) – James_D Jan 08 '23 at 19:48
  • See if the layout ideas here can help -> https://github.com/sedj601/SimpleTextFileLoginApp/blob/main/src/main/resources/com/mycompany/sqliteloginapp/MainScreen.fxml – SedJ601 Jan 08 '23 at 22:54

0 Answers0