如何将边缘添加到网格窗格

Posted

技术标签:

【中文标题】如何将边缘添加到网格窗格【英文标题】:How to add edges to gridpane 【发布时间】:2022-01-05 21:02:36 【问题描述】:

我正在努力编写一个程序,该程序需要我使用 GUI 和 MVC 设计模式制作 nonogram 游戏。由于它是一个非图游戏,我需要创建一个网格。一个非图游戏应该是这样的:

这是我在 GridPane 中创建矩形得到的结果:

但我不知道如何在我创建的网格窗格周围添加包含游戏线索的边缘。

这是我的代码:

public class PuzzleView implements FXComponent 

  private Controller controller;
  Model model;

  public PuzzleView(Controller controller) 
    this.controller = controller;
    model = ((ControllerImpl) controller).getModel();
  
So
  @Override
  public Parent render() 

    GridPane board = new GridPane();
    double width = 30;
    board.setLayoutX(300);
    board.setLayoutY(300);
    int h = model.getHeight();
    int w = model.getWidth();

    Rectangle[][] rec = new Rectangle[w][h];

    for (int i = 0; i < w; i++) 
      for (int j = 0; j < h; j++) 
        rec[i][j] = new Rectangle();
        rec[i][j].setX(i * width);
        rec[i][j].setY(j * width);
        rec[i][j].setWidth(width);
        rec[i][j].setHeight(width);
        rec[i][j].setFill(Color.WHITE);
        rec[i][j].setStroke(Color.BLACK);
        board.add(rec[i][j], i, j);
      
    

【问题讨论】:

在我的脑海中(必须真正使用 JavaFX),您应该使用复合布局。也就是说,您使用一个父容器,它在包含GridPane 的容器周围布置“提示”,也许使用BorderPane?然后,BorderPane 的每个边缘都可以根据您的需要包含不同的布局窗格 首先,将board.add(rec[i][j], i, j) 更改为board.add(rec[i][j], i + 1, j + 1)。然后您可以将“线索”框添加到第 0 行和第 0 列。 【参考方案1】:

考虑使用 JavaFX Control(或 Pane)而不是 shape 来表示网格单元,并使用 4 个 GridPanes 来表示板的不同区域:

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.*;
import javafx.scene.control.Label;
import javafx.scene.layout.*;
import javafx.stage.Stage;

public class MonogramBoard extends Application 

    private static final int BOARD_SIZE = 5, HINT_SIZE = 2;

    @Override
    public void start(Stage primary) 
        Node corner = new Board(HINT_SIZE, HINT_SIZE, false, false).getNode();
        Node topHint = new Board(HINT_SIZE, BOARD_SIZE, true, true).getNode();
        HBox topPane = new HBox(corner, topHint);

        Node leftHint =  new Board(BOARD_SIZE,HINT_SIZE, true, true).getNode();
        Node board = new Board(BOARD_SIZE, BOARD_SIZE, true, true).getNode();
        HBox bottomPane = new HBox(leftHint, board);
        VBox root = new VBox(topPane, bottomPane);
        root.setPadding(new Insets(10));
        primary.setScene(new Scene(root));
        primary.show();
    

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


class Board
    private final GridPane grid;

    public Board(int rows, int columns, boolean isBorder, boolean isGridLines) 
        grid = new GridPane();
        grid.setPadding(new Insets(1));
        if(isBorder) 
            grid.setStyle("-fx-background-color: white; -fx-border-color: black ; -fx-border-width: 2px");
        else
            grid.setStyle("-fx-background-color: white; -fx-border-color: white ; -fx-border-width: 2px");
        
        for(int row = 0; row < rows; row++)
            for(int col = 0; col < columns; col++)
                grid.add(new Cell(isGridLines).getNode(), col, row);
            
        
    

    Node getNode() return grid; 


//represents a single cell
class Cell
    private final Label label;
    private final int CELL_SIZE = 50;

    Cell()
        this(true);
    

    Cell(boolean isBorder)

        label = new Label();
        if(isBorder) 
            label.setStyle("-fx-background-color: white; -fx-border-color: black ; -fx-border-width: 1px");
        else
            label.setStyle("-fx-background-color: white; -fx-border-color: white ; -fx-border-width: 1px");
        
        label.setPrefSize(CELL_SIZE,CELL_SIZE);
    

    Node getNode() return label; 


【讨论】:

【参考方案2】:

在布局方面,将有不止一种方法来解决它。您可以选择 cmets 中建议的方式,也可以使用以下方法。

以下方法依赖于使用 CSS 设置边框样式。通过这种方式,您可以准确地获得您所期望的外观,并且还可以完美地适用于任何尺寸的电路板。

