0

我有一个 TableView 和 Data 类,列的整数属性。但是,我希望列首先显示空单元格,以便用户可以输入他想要的值。

现在这是不可能的,因为在创建 Data 对象时,必须使用初始值创建整数值,因此表格显示已经填充了数字。

  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();
    }
}
4

1 回答 1

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);
    }
}
于 2015-02-05T14:32:30.687 回答