How to work with JavaFx TableView with Custom Table Cell using editable Combobox cells

504 Views Asked by At

I'd like to create a table with following features

  • Edit on Key press
  • Enter key = next Row
  • Tab Key = next Column
  • Escape key = Cancel Edit

The Window Looks As Follows enter image description here

The main problem that arises when we focus on combo box the focus moves out of the table. I want a solution that the focus remains in the table or to next cell in the table and commits the selected value of the combo box. The combo box is of the type Item.

ComboBox<Item> items = new ComboBox<>();

The Table is as follows

public TableView<Purchase> _purchase_table;
public TableColumn<Purchase, String> _id;
public TableColumn<Purchase, Item> _name_of_item; //Of Type Purchase,Item
public TableColumn<Purchase, String> _quantity;
public TableColumn<Purchase, String> _rate;
public TableColumn<Purchase, String> _per;
public TableColumn<Purchase, String> _amount;

The Purchase class is as follows

public class Purchase {
private SimpleStringProperty serialNumber;
private SimpleObjectProperty<Item> itemName;
private SimpleStringProperty quantity;
private SimpleStringProperty rate;
private SimpleStringProperty per;
private SimpleStringProperty amount;

public Purchase() {
    serialNumber = new SimpleStringProperty();
    itemName = new SimpleObjectProperty<>();
    quantity = new SimpleStringProperty();
    rate = new SimpleStringProperty();
    per = new SimpleStringProperty();
    amount = new SimpleStringProperty();
}

public String getSerialNumber() {
    return serialNumber.get();
}

public SimpleStringProperty serialNumberProperty() {
    return serialNumber;
}

public void setSerialNumber(String serialNumber) {
    this.serialNumber.set(serialNumber);
}

public Item getItemName() {
    return itemName.get();
}

public SimpleObjectProperty<Item> itemNameProperty() {
    return itemName;
}



public void setItemName(Item itemName) {
    this.itemName.set(itemName);
}

public String getQuantity() {
    return quantity.get();
}

public SimpleStringProperty quantityProperty() {
    return quantity;
}

public void setQuantity(String quantity) {
    this.quantity.set(quantity);
}

public String getRate() {
    return rate.get();
}

public SimpleStringProperty rateProperty() {
    return rate;
}

public void setRate(String rate) {
    this.rate.set(rate);
}

public String getPer() {
    return per.get();
}

public SimpleStringProperty perProperty() {
    return per;
}

public void setPer(String per) {
    this.per.set(per);
}

public String getAmount() {
    return amount.get();
}

public SimpleStringProperty amountProperty() {
    return amount;
}

public void setAmount(String amount) {
    this.amount.set(amount);
}
}

The Item class is as follows

