在我的TableView中,我有多个可编辑的列。在这里,两列包含组合框,其他两列包含文本字段。一切都很好,但是问题是每当我在表中的0
索引处添加新行时,我都会丢失从列表中选择的组合框值。我发现其背后的原因是table.refresh()
,但是如果我停止使用table.refresh()
,则我的组合框将保留值,但是新行的文本字段将显示上一行的值(我正在添加新行的索引为0,并且有一行现在索引为1)。如何在组合框中保留所选值,并且不显示上一行的文本字段值?
这是我的代码。 TestController
。
public class TestController implements Initializable {
@FXML
private TableColumn colNumber;
@FXML
private TableColumn colEmergency;
@FXML
private Button btnAdd;
@FXML
private TableColumn colCountry;
@FXML
private TableColumn colSMS;
@FXML
private TableColumn colArea;
@FXML
private TableColumn colPhoneType;
@FXML
private Button btnSaveTable;
@FXML
private TableView<ModelPhone> table;
private ObservableList<String> phoneType = FXCollections.observableArrayList("Cell", "Lan");
private final ObservableList countryList = FXCollections.observableArrayList("A", "B", "C");
@Override
public void initialize(URL location, ResourceBundle resources) {
table.setEditable(true);
table.getSelectionModel().setCellSelectionEnabled(true);
colArea.setEditable(true);
colCountry.setEditable(true);
colEmergency.setEditable(true);
colNumber.setEditable(true);
colPhoneType.setEditable(true);
colSMS.setEditable(true);
Callback<TableColumn, TableCell> cellFactory = new Callback<TableColumn, TableCell>() {
public TableCell call(TableColumn p) {
return new EditingCell();
}
};
table.setRowFactory(tv -> {
TableRow<ModelPhone> row = new TableRow<>();
row.addEventFilter(MouseEvent.MOUSE_PRESSED, e -> {
if (e.getButton() == MouseButton.SECONDARY) {
e.consume();
}
});
return row;
});
colArea.setCellValueFactory(new PropertyValueFactory<ModelPhone, String>("AreaCode"));
colArea.setCellFactory(cellFactory);
colNumber.setCellValueFactory(new PropertyValueFactory<ModelPhone, String>("PhoneNumber"));
colNumber.setCellFactory(cellFactory);
colSMS.setCellValueFactory(new PropertyValueFactory<>("SMScheck"));
colSMS.setCellFactory(tc -> new CheckBoxTableCell<>());
colEmergency.setCellValueFactory(new PropertyValueFactory<>("Emergencycheck"));
colEmergency.setCellFactory(tc -> new CheckBoxTableCell<>());
colPhoneType.setCellValueFactory(new PropertyValueFactory<ModelPhone, String>("PhoneType"));
// colPhoneType.setCellFactory(tc -> new ComboBoxTableCell<>(PhoneType));
colPhoneType.setCellFactory(tc -> {
ComboBox combo = new ComboBox();
combo.getItems().addAll(phoneType);
combo.setPrefWidth(colPhoneType.getWidth() - 5);
combo.setMaxWidth(colPhoneType.getWidth() - 5);
TableCell<ModelPhone, String> cell = new TableCell<ModelPhone, String>() {
@Override
protected void updateItem(String reason, boolean empty) {
super.updateItem(reason, empty);
if (empty) {
setGraphic(null);
} else {
// combo.setValue(reason);
setText(this.getItem());
setGraphic(combo);
}
}
};
// combo.getSelectionModel().select(0);
combo.setOnAction(
e -> table.getItems().get(cell.getIndex()).setPhoneType(String.valueOf(combo.getValue())));
return cell;
});
colPhoneType.setOnEditCommit(new EventHandler<CellEditEvent<ModelPhone, String>>() {
@Override
public void handle(TableColumn.CellEditEvent<ModelPhone, String> t) {
((ModelPhone) t.getTableView().getItems().get(t.getTablePosition().getRow()))
.setPhoneType(t.getNewValue());
}
});
colCountry.setCellValueFactory(new PropertyValueFactory<ModelPhone, String>("CountryName"));
colCountry.setCellFactory(tc -> {
ComboBox combo = new ComboBox();
combo.getItems().addAll(countryList);
combo.setPrefWidth(colCountry.getWidth() - 5);
combo.setMaxWidth(colCountry.getWidth() - 5);
// combo.getSelectionModel().selectFirst();
TableCell<ModelPhone, String> cell = new TableCell<ModelPhone, String>() {
@Override
protected void updateItem(String reason, boolean empty) {
super.updateItem(reason, empty);
if (empty) {
setGraphic(null);
} else {
// combo.setValue(reason);
setText(this.getItem());
setGraphic(combo);
}
}
};
combo.setOnAction(
e -> table.getItems().get(cell.getIndex()).setCountryName(String.valueOf(combo.getValue())));
return cell;
});
colCountry.setOnEditCommit(new EventHandler<CellEditEvent<ModelPhone, String>>() {
@Override
public void handle(TableColumn.CellEditEvent<ModelPhone, String> t) {
((ModelPhone) t.getTableView().getItems().get(t.getTablePosition().getRow()))
.setCountryName(t.getNewValue());
}
});
}
@FXML
void addRow(ActionEvent event) {
table.layout();
table.getItems().add(0, new ModelPhone());
table.refresh();// losing selected combo box value
}
@FXML
void saveTable(ActionEvent event) {
}
}
这是我的Test.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane prefHeight="209.0" prefWidth="719.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.biziitech.bgeneral.view.TestController">
<children>
<TableView fx:id="table" layoutX="10.0" layoutY="46.0" maxHeight="-Infinity" prefHeight="150.0" prefWidth="696.0" AnchorPane.bottomAnchor="0.0" AnchorPane.topAnchor="46.0">
<columnResizePolicy>
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
</columnResizePolicy>
<columns>
<TableColumn fx:id="colPhoneType" maxWidth="3000.0" prefWidth="206.0" text="Phone Type" />
<TableColumn fx:id="colCountry" maxWidth="3000.0" prefWidth="206.0" text="Country" />
<TableColumn fx:id="colArea" maxWidth="500.0" minWidth="102.0" prefWidth="102.0" text="Area Code" />
<TableColumn fx:id="colEmergency" maxWidth="74.0" minWidth="74.0" prefWidth="74.0" text="Emergency?" />
<TableColumn fx:id="colSMS" maxWidth="74.0" minWidth="49.0" prefWidth="49.0" text="SMS?" />
<TableColumn fx:id="colNumber" prefWidth="256.0" text="Phone Number" />
</columns>
</TableView>
<Button fx:id="btnAdd" layoutX="14.0" layoutY="8.0" mnemonicParsing="false" onAction="#addRow" text="Add" />
</children>
</AnchorPane>
这是我的EditingCell
类,用于表视图内的文本字段。
public class EditingCell<S, T> extends TableCell<S, T> {
private TextField textField;
public EditingCell() {
}
@Override
public void startEdit() {
if (!isEmpty()) {
super.startEdit();
if (textField == null) {
createTextField();
}
setGraphic(textField);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
// textField.selectAll();
Platform.runLater(new Runnable() {
@Override
public void run() {
textField.requestFocus();
textField.selectAll();
}
});
}
}
@Override
public void cancelEdit() {
super.cancelEdit();
setText((String) getItem());
setGraphic(null);
setContentDisplay(ContentDisplay.TEXT_ONLY);
}
@Override
public void updateItem(T 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);
}
}
}
@Override
public void commitEdit(T item) {
// This block is necessary to support commit on losing focus, because the
// baked-in mechanism
// sets our editing state to false before we can intercept the loss of focus.
// The default commitEdit(...) method simply bails if we are not editing...
if (!isEditing() && !item.equals(getItem())) {
TableView<S> table = getTableView();
if (table != null) {
TableColumn<S, T> column = getTableColumn();
CellEditEvent<S, T> event = new CellEditEvent<>(table,
new TablePosition<S, T>(table, getIndex(), column), TableColumn.editCommitEvent(), item);
Event.fireEvent(column, event);
}
super.cancelEdit(); // this fires an invalid EditCancelEvent.
// update the item within this cell, so that it represents the new value
updateItem(item, false);
if (table != null) {
// reset the editing cell on the TableView
table.edit(-1, null);
// request focus back onto the table, only if the current focus
// owner has the table as a parent (otherwise the user might have
// clicked out of the table entirely and given focus to something else.
// It would be rude of us to request it back again.
// requestFocusOnControlOnlyIfCurrentFocusOwnerIsChild(table);
}
}
super.commitEdit(item);
setContentDisplay(ContentDisplay.TEXT_ONLY);
}
private void createTextField() {
textField = new TextField(getString());
// textField.setMinWidth(this.getWidth() - this.getGraphicTextGap()
// * 2);
textField.focusedProperty().addListener(new ChangeListener<Boolean>() {
@Override
public void changed(ObservableValue<? extends Boolean> arg0, Boolean arg1, Boolean arg2) {
if (!arg2) {
commitEdit((T) textField.getText());
}
}
});
/*
* textField.focusedProperty().addListener((obs, wasFocused, isNowFocused) -> {
* if (!isNowFocused) { commitEdit((T)textField.getText()); } });
*/
textField.setOnKeyPressed(new EventHandler<KeyEvent>() {
@Override
public void handle(KeyEvent t) {
if (t.getCode() == KeyCode.ENTER) {
commitEdit((T) textField.getText());
} else if (t.getCode() == KeyCode.ESCAPE) {
cancelEdit();
} else if (t.getCode() == KeyCode.TAB) {
commitEdit((T) textField.getText());
TableColumn nextColumn = getNextColumn(!t.isShiftDown());
if (nextColumn != null) {
getTableView().edit(getTableRow().getIndex(), nextColumn);
}
} else if (t.getCode() == KeyCode.RIGHT) {
commitEdit((T) textField.getText());
getTableView().getSelectionModel().selectRightCell();
TableColumn nextColumn = getNextColumn(!t.isShiftDown());
if (nextColumn != null) {
getTableView().edit(getTableRow().getIndex(), nextColumn);
}
t.consume();
} else if (t.getCode() == KeyCode.LEFT) {
commitEdit((T) textField.getText());
getTableView().getSelectionModel().selectLeftCell();
TableColumn prevColumn = getNextColumn(false);
if (prevColumn != null) {
getTableView().edit(getTableRow().getIndex(), prevColumn);
}
t.consume();
} else if (t.getCode() == KeyCode.UP) {
commitEdit((T) textField.getText());
getTableView().getSelectionModel().selectAboveCell();
int i = getTableView().getSelectionModel().getSelectedIndex();
if (i >= 0)
getTableView().edit(i, getTableColumn());
t.consume();
} else if (t.getCode() == KeyCode.DOWN) {
commitEdit((T) textField.getText());
getTableView().getSelectionModel().selectBelowCell();
int i = getTableView().getSelectionModel().getSelectedIndex();
if (i >= 0)
getTableView().edit(i, getTableColumn());
t.consume();
}
}
});
/*
* textField.setOnMouseClicked(new EventHandler<MouseEvent>() {
*
* @Override public void handle(MouseEvent t) { // TODO Auto-generated method
* stub if ( t.getButton() == MouseButton.PRIMARY && t.getClickCount() == 2 ) {
* commitEdit((T)textField.getText()); t.consume(); } } });
*/
}
private String getString() {
return getItem() == null ? "" : getItem().toString();
}
private TableColumn<S, ?> getNextColumn(boolean forward) {
List<TableColumn<S, ?>> columns = new ArrayList<>();
for (TableColumn<S, ?> 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<S, ?>> getLeaves(TableColumn<S, ?> root) {
List<TableColumn<S, ?>> 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<S, ?> column : root.getColumns()) {
columns.addAll(getLeaves(column));
}
return columns;
}
}
}
ModelPhone.java
public class ModelPhone {
private LongProperty phoneId = new SimpleLongProperty();
private LongProperty userId = new SimpleLongProperty();
private LongProperty countryId = new SimpleLongProperty();
private IntegerProperty typeId = new SimpleIntegerProperty();
private StringProperty countryName = new SimpleStringProperty();
private StringProperty phoneType = new SimpleStringProperty();
private StringProperty areaCode = new SimpleStringProperty();
private StringProperty phoneNumber = new SimpleStringProperty();
private StringProperty remarks = new SimpleStringProperty();
private IntegerProperty entered_By = new SimpleIntegerProperty();
private Timestamp entryTimestap;
private IntegerProperty updatedBy = new SimpleIntegerProperty();
private Timestamp updateTimestap;
private IntegerProperty activeStatus = new SimpleIntegerProperty();
private IntegerProperty SMS = new SimpleIntegerProperty();
private IntegerProperty emergency = new SimpleIntegerProperty();
private SimpleBooleanProperty SMScheck = new SimpleBooleanProperty();
private SimpleBooleanProperty emergencycheck = new SimpleBooleanProperty();
private SimpleBooleanProperty active = new SimpleBooleanProperty();
public ModelPhone() {
}
public ModelPhone(LongProperty phoneId, LongProperty userId, LongProperty countryId, IntegerProperty typeId,
StringProperty countryName, StringProperty phoneType, StringProperty areaCode, StringProperty phoneNumber,
StringProperty remarks, IntegerProperty entered_By, Timestamp entryTimestap, IntegerProperty updatedBy,
Timestamp updateTimestap, IntegerProperty activeStatus, IntegerProperty sMS, IntegerProperty emergency,
SimpleBooleanProperty sMScheck, SimpleBooleanProperty emergencycheck, SimpleBooleanProperty active) {
super();
this.phoneId = phoneId;
this.userId = userId;
this.countryId = countryId;
this.typeId = typeId;
this.countryName = countryName;
this.phoneType = phoneType;
this.areaCode = areaCode;
this.phoneNumber = phoneNumber;
this.remarks = remarks;
this.entered_By = entered_By;
this.entryTimestap = entryTimestap;
this.updatedBy = updatedBy;
this.updateTimestap = updateTimestap;
this.activeStatus = activeStatus;
SMS = sMS;
this.emergency = emergency;
SMScheck = sMScheck;
this.emergencycheck = emergencycheck;
this.active = active;
}
public final LongProperty phoneIdProperty() {
return this.phoneId;
}
public final long getPhoneId() {
return this.phoneIdProperty().get();
}
public final void setPhoneId(final long phoneId) {
this.phoneIdProperty().set(phoneId);
}
public final LongProperty userIdProperty() {
return this.userId;
}
public final long getUserId() {
return this.userIdProperty().get();
}
public final void setUserId(final long userId) {
this.userIdProperty().set(userId);
}
public final LongProperty countryIdProperty() {
return this.countryId;
}
public final long getCountryId() {
return this.countryIdProperty().get();
}
public final void setCountryId(final long countryId) {
this.countryIdProperty().set(countryId);
}
public final IntegerProperty typeIdProperty() {
return this.typeId;
}
public final int getTypeId() {
return this.typeIdProperty().get();
}
public final void setTypeId(final int typeId) {
this.typeIdProperty().set(typeId);
}
public final StringProperty countryNameProperty() {
return this.countryName;
}
public final String getCountryName() {
return this.countryNameProperty().get();
}
public final void setCountryName(final String countryName) {
this.countryNameProperty().set(countryName);
}
public final StringProperty phoneTypeProperty() {
return this.phoneType;
}
public final String getPhoneType() {
return this.phoneTypeProperty().get();
}
public final void setPhoneType(final String phoneType) {
this.phoneTypeProperty().set(phoneType);
}
public final StringProperty areaCodeProperty() {
return this.areaCode;
}
public final String getAreaCode() {
return this.areaCodeProperty().get();
}
public final void setAreaCode(final String areaCode) {
this.areaCodeProperty().set(areaCode);
}
public final StringProperty phoneNumberProperty() {
return this.phoneNumber;
}
public final String getPhoneNumber() {
return this.phoneNumberProperty().get();
}
public final void setPhoneNumber(final String phoneNumber) {
this.phoneNumberProperty().set(phoneNumber);
}
public final StringProperty remarksProperty() {
return this.remarks;
}
public final String getRemarks() {
return this.remarksProperty().get();
}
public final void setRemarks(final String remarks) {
this.remarksProperty().set(remarks);
}
public final IntegerProperty entered_ByProperty() {
return this.entered_By;
}
public final int getEntered_By() {
return this.entered_ByProperty().get();
}
public final void setEntered_By(final int entered_By) {
this.entered_ByProperty().set(entered_By);
}
public final IntegerProperty updatedByProperty() {
return this.updatedBy;
}
public final int getUpdatedBy() {
return this.updatedByProperty().get();
}
public final void setUpdatedBy(final int updatedBy) {
this.updatedByProperty().set(updatedBy);
}
public final IntegerProperty activeStatusProperty() {
return this.activeStatus;
}
public final int getActiveStatus() {
return this.activeStatusProperty().get();
}
public final void setActiveStatus(final int activeStatus) {
this.activeStatusProperty().set(activeStatus);
}
public final IntegerProperty SMSProperty() {
return this.SMS;
}
public final int getSMS() {
return this.SMSProperty().get();
}
public final void setSMS(final int SMS) {
this.SMSProperty().set(SMS);
}
public final IntegerProperty emergencyProperty() {
return this.emergency;
}
public final int getEmergency() {
return this.emergencyProperty().get();
}
public final void setEmergency(final int emergency) {
this.emergencyProperty().set(emergency);
}
public final SimpleBooleanProperty SMScheckProperty() {
return this.SMScheck;
}
public final boolean isSMScheck() {
return this.SMScheckProperty().get();
}
public final void setSMScheck(final boolean SMScheck) {
this.SMScheckProperty().set(SMScheck);
}
public final SimpleBooleanProperty emergencycheckProperty() {
return this.emergencycheck;
}
public final boolean isEmergencycheck() {
return this.emergencycheckProperty().get();
}
public final void setEmergencycheck(final boolean emergencycheck) {
this.emergencycheckProperty().set(emergencycheck);
}
public final SimpleBooleanProperty activeProperty() {
return this.active;
}
public final boolean isActive() {
return this.activeProperty().get();
}
public final void setActive(final boolean active) {
this.activeProperty().set(active);
}
public Timestamp getEntryTimestap() {
return entryTimestap;
}
public void setEntryTimestap(Timestamp entryTimestap) {
this.entryTimestap = entryTimestap;
}
public Timestamp getUpdateTimestap() {
return updateTimestap;
}
public void setUpdateTimestap(Timestamp updateTimestap) {
this.updateTimestap = updateTimestap;
}
@Override
public String toString() {
return "ModelPhone [phoneId=" + phoneId + ", userId=" + userId + ", countryId=" + countryId + ", typeId="
+ typeId + ", countryName=" + countryName + ", phoneType=" + phoneType + ", areaCode=" + areaCode
+ ", phoneNumber=" + phoneNumber + ", remarks=" + remarks + ", entered_By=" + entered_By
+ ", entryTimestap=" + entryTimestap + ", updatedBy=" + updatedBy + ", updateTimestap=" + updateTimestap
+ ", activeStatus=" + activeStatus + ", SMS=" + SMS + ", emergency=" + emergency + ", SMScheck="
+ SMScheck + ", emergencycheck=" + emergencycheck + ", active=" + active + "]";
}
}