1

I'm having trouble with the following code. My Box and border does not want to center. It keeps reverting to the top left corner. I need it to snap to the center when running the program. I'm new to programming so the issue might be something simple. I have also tried shifting by the width of the border using the setTranslateX and setTranslateY methods. This causes the boxPane to be centered in the StackPane

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.scene.input.ScrollEvent;

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) {
        primaryStage.setTitle("JavaFX Movable Box with Border and Grid");

        int gridSize = 28;
        double boxSize = 500.0; // size of the box
        double borderWidth = 2.0; // width of the border
        double cellSize = boxSize / gridSize;  // size of each cell

        Pane grid = new Pane();
        for (int i = 0; i < gridSize; i++) {
            for (int j = 0; j < gridSize; j++) {
                Rectangle cell = new Rectangle(cellSize, cellSize);
                cell.setFill(Color.WHITE);
                cell.setStroke(Color.BLACK);
                cell.setStrokeWidth(0.5);
                cell.setX(j * cellSize + borderWidth / 2);
                cell.setY(i * cellSize + borderWidth / 2);
                grid.getChildren().add(cell);
            }
        }

        // Create a border around the grid
        Rectangle border = new Rectangle(boxSize + borderWidth, boxSize + borderWidth);
        border.setFill(Color.TRANSPARENT);
        border.setStroke(Color.BLACK);
        border.setStrokeWidth(borderWidth);
        border.setX(borderWidth / 2);
        border.setY(borderWidth / 2);

        Pane boxPane = new Pane();
        boxPane.getChildren().addAll(border, grid);

        StackPane root = new StackPane();
        root.getChildren().add(boxPane);

        Scene scene = new Scene(root, 700, 700);

        scene.setOnScroll((ScrollEvent event) -> {
            double zoomFactor = 1.05;
            double deltaY = event.getDeltaY();
            if (deltaY < 0){
                zoomFactor = 2 - zoomFactor;
            }
            boxPane.setScaleX(boxPane.getScaleX() * zoomFactor);
            boxPane.setScaleY(boxPane.getScaleY() * zoomFactor);
            event.consume();
        });

        boxPane.setOnMouseDragged(event -> {
            double newX = event.getSceneX() - boxSize / 2;
            double newY = event.getSceneY() - boxSize / 2;
            boxPane.setTranslateX(newX);
            boxPane.setTranslateY(newY);
        });

        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

I tried changing the box and scene size

not_a_nerd
  • 39
  • 1
  • 7
KhulZA
  • 11
  • 1
  • This doesn't make a lot of sense to me. It is a "Movable Box". How can it be centered when it is moved? – jewelsea Jul 18 '23 at 18:25

2 Answers2

1

While StackPane is excellent for centering, as shown here, it's superfluous in this case:

Pane boxPane = new Pane();
boxPane.getChildren().addAll(border, grid);
//StackPane root = new StackPane();
//root.getChildren().add(boxPane);
Scene scene = new Scene(boxPane, 700, 700);

To center the boxPane at startup, adjust its position after show(), using the available geometry:

primaryStage.show();
boxPane.setTranslateX((boxPane.getWidth() - boxSize) / 2);
boxPane.setTranslateY((boxPane.getHeight() - boxSize) / 2);

The existing drag handler centers the boxPane under the mouse. To change this behavior, record the location of the mouse pressed event and use it to adjust the target location in your drag handler; some examples are examined here and here:

boxPane.setOnMousePressed((event) -> {
    // record mouse location for later reference
});
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
1

I agree with what @trashgod mentioned.

Below are my additional points for you to consider if needed ;) :

  • Why don't you consider to use a GridPane rather than positioning each cell manually to form like a grid.

  • Do you really need Rectangle as your cell. If you are going to show something in the cell, I believe you will include a Pane and set the Rectangle for background and some node as content. So why don't you consider to use directly a Pane as cell with some border styling, so that you can avoid an extra node(Rectangle) per cell. This is just a thought :)

  • I believe you are trying something with borders to make it look like a perfect grid with equal border widths for all cells. You can try the below approach:

    The idea is, we don't set all borders to a cell. Instead we only set right and bottom border for every cell. and for the container (GridPane) we set only the top and left borders. Which when finally rendered will make a perfect grid (as below).

enter image description here

After combining all the above points (including @trashgod solution) below is quick demo for your reference:

enter image description here

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.input.ScrollEvent;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;

public class MovableBoxDemo extends Application {

    private double lx, ly, x, y;

    @Override
    public void start(Stage primaryStage) {
        primaryStage.setTitle("JavaFX Movable Box with Border and Grid");

        int gridSize = 28;
        double boxSize = 500.0; // size of the box
        double cellSize = boxSize / gridSize;  // size of each cell

        GridPane grid = new GridPane();
        grid.setStyle("-fx-border-width: 1 0 0 1;-fx-border-color:black;");
        for (int i = 0; i < gridSize; i++) {
            for (int j = 0; j < gridSize; j++) {
                Pane cell = new Pane();
                cell.setPrefSize(cellSize, cellSize);
                cell.setStyle("-fx-border-width: 0 1 1 0;-fx-border-color:black;-fx-background-color:white;");
                grid.add(cell, i, j);
            }
        }

        Pane boxPane = new Pane(grid);
        Scene scene = new Scene(boxPane, 700, 700);
        scene.setOnScroll((ScrollEvent event) -> {
            double zoomFactor = 1.05;
            double deltaY = event.getDeltaY();
            if (deltaY < 0) {
                zoomFactor = 2 - zoomFactor;
            }
            boxPane.setScaleX(boxPane.getScaleX() * zoomFactor);
            boxPane.setScaleY(boxPane.getScaleY() * zoomFactor);
            event.consume();
        });
        boxPane.setOnMousePressed(event -> {
            x = event.getSceneX();
            y = event.getSceneY();
            lx = boxPane.getLayoutX();
            ly = boxPane.getLayoutY();
        });
        boxPane.setOnMouseDragged(event -> {
            double diffX = event.getSceneX() - x;
            double diffY = event.getSceneY() - y;
            boxPane.setLayoutX(lx + diffX);
            boxPane.setLayoutY(ly + diffY);
        });

        primaryStage.setScene(scene);
        primaryStage.show();
        boxPane.setLayoutX((boxPane.getWidth() - boxSize) / 2);
        boxPane.setLayoutY((boxPane.getHeight() - boxSize) / 2);
    }

    public static void main(String[] args) {
        launch(args);
    }
}
Sai Dandem
  • 8,229
  • 11
  • 26