public class Item {
private SimpleStringProperty id;
private SimpleStringProperty itemName;
private SimpleStringProperty stockGroupID;
private SimpleStringProperty stockGroup;
private SimpleStringProperty unitID;
private SimpleStringProperty unitName;
private SimpleStringProperty taxabilityID;
private SimpleStringProperty taxability;
private SimpleStringProperty hsn;
private SimpleStringProperty itemDescription;
private SimpleStringProperty integratedTax;
private SimpleStringProperty centralTax;
private SimpleStringProperty stateTax;
private SimpleStringProperty cess;

public Item() {
    id = new SimpleStringProperty();
    itemName = new SimpleStringProperty();
    stockGroupID = new SimpleStringProperty();
    stockGroup = new SimpleStringProperty();
    unitID = new SimpleStringProperty();
    unitName = new SimpleStringProperty();
    taxabilityID = new SimpleStringProperty();
    taxability = new SimpleStringProperty();
    hsn = new SimpleStringProperty();
    itemDescription = new SimpleStringProperty();
    integratedTax = new SimpleStringProperty();
    centralTax = new SimpleStringProperty();
    stateTax = new SimpleStringProperty();
    cess = new SimpleStringProperty();
}
public Item(String id,String itemName,String stockGroupID,String stockGroup,String unitID,String unitName,String taxabilityID,
            String taxability,String hsn,String itemDescription,String integratedTax,String centralTax,
            String stateTax,String cess) {
    this.id = new SimpleStringProperty(id);
    this.itemName = new SimpleStringProperty(itemName);
    this.stockGroupID = new SimpleStringProperty(stockGroupID);
    this.stockGroup = new SimpleStringProperty(stockGroup);
    this.unitID = new SimpleStringProperty(unitID);
    this.unitName = new SimpleStringProperty(unitName);
    this.taxabilityID = new SimpleStringProperty(taxabilityID);
    this.taxability = new SimpleStringProperty(taxability);
    this.hsn = new SimpleStringProperty(hsn);
    this.itemDescription = new SimpleStringProperty(itemDescription);
    this.integratedTax = new SimpleStringProperty(integratedTax);
    this.centralTax = new SimpleStringProperty(centralTax);
    this.stateTax = new SimpleStringProperty(stateTax);
    this.cess = new SimpleStringProperty(cess);
}

public String getId() {
    return id.get();
}

public SimpleStringProperty idProperty() {
    return id;
}

public void setId(String id) {
    this.id.set(id);
}

public String getItemName() {
    return itemName.get();
}

public SimpleStringProperty itemNameProperty() {
    return itemName;
}

public void setItemName(String itemName) {
    this.itemName.set(itemName);
}

public String getStockGroupID() {
    return stockGroupID.get();
}

public SimpleStringProperty stockGroupIDProperty() {
    return stockGroupID;
}

public void setStockGroupID(String stockGroupID) {
    this.stockGroupID.set(stockGroupID);
}

public String getStockGroup() {
    return stockGroup.get();
}

public SimpleStringProperty stockGroupProperty() {
    return stockGroup;
}

public void setStockGroup(String stockGroup) {
    this.stockGroup.set(stockGroup);
}

public String getUnitID() {
    return unitID.get();
}

public SimpleStringProperty unitIDProperty() {
    return unitID;
}

public void setUnitID(String unitID) {
    this.unitID.set(unitID);
}

public String getUnitName() {
    return unitName.get();
}

public SimpleStringProperty unitNameProperty() {
    return unitName;
}

public void setUnitName(String unitName) {
    this.unitName.set(unitName);
}

public String getTaxabilityID() {
    return taxabilityID.get();
}

public SimpleStringProperty taxabilityIDProperty() {
    return taxabilityID;
}

public void setTaxabilityID(String taxabilityID) {
    this.taxabilityID.set(taxabilityID);
}

public String getTaxability() {
    return taxability.get();
}

public SimpleStringProperty taxabilityProperty() {
    return taxability;
}

public void setTaxability(String taxability) {
    this.taxability.set(taxability);
}

public String getHsn() {
    return hsn.get();
}

public SimpleStringProperty hsnProperty() {
    return hsn;
}

public void setHsn(String hsn) {
    this.hsn.set(hsn);
}

public String getItemDescription() {
    return itemDescription.get();
}

public SimpleStringProperty itemDescriptionProperty() {
    return itemDescription;
}

public void setItemDescription(String itemDescription) {
    this.itemDescription.set(itemDescription);
}

public String getIntegratedTax() {
    return integratedTax.get();
}

public SimpleStringProperty integratedTaxProperty() {
    return integratedTax;
}

public void setIntegratedTax(String integratedTax) {
    this.integratedTax.set(integratedTax);
}

public String getCentralTax() {
    return centralTax.get();
}

public SimpleStringProperty centralTaxProperty() {
    return centralTax;
}

public void setCentralTax(String centralTax) {
    this.centralTax.set(centralTax);
}

public String getStateTax() {
    return stateTax.get();
}

public SimpleStringProperty stateTaxProperty() {
    return stateTax;
}

public void setStateTax(String stateTax) {
    this.stateTax.set(stateTax);
}

public String getCess() {
    return cess.get();
}

public SimpleStringProperty cessProperty() {
    return cess;
}

public void setCess(String cess) {
    this.cess.set(cess);
}
}

The purchase model class

