我想编写代码,可以执行以下操作:
创建 9*9 GridPane 板,其中填充 81 个 StackPanes。
当我单击单元格(StackPane)时,如果它是白色的,我想将背景 StackPane 的颜色更改为蓝色。如果我船上已经有蓝色电池,那么旧电池会变成白色,新电池会变成蓝色。所以,在任何时候我只能有 0 或 1 个彩色单元格。
我尝试使用 StackPanes 的 Array[9][9] 但失败了,因为即使我在“public void start(Stage stage)”之前声明此数组,我也无法在 lambda 表达式或内部类中使用每个 StackPane。
我尝试使用变量来告诉我是否有 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();
}
}
解决此问题的一种方法是将单元格包含到 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 中似乎确实不正确。我添加了一个逻辑,为每个单元格添加边框以获得最终结果(下图)。
以下是这两项更改的完整演示:
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();
}
}