我正在通过扩展ExtendedTableView创建类TableView,我想允许用户使用预先设置的设置创建一个ExtendedTableView并允许单元格可编辑。以下是一个代码部分,简要显示了如何编辑单元格:

public void start(Stage stage) {
        Scene scene = new Scene(new Group());
        stage.setTitle("Table View Sample");
        final Label label = new Label("Address Book");
        label.setFont(new Font("Arial", 20));
        //Create a customer cell factory so that cells can support editing.
        Callback<TableColumn, TableCell> cellFactory = new Callback<TableColumn, TableCell>() {
            @Override
            public TableCell call(TableColumn p) {
                return new EditingCell();
            }
        };

        //Set up the columns
        TableColumn firstNameCol = new TableColumn("First Name");
        firstNameCol.setMinWidth( 100 );
        firstNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("firstName"));
        firstNameCol.setCellFactory(cellFactory);
        TableColumn lastNameCol = new TableColumn("Last Name");
        lastNameCol.setMinWidth( 100 );
        lastNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("lastName"));
        lastNameCol.setCellFactory(cellFactory);
//        lastNameCol.setEditable( false );
        TableColumn emailCol = new TableColumn("Email");
        emailCol.setMinWidth(400);
        TableColumn primaryEmailCol = new TableColumn("Primary Email");
        primaryEmailCol.setMinWidth(200);
        primaryEmailCol.setCellValueFactory(new PropertyValueFactory<Person, String>("primaryEmail"));
        primaryEmailCol.setCellFactory(cellFactory);
        //Make this column un-editable
        primaryEmailCol.setEditable( false );
        TableColumn secondaryEmailCol = new TableColumn("Secondary Email");
        secondaryEmailCol.setMinWidth(200);
        secondaryEmailCol.setCellValueFactory(new PropertyValueFactory<Person, String>("secondaryEmail"));
        secondaryEmailCol.setCellFactory(cellFactory);
//        secondaryEmailCol.setEditable( false );
        emailCol.getColumns().addAll(primaryEmailCol, secondaryEmailCol);
        //Add the columns and data to the table.
        table.setItems(data);
        table.getColumns().addAll(firstNameCol, lastNameCol, emailCol);
        //Make the table editable
        table.setEditable(true);
        //Modifying the firstName property
        firstNameCol.setOnEditCommit(new EventHandler<CellEditEvent<Person, String>>() {
            @Override
            public void handle(CellEditEvent<Person, String> t) {
                ((Person) t.getTableView().getItems().get(t.getTablePosition().getRow())).setFirstName(t.getNewValue());
            }
        });
        //Modifying the lastName property
        lastNameCol.setOnEditCommit(new EventHandler<CellEditEvent<Person, String>>() {
            @Override
            public void handle(CellEditEvent<Person, String> t) {
                ((Person) t.getTableView().getItems().get(t.getTablePosition().getRow())).setLastName(t.getNewValue());
            }
        });
        //Modifying the primary email property
        primaryEmailCol.setOnEditCommit(new EventHandler<CellEditEvent<Person, String>>() {
            @Override
            public void handle(CellEditEvent<Person, String> t) {
                ((Person) t.getTableView().getItems().get(t.getTablePosition().getRow())).setPrimaryEmail(t.getNewValue());
            }
        });
        //Modifying the secondary email property
        secondaryEmailCol.setOnEditCommit(new EventHandler<CellEditEvent<Person, String>>() {
            @Override
            public void handle(CellEditEvent<Person, String> t) {
                ((Person) t.getTableView().getItems().get(t.getTablePosition().getRow())).setSecondaryEmail(t.getNewValue());
            }
        });
        final VBox vbox = new VBox();
        vbox.setSpacing(5);
        vbox.getChildren().addAll(label, table);
        vbox.setPadding(new Insets(10, 0, 0, 10));
        ((Group) scene.getRoot()).getChildren().addAll(vbox);
        stage.setScene(scene);
        stage.show();
}