public class PurchaseModel {
private ObservableList<Purchase> purchases;
private ObservableList<Item> items;
private int row,column;
public PurchaseModel() {
    row = 0;
    column = 0;
    purchases = FXCollections.observableArrayList();
    Purchase purchase = new Purchase();
    purchase.setSerialNumber("1");
    purchase.setItemName(getItem());
    purchase.setQuantity("4");
    purchase.setRate("20.00");
    purchase.setPer("Pcs");
    purchase.setAmount("80.00");
    purchases.add(purchase);

    items = FXCollections.observableArrayList();
    Item item = new Item();
    item.setId("1");
    item.setItemName("Lux");
    item.setStockGroupID("1");
    item.setStockGroup("items @ 5%");
    item.setUnitID("1");
    item.setUnitName("Kg");
    item.setTaxabilityID("1");
    item.setTaxability("5%");
    item.setHsn("344344");
    item.setItemDescription("dkfmks skmd");
    item.setIntegratedTax("5");
    item.setCentralTax("2.5");
    item.setStateTax("2.5");
    item.setCess("0.0");
    items.add(item);

    item = new Item();
    item.setId("2");
    item.setItemName("Godrej");
    item.setStockGroupID("1");
    item.setStockGroup("items @ 5%");
    item.setUnitID("1");
    item.setUnitName("Kg");
    item.setTaxabilityID("1");
    item.setTaxability("5%");
    item.setHsn("344344");
    item.setItemDescription("dkfmks skmd");
    item.setIntegratedTax("5");
    item.setCentralTax("2.5");
    item.setStateTax("2.5");
    item.setCess("0.0");
    items.add(item);

    item = new Item();
    item.setId("2");
    item.setItemName("Pears");
    item.setStockGroupID("1");
    item.setStockGroup("items @ 5%");
    item.setUnitID("1");
    item.setUnitName("Kg");
    item.setTaxabilityID("1");
    item.setTaxability("5%");
    item.setHsn("344344");
    item.setItemDescription("dkfmks skmd");
    item.setIntegratedTax("5");
    item.setCentralTax("2.5");
    item.setStateTax("2.5");
    item.setCess("0.0");
    items.add(item);
}

public ObservableList<Purchase> fillPurchaseTableViewWithData(){
    return purchases;
}

public ObservableList<Item> fillItemListViewWithData(){
    return items;
}

public Item getItem(){
    return new Item("1","Porter and Gamble","1","Item @ 5%","1","Kg",
            "1","5%","23323","a very good toy","5","2.5",
            "2.5","0");
}

public int getRow() {
    return row;
}

public void setRow(int row) {
    this.row = row;
}

public int getColumn() {
    return column;
}

public void setColumn(int column) {
    this.column = column;
}
}

The Controller Class is as follows

public class PurchaseController implements Initializable {

public TableView<Purchase> _purchase_table;
public TableColumn<Purchase, String> _id;
public TableColumn<Purchase, Item> _name_of_item;
public TableColumn<Purchase, String> _quantity;
public TableColumn<Purchase, String> _rate;
public TableColumn<Purchase, String> _per;
public TableColumn<Purchase, String> _amount;

private PurchaseModel theModel;

@Override
public void initialize(URL location, ResourceBundle resources) {

    theModel = new PurchaseModel();

    _id.setCellValueFactory(new IDCellValueFactory());
    _name_of_item.setCellValueFactory(new ItemCellValueFactory());
    _quantity.setCellValueFactory(new QuantityCellValueFactory());
    _rate.setCellValueFactory(new RateCellValueFactory());
    _per.setCellValueFactory(new PerCellValueFactory());
    _amount.setCellValueFactory(new AmountCellValueFactory());

    _name_of_item.setCellFactory(new ItemComboBoxEditingCellFactory());
    //_name_of_item.setOnEditCommit(new ItemCellOnEditCommit() );

    _purchase_table.setItems(theModel.fillPurchaseTableViewWithData());
    _purchase_table.setEditable(true);
    _purchase_table.getSelectionModel().cellSelectionEnabledProperty().set(true);

    _purchase_table.getFocusModel().focusedCellProperty().addListener(new PurchaseTableCellSelectionListener());

}

private class IDCellValueFactory implements Callback<TableColumn.CellDataFeatures<Purchase, String>, ObservableValue<String>> {
    @Override
    public ObservableValue<String> call(TableColumn.CellDataFeatures<Purchase, String> param) {
        return param.getValue().serialNumberProperty();
    }
}

private class ItemCellValueFactory implements Callback<TableColumn.CellDataFeatures<Purchase, Item>, ObservableValue<Item>> {
    @Override
    public ObservableValue<Item> call(TableColumn.CellDataFeatures<Purchase, Item> param) {
        return param.getValue().itemNameProperty();
    }
}

private class QuantityCellValueFactory implements Callback<TableColumn.CellDataFeatures<Purchase, String>, ObservableValue<String>> {

