2015-02-05 2 views
0

У меня есть класс TableView и Data с целыми свойствами для столбцов. Однако я бы хотел, чтобы столбцы сначала отображали пустые ячейки, чтобы пользователь мог поместить ценность, которую он хочет.TableColumn, Как связать его с собственностью, но не заполнить ячейки

В настоящее время его невозможно, так как при создании объекта данных необходимо создать целочисленные значения с начальным значением, поэтому таблица будет заполнена уже цифрами.

private ObservableList<MyData> dataList = FXCollections.observableArrayList(); 

..... изм ....

private void buttAddColumnAction(ActionEvent event){   
     int i = numberOfColumns;// thats the key for lambda expression. Unicate number for column to access its variable; 

     if(dataList.size() > 0)//resizing each data object with new variable 
      for(MyData x: dataList) 
       x.addNew(); 

     TableColumn<MyData, Integer> newColumn = new TableColumn<>("#" + String.valueOf(++numberOfColumns)); 

     newColumn.setCellValueFactory(cellData -> cellData.getValue().getCellValue(i)); 
    // newColumn.setCellFactory(TextFieldTableCell.<MyData, Integer>forTableColumn(new IntegerStringConverter())); 

     Callback<TableColumn<MyData, Integer>, TableCell<MyData, Integer>> cellFactoryInt = (TableColumn<MyData, Integer> p) -> new EditingCellNumbers(tableView); 
     newColumn.setCellFactory(cellFactoryInt); 
     tableView.getColumns().add(newColumn); 

    } 


public class MyData{ //dont forget about public because you wont get acces to properties 
    private ObservableList<ObjectProperty<Integer>> cellValue = FXCollections.observableArrayList(); 

    public MyData(int howManyColumns) { 
     for(int i=0; i<howManyColumns; ++i) 
      this.cellValue.add(new SimpleObjectProperty<Integer>(null)); 
    } 

    public ObjectProperty<Integer> getCellValue(int whichOne) { 
     return cellValue.get(whichOne); 
    } 

    public void setCellValue(int cellValue, int whichOne) { 
     this.cellValue.set(whichOne, new SimpleObjectProperty<Integer>(cellValue)); 
    } 

    public void addNew(){ //ads another variable for another column 
     cellValue.add(new SimpleObjectProperty<Integer>(null)); 
    } 
    public void deleteLast(){ //deletes last variable when column is deleted 
     cellValue.remove(cellValue.size()-1); 
    } 
} 


CellFactory 



//Klasa ta pozwala na definiowania zachowania komórek, które edytuje użytkownik 
    public class EditingCellNumbers extends TableCell<MyData, Integer>{ 
    private TextField textField; 
    private TableView<MyData> parentTableView; 
    public static int numberOfColumns; 

    public EditingCellNumbers(TableView<MyData> parent) { 
     this.parentTableView = parent; 
     numberOfColumns = parent.getColumns().size(); 
    } 

    @Override 
    public void startEdit(){ 
     if (!isEmpty()) { 
      super.startEdit(); 
      createTextField(); 
      setText(null); 
      setGraphic(textField); 
      textField.selectAll(); 
      textField.requestFocus(); 
     } 
    } 

    @Override 
    public void cancelEdit() { 
     super.cancelEdit(); 

     setText(String.valueOf(getItem())); 
     setGraphic(null); 
    } 

    @Override 
    public void updateItem(Integer item, boolean empty) { 
     super.updateItem(item, empty); 

     if (empty) { 
      setText(null); 
      setGraphic(null); 
     } else { 
      if (isEditing()) { 
       if (textField != null) { 
        textField.setText(getString()); 

       } 
       setText(null); 
       setGraphic(textField); 
      } else { 
       setText(getString()); 
       setGraphic(null); 
      } 
     } 
    } 

    private void createTextField() { 
     textField = new TextField(getString()); 
     textField.setMinWidth(this.getWidth() - this.getGraphicTextGap()* 2); 
     textField.focusedProperty().addListener(
      (ObservableValue<? extends Boolean> arg0, 
      Boolean arg1, Boolean arg2) -> { 
       if (!arg2) { 
     XXX   commitEdit(Integer.valueOf(textField.getText())); 
       } 
     }); 
     textField.setOnKeyReleased(new EventHandler<Event>() { 
      @Override 
      public void handle(Event event) { 
       try{ 
        int i = Integer.valueOf(textField.getText()); 
        //digit given... 
        if((i>=0) && (i<10)){//making sure cell is filled with just one digit 
         commitEdit(Integer.valueOf(textField.getText())); 
         int selectedColumn = parentTableView.getSelectionModel().getSelectedCells().get(0).getColumn(); // gets the number of selected column 
         int selectedRow = parentTableView.getSelectionModel().getSelectedCells().get(0).getRow(); 
         if(selectedColumn < numberOfColumns-1){ 
          parentTableView.getSelectionModel().selectNext(); 
          parentTableView.edit(selectedRow, parentTableView.getColumns().get(selectedColumn+1)); 
         }else{ 
          parentTableView.getSelectionModel().select(selectedRow+1, parentTableView.getColumns().get(0)); 
          parentTableView.edit(selectedRow+1, parentTableView.getColumns().get(0)); 

         } 

        }else 
         textField.clear(); 
       }catch(NumberFormatException e){ 
        textField.clear(); 
       } 
      } 
     }); 
    } 

    private String getString() { 
     return getItem() == null ? "" : getItem().toString(); 
    } 
} 
+0

