class扩展另一个类,其参数仅在运行时期间已知

时间:2018-04-25 17:21:35

标签: java javafx

我正在通过扩展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类),这无关紧要。但我们的想法是创建一个自定义的tableview,使其足够通用,用户不需要知道使单元格可编辑等所需的代码。

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{
}

1 个答案:

答案 0 :(得分:1)

作为一般规则,如果您在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<>());