在 JavaFX 中更改 GridPane 中的彩色单元格

问题描述 投票:0回答:1

我想编写代码,可以执行以下操作:

  1. 创建 9*9 GridPane 板,其中填充 81 个 StackPanes。

  2. 当我单击单元格(StackPane)时,如果它是白色的,我想将背景 StackPane 的颜色更改为蓝色。如果我船上已经有蓝色电池,那么旧电池会变成白色,新电池会变成蓝色。所以,在任何时候我只能有 0 或 1 个彩色单元格。

  3. 我尝试使用 StackPanes 的 Array[9][9] 但失败了,因为即使我在“public void start(Stage stage)”之前声明此数组,我也无法在 lambda 表达式或内部类中使用每个 StackPane。

  4. 我尝试使用变量来告诉我是否有 1 个彩色单元格以及 2 个变量中的彩色单元格的坐标。当我单击单元格时,我看到坐标有效,但我无法更改窗格的颜色。


package com.example.testingcolorswitching;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.StackPane;
import javafx.scene.shape.Line;
import javafx.stage.Stage;

import java.io.IOException;

public class HelloApplication extends Application {


    boolean isAnyPaneSelected = true; // true if 1 of cells is selected
    int xColored = 1; // holds X coordinate of Selected cell;
    int yColored = 1; // holds Y coordinate of Selected cell;
    int columnSize = 50;
    int rowSize = 50;

    @Override
    public void start(Stage stage) throws IOException {

        GridPane grid = new GridPane();

        for (int x = 0; x < 9; x++)
            for (int y = 0; y < 9; y++){
                StackPane cell = new StackPane();
                cell.setMinSize(columnSize, rowSize);
                
                // I would like that this was checked every time I click on GridPane 
                if (isAnyPaneSelected && x == xColored && y == yColored)
                    cell.setStyle("-fx-background-color:BLUE");

                final int thisX = x;
                final int thisY = y;

                cell.setOnMouseClicked((event) -> {
                    if(isAnyPaneSelected) {
                        if (thisX == xColored & thisY == yColored)
                            isAnyPaneSelected = false;
                        else {
                            xColored = thisX;
                            yColored = thisY;
                        }
                    } else {
                        isAnyPaneSelected = true;
                        xColored = thisX;
                        yColored = thisY;
                    }

                    System.out.println(isAnyPaneSelected + " " + xColored + " " + yColored);
                });

                grid.add(cell, x, y);
            }


        // code below is not important. This code adds lines on screen.
        for (int i = 0; i <= 9; i++){
            Line line = new Line(0.0, rowSize * i, rowSize * 9, rowSize * i);
            line.setManaged(false);
            if (i % 3 == 0)
                line.setStrokeWidth(3);

            else
                line.setStrokeWidth(1);
            grid.getChildren().add(line);

            line = new Line(columnSize * i, 0.0, columnSize * i, columnSize * 9);
            line.setManaged(false);
            if (i % 3 == 0)
                line.setStrokeWidth(3);

            else
                line.setStrokeWidth(1);
            grid.getChildren().add(line);
        }

        Scene scene = new Scene(grid, 600, 600);
        stage.setScene(scene);
        stage.show();

    }

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

javafx controls inner-classes
1个回答
0
投票

解决此问题的一种方法是将单元格包含到 ObjectProperty 中,然后您可以添加侦听器来添加/删除单元格的样式。

类似:

// Create an object property to hold the selected cell.
private ObjectProperty<StackPane> selectedCell = new SimpleObjectProperty<>();

// Add listener to the object property to toggle the style
selectedCell.addListener((obs, old, val) -> {
    if (old != null) {
        old.setStyle(null);
    }
    if (val != null) {
        val.setStyle("-fx-background-color:BLUE");
    }
});

// On click, set the cell to the objectproperty.
cell.setOnMouseClicked((event) -> {
    // If already selected, then remove it.
    if (cell.equals(selectedCell.get())) {
        selectedCell.set(null);
    } else {
        selectedCell.set(cell);
    }
});

话虽如此,我还建议改变显示线条的逻辑。添加非托管行并将其放置在 GridPane 中似乎确实不正确。我添加了一个逻辑,为每个单元格添加边框以获得最终结果(下图)。

enter image description here

以下是这两项更改的完整演示:

enter image description here

import javafx.application.Application;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

import java.io.IOException;

public class CellColouringDemo extends Application {

    public static final String CSS = "data:text/css," + // language=CSS
            """
                        .outer-box{
                            -fx-border-style:solid;
                            -fx-border-color:black;
                            -fx-border-width:3px 0px 0px 3px;
                        }
                        
                        .cell{
                            -fx-border-style:solid;
                            -fx-border-color:black;
                            -fx-border-width:0px 1px 1px 0px;
                        }
                        
                        .cell-right{
                            -fx-border-width:0px 3px 1px 0px;
                        }
                        .cell-bottom{
                            -fx-border-width:0px 1px 3px 0px;
                        }
                        .cell-corner{
                            -fx-border-width:0px 3px 3px 0px;
                        }
                        
                        .selected-cell{
                            -fx-background-color: blue;
                        }
                    """;
    private int columnSize = 50;
    private int rowSize = 50;

    private ObjectProperty<StackPane> selectedCell = new SimpleObjectProperty<>();

    @Override
    public void start(Stage stage) throws IOException {
        selectedCell.addListener((obs, old, val) -> {
            if (old != null) {
                old.getStyleClass().remove("selected-cell");
            }
            if (val != null) {
                val.getStyleClass().add("selected-cell");
            }
        });
        GridPane grid = new GridPane();
        grid.getStyleClass().add("outer-box");
        for (int row = 0; row < 9; row++) {
            for (int col = 0; col < 9; col++) {
                StackPane cell = new StackPane();
                cell.getStyleClass().add("cell");
                setCellStyle(cell, row, col);
                cell.setMinSize(columnSize, rowSize);
                cell.setOnMouseClicked((event) -> {
                    if (cell.equals(selectedCell.get())) {
                        selectedCell.set(null);
                    } else {
                        selectedCell.set(cell);
                    }
                });
                grid.add(cell, col, row);
            }
        }
        StackPane root = new StackPane(new Group(grid));
        Scene scene = new Scene(root, 600, 600);
        scene.getStylesheets().add(CSS);
        stage.setScene(scene);
        stage.show();
    }

    private void setCellStyle(StackPane cell, int row, int col) {
        boolean isBottom = (row + 1) % 3 == 0;
        boolean isRight = (col + 1) % 3 == 0;
        if (isBottom && isRight) {
            cell.getStyleClass().add("cell-corner");
        } else if (isBottom) {
            cell.getStyleClass().add("cell-bottom");
        } else if (isRight) {
            cell.getStyleClass().add("cell-right");
        }
    }

    public static void main(String[] args) {
        launch();
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.