I want to have a rectangular grid with square cells, which can be zoomed and dragged (like you would a map). So I put it in a ScrollPane, altough it behaves rather weirdly at certain sizes. The size of the grid will change dynamically.
On the picture there is a grid of size 20x20.
- Not all gaps are shown inside the grid. Notice that it should be 20 squares but isn't. Both Vgap and Hgap is 1.
- The grid itself is larger than the content, which is not good, because when it will be zoomed I could drag beyond the border of the grid.
- I would like to center the GridPane inside the ScrollPane when it is smaller than the scrollpane. (
Gridpane alignment="CENTER"
is apparently not doing anything)
Minimal, Complete, and Verifiable example
FXML:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.layout.GridPane?>
<ScrollPane hbarPolicy="NEVER" hvalue="0.5" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" pannable="true" prefHeight="400.0" prefWidth="600.0" vbarPolicy="NEVER" vvalue="0.5" xmlns="http://javafx.com/javafx/9" xmlns:fx="http://javafx.com/fxml/1" fx:controller="bug.app.Bug">
<GridPane fx:id="gridPane" alignment="CENTER" hgap="1.0" style="-fx-background-color: red;" vgap="1.0">
</GridPane>
</ScrollPane>
Controller + Main:
package bug.app;
import javafx.application.Application;
import javafx.beans.binding.DoubleBinding;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class Bug extends Application {
private static final int HEIGHT = 20;
private static final int WIDTH = 20;
private static final double MIN_CELL_SIZE = 2;
@FXML private GridPane gridPane;
private DoubleProperty zoomRatio = new SimpleDoubleProperty(5);
@FXML
private void initialize() {
final DoubleBinding cellSizeBinding = zoomRatio.multiply(MIN_CELL_SIZE);
List<Node> cells = new ArrayList<>(HEIGHT * WIDTH);
for (int row = 0; row < HEIGHT; row++) {
for (int col = 0; col < WIDTH; col++) {
final Pane cell = new Pane();
cell.setBackground(new Background(new BackgroundFill(Color.YELLOW, CornerRadii.EMPTY, Insets.EMPTY)));
cell.setMinSize(MIN_CELL_SIZE, MIN_CELL_SIZE);
cell.setMaxWidth(Region.USE_PREF_SIZE);
cell.setMaxHeight(Region.USE_PREF_SIZE);
cell.prefWidthProperty().bind(cellSizeBinding);
cell.prefHeightProperty().bind(cellSizeBinding);
GridPane.setConstraints(cell, col, row, 1, 1);
cells.add(cell);
}
}
gridPane.getChildren().clear();
gridPane.getChildren().addAll(cells);
}
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) throws IOException {
Parent root = FXMLLoader.load(
getClass().getResource("/view/bugView.fxml"));
final Scene scene = new Scene(root, 600, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
}
NB: I chose a Pane as a Cell because I want to subclass it and eventually fill it (with probably Shapes?) with different colours dividing the square into 1-4 parts. Imagine two or four triangles forming a square. I would also like to resize this elegantly (AFAIK Shapes are not resizable), maybe somehow binding the size of the inner Shapes to the Panes' size will do the magic. I am not that far yet, but feel free to advise on this too.