TableView,自定义单元格编辑行为

时间:2015-02-04 21:55:14

标签: tableview javafx-8

我有这个适用于TableView的应用程序。它添加/删除新的行或列并存储每个单元格的数据。

public class MyTable extends Application {
private BorderPane root;
private HBox hBox;
private TableView<MyData> tableView;    
private Button buttAddColumn, buttDeleteColumn;
private Button buttAddRow, buttDeleteRow;
private int numberOfColumns = 0;
private ObservableList<MyData> dataList = FXCollections.observableArrayList();
@Override
public void init() throws Exception {
    root = new BorderPane();
    hBox = new HBox();
    buttAddColumn = new Button("Add columns");
    buttDeleteColumn = new Button("Delete columns");
    buttAddRow = new Button("Add rows");
    buttDeleteRow = new Button("Delete rows");
    tableView = new TableView<>();

    tableView.setEditable(true);
    tableView.setItems(dataList);
    hBox.getChildren().addAll(buttAddColumn,buttDeleteColumn,buttAddRow,buttDeleteRow);

    root.setTop(hBox);
    root.setCenter(tableView);


    //----------------------------------------------------------------
    buttAddColumn.setOnAction(new EventHandler<ActionEvent>() {
        @Override
        public void handle(ActionEvent event) {
            buttAddColumnAction(event);
        }
    });
    buttDeleteColumn.setOnAction(new EventHandler<ActionEvent>() {
        @Override
        public void handle(ActionEvent event) {
            buttDeleteColumnAction(event);
        }
    });
    buttAddRow.setOnAction(new EventHandler<ActionEvent>() {
        @Override
        public void handle(ActionEvent event) {
            buttAddRowAction(event);
        }
    });
    buttDeleteRow.setOnAction(new EventHandler<ActionEvent>() {
        @Override
        public void handle(ActionEvent event) {
            buttDeleteRowAction(event);
        }
    });
}

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(i);
    TableColumn<MyData, Integer> newColumn = new TableColumn<>("#" + String.valueOf(++numberOfColumns));    
    newColumn.setCellValueFactory(cellData -> cellData.getValue().getCellValue(i).asObject());
    newColumn.setCellFactory(TextFieldTableCell.<MyData, Integer>forTableColumn(new IntegerStringConverter()));

    tableView.getColumns().add(newColumn);
}
private void buttDeleteColumnAction(ActionEvent event){
    if(numberOfColumns > 0){
        tableView.getColumns().remove(numberOfColumns-1);
        --numberOfColumns;

        if(dataList.size() > 0)
            for(MyData x: dataList) //deleting unnecesary variable
                x.deleteLast();
    }
}
private void buttAddRowAction(ActionEvent event){
    dataList.add(new MyData(numberOfColumns)); 
}
private void buttDeleteRowAction(ActionEvent event){
    if(dataList.size() > 0){//resizing each data object with new variable
        dataList.remove(dataList.size()-1);
    }
}

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

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

    public SimpleIntegerProperty getCellValue(int whichOne) {
        return cellValue.get(whichOne);
    }

    public void setCellValue(int cellValue, int whichOne) {
        this.cellValue.set(whichOne, new SimpleIntegerProperty(cellValue));
    }

    public void addNew(int numberOfNewElement){ //ads another variable for another column
        cellValue.add(new SimpleIntegerProperty(new Random().nextInt(10)));
    }
    public void deleteLast(){ //deletes last variable when column is deleted
        cellValue.remove(cellValue.size()-1);
    }
}

//*******************************************************************
@Override
public void start(Stage primaryStage) throws Exception {
    try {
        Scene scene = new Scene(root,400,400);
        primaryStage.setScene(scene);
        primaryStage.show();
    } catch(Exception e) {
        e.printStackTrace();
    }
}
public static void main(String[] args) {
    launch(args);
}

}