пусть пользовательский клетка показать ничего, если значение равно 0 (или еще не инициализировано, требуется немного дополнительной логики) – kleopatra

+0

Я не знаю, как сделать ячейки ничего не показывать .... – Tomasz

+0

@Tomek 'setText (null)' в вашем рендерере? – eckig

ответ

2

Разрешить null значения в столбце с помощью ObjectProperty<Integer> вместо IntegerProperty. Это дает более естественный способ определить «не инициализированный», чем представление его 0 (или некоторым другим значением прокси).

Затем вы можете использовать TextFieldTableCell, а просто поставить пользовательские StringConverter<Integer>:

public class MyData{ //dont forget about public because you wont get acces to properties 
    private ObservableList<ObjectProperty<Integer>> cellValue = FXCollections.observableArrayList(); 

    public MyData(int howManyColumns) { 
     for(int i=0; i<howManyColumns; ++i) 
      this.cellValue.add(new SimpleObjectProperty<>(new Random().nextInt(10))); 
    } 

// ... 
} 

и

newColumn.setCellValueFactory(cellData -> cellData.getValue().getCellValue(i)); 
    newColumn.setCellFactory(TextFieldTableCell.<MyData, Integer>forTableColumn(new StringConverter<Integer>() { 
    @Override 
    public String toString(Integer i) { 
     if (i == null) { 
      return "" ; 
     } else { 
      return i.toString(); 
     } 
    } 

    @Override 
    public Integer fromString(String string) { 
     if (string.trim().length() == 0) { 
      return null ; 
     } else { 
      try { 
       return Integer.valueOf(string); 
      } catch (NumberFormatException nfe) { 
       return null ; 
      } 
     } 
    } 
})); 

Полный пример:

import java.util.Random; 
import java.util.function.Function; 

import javafx.application.Application; 
import javafx.beans.property.ObjectProperty; 
import javafx.beans.property.SimpleObjectProperty; 
import javafx.beans.property.SimpleStringProperty; 
import javafx.beans.property.StringProperty; 
import javafx.beans.value.ObservableValue; 
import javafx.scene.Scene; 
import javafx.scene.control.TableColumn; 
import javafx.scene.control.TableView; 
import javafx.scene.control.cell.TextFieldTableCell; 
import javafx.scene.layout.BorderPane; 
import javafx.stage.Stage; 
import javafx.util.StringConverter; 

public class TableViewWithEmptyIntegerColumn extends Application { 

    @Override 
    public void start(Stage primaryStage) { 
     TableView<Item> table = new TableView<>(); 
     table.setEditable(true); 
     TableColumn<Item, String> nameCol = createCol("Name", Item::nameProperty); 
     TableColumn<Item, Integer> valueCol = createCol("Value", Item::valueProperty); 
     valueCol.setEditable(true); 

     valueCol.setCellFactory(TextFieldTableCell.forTableColumn(new StringConverter<Integer>() { 

      @Override 
      public String toString(Integer i) { 
       if (i == null) { 
        return "" ; 
       } else { 
        return i.toString() ; 
       } 
      } 

      @Override 
      public Integer fromString(String string) { 
       if (string.trim().length() == 0) { 
        return null ; 
       } else { 
        // better to check for a valid int format instead of using try-catch... 
        try { 
         return Integer.valueOf(string); 
        } catch (NumberFormatException nfe) { 
         return null ; 
        } 
       } 
      } 

     })); 

     Random rng = new Random(); 
     for (int i=1; i<=20; i++) { 
      if (rng.nextDouble() < 0.5) { 
       table.getItems().add(new Item("Item "+i)); 
      } else { 
       table.getItems().add(new Item("Item "+i, rng.nextInt(10)+1)); 
      } 
     } 

     table.getColumns().addAll(nameCol, valueCol); 
     primaryStage.setScene(new Scene(new BorderPane(table), 400, 600)); 
     primaryStage.show(); 
    } 

    private <S,T> TableColumn<S,T> createCol(String title, Function<S, ObservableValue<T>> property) { 
     TableColumn<S,T> col = new TableColumn<>(title); 
     col.setCellValueFactory(cellData -> property.apply(cellData.getValue())); 
     return col ; 
    } 

    public static class Item { 
     private final StringProperty name = new SimpleStringProperty(); 
     private final ObjectProperty<Integer> value = new SimpleObjectProperty<>(); 

     public Item(String name, Integer value) { 
      setName(name); 
      setValue(value); 
     } 

     public Item(String name) { 
      this(name, null); 
     } 

     public final StringProperty nameProperty() { 
      return this.name; 
     } 

     public final String getName() { 
      return this.nameProperty().get(); 
     } 

     public final void setName(final String name) { 
      this.nameProperty().set(name); 
     } 

     public final ObjectProperty<Integer> valueProperty() { 
      return this.value; 
     } 

     public final Integer getValue() { 
      return this.valueProperty().get(); 
     } 

     public final void setValue(final Integer value) { 
      this.valueProperty().set(value); 
     } 


    } 

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

. На самом деле стандартный «IntegerStringConverter» даже работает здесь, хотя он и не работает, t обрабатывает нецелые, непустые значения элегантно. –

+0

Кажется, что это работает, hovwer с моей фабрикой ячеек (что мне нужно), это приносит мне много проблем при редактировании, и я не уверен, что смогу справиться с этим. – Tomasz

+0

Вам, вероятно, потребуется опубликовать код для вашей реализации ячейки. –