首先,您将提示部分和拼图部分分成单独的网格窗格。这样您就可以更好地控制各个部分。

然后您在网格窗格中设置网格窗格和框的样式以获得所需的样式。在第二个屏幕截图中,我添加了间距以展示每个网格窗格和框的样式以实现最终外观。

关键是您要专门设置每个边框的边宽(0px、1px 或 2px)。渲染最终布局后,您将获得所需的外观。

请查看以下演示:

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.CheckBox;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

import java.util.stream.Stream;

public class GridPaneBordersDemo extends Application 
    @Override
    public void start(Stage stage) throws Exception 
         double width = 30; // each box size
        int rows = 8; // Main box rows & cols
        int cols = 6;
        int topHintRows = 3;
        int sideHintCols = 4;

        // Top hint pane
        GridPane topHint = new GridPane();
        topHint.getStyleClass().add("topHintPane");
        for (int i = 0; i < cols; i++) 
            for (int j = 0; j < topHintRows; j++) 
                StackPane box = getBox(width);
                box.getStyleClass().add("topHintBox");
                topHint.add(box, i, j);
            
        

        // Side hint pane
        GridPane sideHint = new GridPane();
        sideHint.getStyleClass().add("sideHintPane");
        for (int i = 0; i < sideHintCols; i++) 
            for (int j = 0; j < rows; j++) 
                StackPane box = getBox(width);
                box.getStyleClass().add("sideHintBox");
                sideHint.add(box, i, j);
            
        

        // Main Puzzle
        GridPane mainPuzzle = new GridPane();
        mainPuzzle.getStyleClass().add("puzzlePane");
        for (int i = 0; i < cols; i++) 
            for (int j = 0; j < rows; j++) 
                StackPane box = getBox(width);
                box.getStyleClass().add("puzzleBox");
                mainPuzzle.add(box, i, j);
            
        

        GridPane emptyGrid = new GridPane();
        emptyGrid.getStyleClass().add("emptyGrid");

        GridPane pane = new GridPane();
        pane.setPadding(new Insets(10));
        pane.add(emptyGrid,0,0);
        pane.add(topHint,1,0);
        pane.add(sideHint,0,1);
        pane.add(mainPuzzle,1,1);

        CheckBox checkBox = new CheckBox("Show spacing");
        checkBox.selectedProperty().addListener((obs,old,val)->
            double gap = val?10:0;
            Insets insets = val? new Insets(10):Insets.EMPTY;
            Stream.of(pane,topHint,sideHint,mainPuzzle,emptyGrid).forEach(grid->
                grid.setHgap(gap);
                grid.setVgap(gap);
                grid.setPadding(insets);
            );
            stage.sizeToScene();
        );
        VBox root =new VBox(checkBox,pane);
        root.setSpacing(10);
        root.setPadding(new Insets(10));
        Scene scene = new Scene(root);
        scene.getStylesheets().add(getClass().getResource("grid.css").toExternalForm());
        stage.setScene(scene);
        stage.setTitle("GridPane Border");
        stage.setOnShown(e->stage.sizeToScene());
        stage.show();

    

    private StackPane getBox(double width)
        StackPane box = new StackPane();
        box.setMinSize(width,width);
        box.setMaxSize(width,width);
        box.getStyleClass().add("box");
        return box;
    

CSS 代码(grid.css):

.emptyGrid
   -fx-border-width: 0px 1px 1px 0px;
   -fx-border-color: black;


.topHintPane
   -fx-border-width: 2px 1px 1px 1px;
   -fx-border-color: black;


.sideHintPane
   -fx-border-width: 1px 1px 1px 2px;
   -fx-border-color: black;


.puzzlePane
   -fx-border-width: 1px;
   -fx-border-color: black;


.box
  -fx-background-color:transparent ;


.topHintBox
   -fx-border-width: 0px 1px 0px 0px;
   -fx-border-color: black;


.sideHintBox
   -fx-border-width: 0px 0px 1px 0px;
   -fx-border-color: black;


.puzzleBox
   -fx-border-width: 0px 1px 1px 0px;
   -fx-border-color: black;

我再次提醒您,您也可以通过其他方法实现。这只是使用单个框和 gridPane 样式的一种方式。

【讨论】:

以上是关于如何将边缘添加到网格窗格的主要内容,如果未能解决你的问题,请参考以下文章

php 如何以编程方式使用panelizer将窗格添加到节点

如何在窗格上添加多种灯光效果?

Javafx 网格窗格中心元素

JavaFX 动态地将标签添加到窗格,在 fxml 文件中定义

JavaFX 在网格窗格中显示多个图像

JavaFX 使用 fx:id 或 id 将节点动态添加到窗格