2016-11-09 5 views
4

Я пользуюсь GridPane, чтобы получить информацию о городах (в игре), но иногда я хочу удалить некоторые строки. Это класс я использую для моего 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.

Может кто-нибудь мне помочь? (Скажите, хотите ли вы весь код, необходимый для его воспроизведения дома)

+2

Пожалуйста, пост код в вопросе ([должным образом отформатированы] (http://meta.stackexchange.com/questions/22186/how-do-i-format-my- кодовые блоки)), вместо того, чтобы предоставлять ссылку на него. –

ответ

9
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); 
} 
+0

Спасибо за быстрый ответ. Я попробую этот код, когда буду дома. Я забыл сказать, что у меня уже есть строка в GridPane (это не город, это просто заголовок), это влияет на ваш код? – Franckyi

+0

До тех пор, пока не используются пробелы строк, проблем не должно быть. Вам просто нужно использовать правильный индекс строки, т. Е. Если заголовок использует одну строку, а вторая строка (index = 1) содержит первый город, вам нужно передать '1' в' deleteRow'. – fabian

+0

О, и у меня другая проблема. RemoveRow работает хорошо, но я не знаю, как изменить строку ... – Franckyi