我想编写一个自定义JavaFX自定义控件,如DatePicker和ColorPicker,但我不需要显示Calendarview或调色板,而是需要显示包含TableView和TextField的GridPane。我不知道如何使这个泛型适用于任何数据模型,我如何设置TableView的列。 为此,我已经从MVC类扩展(ComboBoxBase,ComboBoxPopupControl,ComboBoxBaseBehavior)。但是对于我如何正确实现这种自定义控件似乎很复杂。
到目前为止,这是我的代码:
public class ComboBoxTablePopup<S> extends ComboBoxBase {
/***************************************************************************
* *
* Static properties and methods *
* *
**************************************************************************/
private static <T> StringConverter<T> defaultStringConverter() {
return new StringConverter<T>() {
@Override
public String toString(T t) {
return t == null ? null : t.toString();
}
@Override
public T fromString(String string) {
return (T) string;
}
};
}
/***************************************************************************
* *
* Constructors *
* *
**************************************************************************/
/**
* Creates a default ComboboxTablePopup instance with an empty
* {@link #itemsProperty() items} list and default
* {@link #selectionModelProperty() selection model}.
*/
public ComboBoxTablePopup() {
this(FXCollections.<S>emptyObservableList());
}
/**
* Creates a default ComboboxTablePopup instance with the provided items list and
* a default {@link #selectionModelProperty() selection model}.
*/
public ComboBoxTablePopup(ObservableList<S> items) {
setItems(items);
getStyleClass().add(DEFAULT_STYLE_CLASS);
setEditable(true);
setPromptText("Plz Search for a pirticular term");
}
private static final String DEFAULT_STYLE_CLASS = "combobox-table-popup";
private ReadOnlyObjectWrapper<TextField> editor;
private ObjectProperty<ObservableList<S>> items = new SimpleObjectProperty<ObservableList<S>>(this, "items");
public final void setItems(ObservableList<S> value) {
itemsProperty().set(value);
}
public final ObservableList<S> getItems() {
return items.get();
}
public ObjectProperty<ObservableList<S>> itemsProperty() {
return items;
}
// Converter
public ObjectProperty<StringConverter<S>> converterProperty() {
return converter;
}
private ObjectProperty<StringConverter<S>> converter =
new SimpleObjectProperty<StringConverter<S>>(this, "converter", ComboBoxTablePopup.<S>defaultStringConverter());
public final void setConverter(StringConverter<S> value) {
converterProperty().set(value);
}
public final StringConverter<S> getConverter() {
return converterProperty().get();
}// Create a symmetric (format/parse) converter with the default locale.
// Editor
public TextField getEditor() {
return editorProperty().get();
}
public ReadOnlyObjectProperty<TextField> editorProperty() {
if (editor == null) {
editor = new ReadOnlyObjectWrapper<TextField>(this, "editor");
editor.set(new ComboBoxListViewSkin.FakeFocusTextField());
}
return editor.getReadOnlyProperty();
}
@Override
protected Skin<?> createDefaultSkin() {
return new ComboBoxTablePopupSkin<>(this);
}
}
public class ComboBoxTablePopupBehavior extends ComboBoxBaseBehavior {
/**
* @param comboBox
*/
public ComboBoxTablePopupBehavior(ComboBoxBase comboBox) {
super(comboBox, COMBOBOX_TABLE_POPUP_BINDINGS);
}
/***************************************************************************
* *
* Key event handling *
* *
**************************************************************************/
protected static final List<KeyBinding> COMBOBOX_TABLE_POPUP_BINDINGS = new ArrayList<KeyBinding>();
static {
COMBOBOX_TABLE_POPUP_BINDINGS.add(new KeyBinding(KeyCode.ENTER, "togglePopup"));
COMBOBOX_TABLE_POPUP_BINDINGS.addAll(COMBO_BOX_BASE_BINDINGS);
}
}
public class ComboBoxTablePopupSkin扩展了ComboBoxPopupControl {
private ComboBoxTablePopup comboBoxTablePopup;
private ObservableList<S> comboboxTablePopupItems;
private TextField displayNode;
private TableView<S> tableViewPopupContent;
private ObservableList<S> tableViewItems;
public ComboBoxTablePopupSkin(ComboBoxTablePopup comboBoxTablePopup) {
super(comboBoxTablePopup, new ComboBoxTablePopupBehavior(comboBoxTablePopup));
this.comboBoxTablePopup = comboBoxTablePopup;
updateComboBoxTablePopupItems();
tableViewPopupContent = createTableView();
getChildren().add(tableViewPopupContent);
registerChangeListener(getEditor().textProperty(), "text");
}
@Override
protected Node getPopupContent() {
return this.tableViewPopupContent;
}
@Override
protected TextField getEditor() {
return ((ComboBoxTablePopup) getSkinnable()).getEditor();
}
@Override
protected StringConverter getConverter() {
return ((ComboBoxTablePopup) getSkinnable()).getConverter();
}
@Override
public Node getDisplayNode() {
if (displayNode == null) {
displayNode = getEditableInputNode();
displayNode.getStylesheets().add("ComboBoxTable-display-node");
updateDisplayNode();
}
displayNode.setEditable(comboBoxTablePopup.isEditable());
return displayNode;
}
@Override
protected void handleControlPropertyChanged(String p) {
if ("text".equalsIgnoreCase(p)) {
if (getEditor().textProperty().get().isEmpty()) {
hide();
} else
show();
} else {
super.handleControlPropertyChanged(p);
}
}
public void updateComboBoxTablePopupItems() {
comboboxTablePopupItems = comboBoxTablePopup.getItems();
comboboxTablePopupItems = comboboxTablePopupItems == null ? FXCollections.<S>emptyObservableList() : comboboxTablePopupItems;
}
private TableView<S> createTableView() {
final TableView<S> tableView = new TableView<>();
tableView.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
tableView.setFocusTraversable(false);
tableView.getSelectionModel().selectedItemProperty().addListener(o -> {
int index = tableView.getSelectionModel().getSelectedIndex();
System.out.println("selected item changed");
});
return tableView;
}
}