    @Override
    public ObservableValue<String> call(TableColumn.CellDataFeatures<Purchase, String> param) {
        return param.getValue().quantityProperty();
    }
}

private class RateCellValueFactory implements Callback<TableColumn.CellDataFeatures<Purchase, String>, ObservableValue<String>> {
    @Override
    public ObservableValue<String> call(TableColumn.CellDataFeatures<Purchase, String> param) {
        return param.getValue().rateProperty();
    }
}

private class PerCellValueFactory implements Callback<TableColumn.CellDataFeatures<Purchase, String>, ObservableValue<String>> {
    @Override
    public ObservableValue<String> call(TableColumn.CellDataFeatures<Purchase, String> param) {
        return param.getValue().perProperty();
    }
}

private class AmountCellValueFactory implements Callback<TableColumn.CellDataFeatures<Purchase, String>, ObservableValue<String>> {
    @Override
    public ObservableValue<String> call(TableColumn.CellDataFeatures<Purchase, String> param) {
        return param.getValue().amountProperty();
    }
}

private class  ItemComboBoxEditingCellFactory implements Callback<TableColumn<Purchase, Item>, TableCell<Purchase, Item>> {
    @Override
    public TableCell<Purchase, Item> call(TableColumn<Purchase, Item> param) {
        return new ItemComboBoxEditingCell();
    }
}

private class ItemComboBoxEditingCell extends TableCell<Purchase, Item> {
    private ComboBox<Item> comboBox;
    private TablePosition<Purchase,Item> pos;

    public ItemComboBoxEditingCell() {
        pos = new TablePosition<>(getTableView(),0,null);
    }

    @Override
    public void startEdit() {
        if (!isEmpty()) {
            super.startEdit();
            createComboBox();
            setText(null);
            setGraphic(comboBox);
        }
    }

    @Override
    public void commitEdit(Item newValue) {
        super.commitEdit(newValue);
        ((Purchase)getTableView().getItems()
                .get(getIndex()))
                .setItemName(newValue);

    }

    @Override
    public void cancelEdit() {
        super.cancelEdit();
        setText(getItemSelected().getItemName());
        setGraphic(null);
    }

    @Override
    protected void updateItem(Item item, boolean empty) {
        super.updateItem(item, empty);

        if (empty){
            setGraphic(null);
            setText(null);

        }else {
            setText(getItemSelected().getItemName());
            setGraphic(comboBox);
        }
    }



    private Item getItemSelected() {
        return getItem() == null ? theModel.getItem() : getItem();
    }

    private void createComboBox() {
        comboBox = new ComboBox<>();
        comboBox.setItems(theModel.fillItemListViewWithData());
        comboBox.setEditable(true);
        comboBox.setCellFactory(new ItemComboBoxCellFactory());
        //comboBox.setOnAction(new ItemComboBoxSelectionListener());
        //comboBox.focusedProperty().addListener(new ItemComboBoxFocusListener());
        //comboBox.showingProperty().addListener(new ItemComboBoxShowingListener());
        comboBox.valueProperty().set(getItemSelected());
        comboBox.setConverter(new ItemComboBoxStringConverter());
        comboBox.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2);
    }

    private class ItemComboBoxCellFactory implements Callback<ListView<Item>,ListCell<Item>>{
        @Override
        public ListCell<Item> call(ListView<Item> param) {
            return new ItemComboBoxCell();
        }
    }

    private class ItemComboBoxCell extends ListCell<Item>{
        @Override
        protected void updateItem(Item item, boolean empty) {
            super.updateItem(item, empty);
            if (item == null || empty){
                setText(null);
            }else {
                setText(item.getItemName());
            }
        }
    }

    private class ItemComboBoxStringConverter extends StringConverter<Item>{
        private Item i;
        @Override
        public String toString(Item item) {
            if (item == null)
                return null;
            i = item;
            return item.getItemName();
        }

        @Override
        public Item fromString(String s) {
            return i;
        }
    }


}

private class PurchaseTableCellSelectionListener implements ChangeListener<TablePosition>{
    @Override
    public void changed(ObservableValue<? extends TablePosition> observableValue, TablePosition tablePosition, TablePosition t1) {
        int row = t1.getRow();
        int column = t1.getColumn();
        theModel.setRow(row);
        theModel.setColumn(column);
    }
}

Please tell me a way to implement all the four points that i have mentioned above.

0

There are 0 best solutions below