我认为处理此问题的最佳方法是实际从网格窗格中删除该行,而不是试图使该行“不可见”。在 GridPane 的任意位置插入和删除行有点棘手,因为 GridPane API 没有对此类函数的本机支持。因此,我根据您的自定义 GridPane 实现创建了一个小实用程序,该实用程序演示了在 GridPane 中添加和删除行。为此,自定义实现必须保留哪些节点位于哪些行的内部概念,并在添加或删除新行时更新每个节点和每个行的列约束。隐藏可以通过从网格窗格中删除一行来完成,然后在稍后阶段,将同一行添加回网格窗格中之前删除它的索引处。我知道这不是您想要的,但对我来说这似乎是最合理的解决方案。
/** Click on a Label to remove the row containing the label from the GridPane */
import javafx.application.Application;
import javafx.collections.*;
import javafx.geometry.*;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.*;
import javafx.stage.Stage;
import java.util.*;
public class HiddenNodes extends Application {
private static final int N_COLS = 3;
private static final int INIT_N_ROWS = 10;
private int nextRowId = 0;
private Node[] lastRemovedRow = null;
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) throws Exception {
CustomGrid grid = new CustomGrid();
for (int i = 0; i < INIT_N_ROWS; i++) {
Label[] labels = createRow(grid);
grid.insertRow(i, labels);
}
Button prepend = new Button("Prepend");
prepend.setOnAction(event -> {
Label[] labels = createRow(grid);
grid.insertRow(0, labels);
});
Button append = new Button("Append");
append.setOnAction(event -> {
Label[] labels = createRow(grid);
grid.insertRow(grid.getRowsSize(), labels);
});
HBox controls = new HBox(10, prepend, append);
VBox layout = new VBox(10, controls, grid);
layout.setPadding(new Insets(10));
stage.setScene(new Scene(layout, 200, 600));
stage.show();
}
private Label[] createRow(CustomGrid grid) {
Label[] labels = new Label[N_COLS];
for (int j = 0; j < N_COLS; j++) {
final int fj = j;
labels[j] = new Label(nextRowId + ":" + j);
labels[j].setStyle("-fx-background-color: coral;");
labels[j].setOnMouseClicked((MouseEvent e) -> {
lastRemovedRow = grid.removeRowContaining(labels[fj]);
});
}
nextRowId++;
return labels;
}
class CustomGrid extends GridPane {
private ObservableList<Node[]> rows = FXCollections.observableArrayList();
CustomGrid() {
this.setHgap(20);
this.setVgap(20);
ColumnConstraints firstColConstraints = new ColumnConstraints();
firstColConstraints.setHalignment(HPos.RIGHT);
firstColConstraints.setPercentWidth(50.0);
firstColConstraints.setHgrow(Priority.ALWAYS);
ColumnConstraints secondColConstraints = new ColumnConstraints();
ColumnConstraints thirdColConstraints = new ColumnConstraints();
thirdColConstraints.setHgrow(Priority.ALWAYS);
thirdColConstraints.setHalignment(HPos.LEFT);
this.getColumnConstraints().addAll(firstColConstraints, secondColConstraints, thirdColConstraints);
VBox.setMargin(this, new Insets(10, 0, 50, 0));
}
void insertRow(int rowIdx, Node... nodes) {
for (int i = rows.size() - 1; i >= rowIdx; i--) {
for (int j = 0; j < rows.get(i).length; j++) {
setConstraints(rows.get(i)[j], j, i + 1);
}
}
addRow(rowIdx, nodes);
rows.add(rowIdx, nodes);
}
private Node[] removeRow(int rowIdx) {
for (int i = rows.size() - 1; i > rowIdx; i--) {
for (int j = 0; j < rows.get(i).length; j++) {
setConstraints(rows.get(i)[j], j, i - 1);
}
}
for (Node node: rows.get(rowIdx)) {
getChildren().remove(node);
}
return rows.remove(rowIdx);
}
Node[] removeRowContaining(Node node) {
Iterator<Node[]> rowIterator = rows.iterator();
int rowIdx = 0;
while (rowIterator.hasNext()) {
Node[] row = rowIterator.next();
for (Node searchNode : row) {
if (searchNode == node) {
return removeRow(rowIdx);
}
}
rowIdx++;
}
return null;
}
int getRowsSize() {
return rows.size();
}
}
}
上述程序只是一个大纲,需要额外的逻辑来在适当的行索引处重新显示“隐藏”节点(已从网格中删除)(这是一个相当棘手的问题)。
注意:您可以考虑使用 TableView 而不是 GridPane。通过操作支持 TableView 的项目列表,向 TableView 添加和删除节点非常简单。当然,我知道 TableView 并不是解决所有此类问题的合适解决方案(因为 TableView 带有许多其他功能,例如标题和排序,您可能不希望拥有这些功能)。