我使用GridPane
来存储有关城市的信息(在游戏中),但有时我想删除一些行。这是我用于GridPane
:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import com.franckyi.kingsim.city.City;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.layout.GridPane;
import javafx.scene.text.Text;
public class CityGrid extends GridPane {
private List<City> cities;
public CityGrid() {
super();
cities = new ArrayList<City>();
}
public List<City> getCities() {
return cities;
}
public void deleteCity(int row) {
cities.remove(row - 1);
removeNodes(getNodesFromRow(row));
int i = row;
while (!getNodesFromRow(i + 1).isEmpty()) {
moveNodes(i + 1, getNodesFromRow(i + 1));
removeNodes(getNodesFromRow(i + 1));
i++;
}
}
public void addCity(City city) {
cities.add(city);
int col = 0;
List<Node> rowNodes = new ArrayList<Node>();
Button mod = new Button("Modify");
mod.setOnAction(event -> {
});
Button del = new Button("Delete");
del.setOnAction(event -> {
deleteCity(getRowIndex(del));
});
rowNodes.addAll(Arrays.asList(new CheckBox(), new Text(city.getName()), new Text(city.getStatus().getText()),
new Text(city.getTrade() + ""), new Text(city.getCost() + ""), new Text(city.getTroops() + ""), mod,
del));
for (Node n : rowNodes) {
n.setId(cities.size() + "");
this.add(n, col, cities.size());
col++;
}
}
private List<Node> getNodesFromRow(int i) {
List<Node> list = new ArrayList<Node>();
for (Node n : getChildren()) {
if (getRowIndex(n).equals(i)) {
list.add(n);
}
}
System.out.println(list.size());
return list;
}
private void removeNodes(List<Node> list) {
for (Node node : list) {
this.getChildren().remove(getIndex(getColumnIndex(node), getRowIndex(node)));
}
}
private void moveNodes(int row, List<Node> nodes) {
int i = 0;
for (Node node : getNodesFromRow(row)) {
this.getChildren().set(getIndex(getColumnIndex(node), getRowIndex(node)),
nodes.get(i));
i++;
}
}
private int getIndex(int col, int row) {
int i = 0;
for (Node node : getChildren()) {
if (getColumnIndex(node) == col && getRowIndex(node) == row)
return i;
i++;
}
return 0;
}
}
addCity
功能完美无缺。当我删除添加的最后一个城市时,deleteCity
功能也有效。但是当我删除一个城市时,它会自动删除我删除后添加的所有城市,而且我不想这样做。
您还应该注意到,每次执行getNodesFromRow(int i)
方法时,它都会打印所选行中的节点数。当我添加两个城市并删除第一个城市时,这就是我在控制台中获得的内容:8,0,8,8,8,8,8,0。
有人能帮助我吗? (如果您想要在家中复制所需的所有代码,请告诉我)
答案 0 :(得分:12)
private void moveNodes(int row, List<Node> nodes) {
int i = 0;
for (Node node : getNodesFromRow(row)) {
this.getChildren().set(getIndex(getColumnIndex(node), getRowIndex(node)),
nodes.get(i));
i++;
}
}
这不起作用。子列表中的索引在GridPane
之外没有任何意义,除了它们的绘制顺序。行/列索引保存到每个子项的properties
map。要修改这些,您需要使用static GridPane.setRowIndex
method。
示例强>
@Override
public void start(Stage primaryStage) {
Button btn = new Button("Delete");
TextField tf = new TextField();
TextFormatter<Integer> formatter = new TextFormatter<>(new IntegerStringConverter());
formatter.setValue(0);
tf.setTextFormatter(formatter);
btn.disableProperty().bind(IntegerExpression.integerExpression(formatter.valueProperty()).lessThan(0));
GridPane grid = new GridPane();
grid.setHgap(5);
grid.setVgap(5);
btn.setOnAction((ActionEvent event) -> {
deleteRow(grid, formatter.getValue());
});
for (int r = 0; r < 5; r++) {
for (int c = 0; c < 3; c++) {
grid.add(new Text(r+"_"+c), c, r);
}
}
Scene scene = new Scene(new VBox(new HBox(tf, btn), grid));
primaryStage.setScene(scene);
primaryStage.show();
}
static void deleteRow(GridPane grid, final int row) {
Set<Node> deleteNodes = new HashSet<>();
for (Node child : grid.getChildren()) {
// get index from child
Integer rowIndex = GridPane.getRowIndex(child);
// handle null values for index=0
int r = rowIndex == null ? 0 : rowIndex;
if (r > row) {
// decrement rows for rows after the deleted row
GridPane.setRowIndex(child, r-1);
} else if (r == row) {
// collect matching rows for deletion
deleteNodes.add(child);
}
}
// remove nodes from row
grid.getChildren().removeAll(deleteNodes);
}
答案 1 :(得分:0)
我今天有相同的任务,但又增加了要求,不仅要删除(隐藏)单行,还要删除多行,以后再读取(取消隐藏)它们。 (我的用例是一种表格,必须根据用户的选择显示一组字段的不同子集。)
我要感谢fabian在正确的轨道上,我设计了如下所示的GridPaneRowHider类。 要将其与给定的GridPane一起使用,
GridPane myPane = ...
分配实例
GridPaneRowHider h = new GridPaneRowHider();
并致电
h.hide(myPane,1,2,6);
隐藏指定的行和
h.unhide(myPane);
再次显示它们。
所以这是代码:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.stream.IntStream;
import nnn.util.collection.Pair;
import javafx.scene.Node;
import javafx.scene.layout.GridPane;
/**
* An object that can hide and unhide rows in a GridPane.
*
* @author Tillmann
* @since 1.1.9
*/
public class GridPaneRowHider {
/**
* A container of the currently hidden Nodes, along with information about
* their positions; associates rows with Nodes in row; sorted by rows,
* ascending
*/
private Map<Integer,List<Pair<Node,Integer>>> hidden_ = new TreeMap<Integer,List<Pair<Node,Integer>>>(
(a, b) -> a.compareTo(b));
/**
* From the specified GridPane hides the specified rows.
*
* @param gp the GridPane
* @param rows the rows to hide
* @see #unhide(GridPane)
*/
public void hide(GridPane gp, int... rows) {
// to suit the algorithm, sort the rows in descending fashion (higher row
// numbers before lower, i.e. visually south to north)
Integer[] sRows = IntStream.of(rows).boxed().toArray(Integer[]::new);
Arrays.sort(sRows,(a, b) -> b.compareTo(a));
// row by row
for (int row : sRows) {
// the list of Nodes in this row
List<Pair<Node,Integer>> li = new ArrayList<Pair<Node,Integer>>();
hidden_.put(Integer.valueOf(row),li);
// look at all the Nodes
for (Iterator<Node> it = gp.getChildren().iterator(); it.hasNext();) {
Node n = it.next();
int r = GridPane.getRowIndex(n);
// if it's a Node in the row to hide
if (r == row) {
// save it in the list
li.add(new Pair<>(n,GridPane.getColumnIndex(n)));
// and remove it from the GridPane
it.remove();
}
// if it's a Node further down, move it a row upwards (to the North)
// to fill the visual gap
else if (r > row)
GridPane.setRowIndex(n,r - 1);
}
}
}
/**
* Shows the rows again that have been hidden by a previous call to
* <code>hide()</code>.
* <p>
*
* If no call to hide() took place before (or unhide() has been called
* already), nothing happens. If hide() has been called several times, the
* result is undefined.
*
* @param gp the GridPane
* @see #hide(GridPane, int...)
*/
public void unhide(GridPane gp) {
// walk along the rows from north to south
for (Map.Entry<Integer,List<Pair<Node,Integer>>> me : hidden_.entrySet()) {
// look at the Nodes in the GridPane
for (Node n : gp.getChildren()) {
int r = GridPane.getRowIndex(n);
// if the Node is in the row to unhide or further down, make room
// by moving it a row further down (to the south)
if (r >= me.getKey())
GridPane.setRowIndex(n,r + 1);
}
// readd the hidden Nodes to the GridPane at their saved locations
for (Pair<Node,Integer> p : me.getValue())
gp.add(p.t_,p.u_,me.getKey());
}
// and mark we're done
hidden_.clear();
}
}