如何更改它,所以当用户双击单元格时,程序会等待直到他从0-9按下单个数字,然后自动接受它并打开下一个单元格以放入另一个数字(所以他不需要手动打开/关闭它们?

我目前不知道如何做到这一点。甚至如何使空单元格等待数据(也许数据类应该包含char变量而不是Integer,那么我可以将值""放到单元格中???)

1 个答案:

答案 0 :(得分:1)

6个小时左右,我已经做到了......

我必须在每个列中添加类似这样的内容,这些列是使用单元格编辑事件的类。

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

此类的实现:

package application;

import application.MyTable.MyData;
import javafx.beans.value.ObservableValue;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;

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

这里有一点点编辑的应用程序类:

public class MyTable extends Application {
private BorderPane root;
private HBox hBox;
private TableView<MyData> tableView;    
private Button buttAddColumn, buttDeleteColumn;
private Button buttAddRow, buttDeleteRow;
private int numberOfColumns = 0;
private ObservableList<MyData> dataList = FXCollections.observableArrayList();

    @Override
    public void init() throws Exception {
        root = new BorderPane();
        buttAddColumn = new Button("Add columns");
        buttDeleteColumn = new Button("Delete columns");
        buttAddRow = new Button("Add rows");
        buttDeleteRow = new Button("Delete rows");
        tableView = new TableView<>();
        hBox = new HBox();
        hBox.getChildren().addAll(buttAddColumn,buttDeleteColumn,buttAddRow,buttDeleteRow);

        tableView.setEditable(true);
        tableView.getSelectionModel().setCellSelectionEnabled(true);
        tableView.setItems(dataList);

        root.setTop(hBox);
        root.setCenter(tableView);

        //----------------------------------------------------------------
        buttAddColumn.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                buttAddColumnAction(event);
            }
        });
        buttDeleteColumn.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                buttDeleteColumnAction(event);
            }
        });
        buttAddRow.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                buttAddRowAction(event);
            }
        });
        buttDeleteRow.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                buttDeleteRowAction(event);
            }
        });

    }

    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(i);

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

        newColumn.setCellValueFactory(cellData -> cellData.getValue().getCellValue(i).asObject());
        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);
    }
    private void buttDeleteColumnAction(ActionEvent event){
        if(numberOfColumns > 0){
            tableView.getColumns().remove(numberOfColumns-1);
            --numberOfColumns;
            --EditingCellNumbers.numberOfColumns;
            if(dataList.size() > 0)
                for(MyData x: dataList) //deleting unnecesary variable
                    x.deleteLast();
        }
    }
    private void buttAddRowAction(ActionEvent event){
        dataList.add(new MyData(numberOfColumns)); 
    }
    private void buttDeleteRowAction(ActionEvent event){
        if(dataList.size() > 0){//resizing each data object with new variable
            dataList.remove(dataList.size()-1);
        }
    }
    //*******************************************************************
    public class MyData{ //dont forget about public because you wont get acces to properties
        private ObservableList<SimpleIntegerProperty> cellValue = FXCollections.observableArrayList();

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

        public SimpleIntegerProperty getCellValue(int whichOne) {
            return cellValue.get(whichOne);
        }

        public void setCellValue(int cellValue, int whichOne) {
            this.cellValue.set(whichOne, new SimpleIntegerProperty(cellValue));
        }

        public void addNew(int numberOfNewElement){ //ads another variable for another column
            cellValue.add(new SimpleIntegerProperty(new Random().nextInt(10)));
        }
        public void deleteLast(){ //deletes last variable when column is deleted
            cellValue.remove(cellValue.size()-1);
        }
    }

    //*******************************************************************
    @Override
    public void start(Stage primaryStage) throws Exception {
        try {
            Scene scene = new Scene(root,400,400);
            primaryStage.setScene(scene);
            primaryStage.show();
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args) {
        launch(args);
    }

}

很多代码,但也许有人会在将来使用它:P