public class EditingCell extends TableCell<Person, String> {
    private TextField textField;
    public EditingCell() {
    }
    @Override
    public void startEdit() {
        super.startEdit();
        if (textField == null) {
            createTextField();
        }
        setGraphic(textField);
        setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
        Platform.runLater(new Runnable() {
            @Override
            public void run() {
                textField.requestFocus();
                textField.selectAll();
            }
        });
    }
    @Override
    public void cancelEdit() {
        super.cancelEdit();
        setText((String) getItem());
        setContentDisplay(ContentDisplay.TEXT_ONLY);
    }
    @Override
    public void updateItem(String item, boolean empty) {
        super.updateItem(item, empty);
        if (empty) {
            setText(null);
            setGraphic(null);
        } else {
            if (isEditing()) {
                if (textField != null) {
                    textField.setText(getString());
                }
                setGraphic(textField);
                setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
            } else {
                setText(getString());
                setContentDisplay(ContentDisplay.TEXT_ONLY);
            }
        }
    }
    private void createTextField() {
        textField = new TextField(getString());
        textField.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2);
        textField.setOnKeyPressed(new EventHandler<KeyEvent>() {
            @Override
            public void handle(KeyEvent t) {
                if (t.getCode() == KeyCode.ENTER) {
                    commitEdit(textField.getText());
                } else if (t.getCode() == KeyCode.ESCAPE) {
                    cancelEdit();
                } else if (t.getCode() == KeyCode.TAB) {
                    commitEdit(textField.getText());
                    TableColumn nextColumn = getNextColumn(!t.isShiftDown());
                    if (nextColumn != null) {
                        getTableView().edit(getTableRow().getIndex(), nextColumn);
                    }
                }
            }
        });
        textField.focusedProperty().addListener(new ChangeListener<Boolean>() {
            @Override
            public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
                if (!newValue && textField != null) {
                    commitEdit(textField.getText());
                }
            }
        });
    }
    private String getString() {
        return getItem() == null ? "" : getItem().toString();
    }
    /**
     *
     * @param forward true gets the column to the right, false the column to the left of the current column
     * @return
     */
    private TableColumn<Person, ?> getNextColumn(boolean forward) {
        List<TableColumn<Person, ?>> columns = new ArrayList<>();
        for (TableColumn<Person, ?> column : getTableView().getColumns()) {
            columns.addAll(getLeaves(column));
        }
        //There is no other column that supports editing.
        if (columns.size() < 2) {
            return null;
        }
        int currentIndex = columns.indexOf(getTableColumn());
        int nextIndex = currentIndex;
        if (forward) {
            nextIndex++;
            if (nextIndex > columns.size() - 1) {
                nextIndex = 0;
            }
        } else {
            nextIndex--;
            if (nextIndex < 0) {
                nextIndex = columns.size() - 1;
            }
        }
        return columns.get(nextIndex);
    }

    private List<TableColumn<Person, ?>> getLeaves(TableColumn<Person, ?> root) {
        List<TableColumn<Person, ?>> columns = new ArrayList<>();
        if (root.getColumns().isEmpty()) {
            //We only want the leaves that are editable.
            if (root.isEditable()) {
                columns.add(root);
            }
            return columns;
        } else {
            for (TableColumn<Person, ?> column : root.getColumns()) {
                columns.addAll(getLeaves(column));
            }
            return columns;
        }
    }
}


上面的示例显示了EditingCell extends TableCell<Person, String>类,但是我想做的是这样的:

public class ExtendedTableView extends TableView{
  public ExtendedTableView(){
    init();
  }
  private void init(){
    this.setEditable(true);
    this.setTableMenuButtonVisible(true);
  }
}

public class EditingCell extends TableCell<UNKNOWN, String>{

    private TableColumn<UNKNOWN, ?> getNextColumn(boolean forward) {
    }

}


我希望用户能够执行ExtendedTableView table = new ExtendedTableView()之类的操作来获取具有所有设置且可编辑单元格的表格。不必添加更多行,例如传入class / classtype(而不是Person class)。但是这个想法是创建一个自定义的表格视图,这样它就足够通用了,用户不需要知道使单元格可编辑等所需的代码。

public class MyClass{
  public MyClass(){
  }

  public void createTable(){
    ExtendedTableView tableA = new ExtendedTableView();
    ExtendedTableView tableB = new ExtendedTableView();
    /*somehow find a way to pass classA into tableA so that class table cell can be something like this: "TableCell < ClassA, String>"*/
  }
}

public class classA{
}

public class classB{
}

最佳答案

通常,如果您在2010年之后的任何时间使用原始类型,则可能不是最佳方式。 (特别是,除非您与旧版(即Java 1.5之前的版本)的代码进行交互,否则请不要使用原始类型。)

在这种情况下,您只需要使您的ExtendedTableView类成为通用类,即为其提供类型参数:

public class ExtendedTableView<T> extends TableView<T> {

    public ExtendedTableView(){
        init();
    }
    private void init(){
        this.setEditable(true);
        this.setTableMenuButtonVisible(true);
    }
}


同样,对于您的EditingCell类:

public class EditingCell<T> extends TableCell<T, String>{

    private TableColumn<T, ?> getNextColumn(boolean forward) {
    }

}


现在,给定

public class ClassA { /* ... */ }




public class ClassB { /* ... */ }


您的客户代码可以做到

ExtendedTableView<ClassA> tableA = new ExtendedTableView<>();
ExtendedTableView<ClassB> tableB = new ExtendedTableView<>();


你可以做类似的事情

TableColumn<ClassA, String> someColumn = new TableColumn<>();
tableA.getColumns().add(someColumn);
someColumn.setCellFactory(tc -> new EditingCell<>());

10-06 00:15