JavaFXTableView-添加一行

JavaFXTableView-添加一行,javafx,tableview,Javafx,Tableview,我有一个应用程序,其中有一个tableview 我从数据库中获取信息并显示数据 有没有一种方法可以让tableview中的底行作为输入新数据的方式 我在网上看到了texfields和add按钮,但我想知道是否可以直接从tableview输入新数据 感谢您提供的任何帮助或建议您可以通过在自己的自定义类中扩展TableCell来提供此行为。然后,将其CellFactory中的列设置为这种类型的单元格,并在其中提供自定义实现。然后,您可以添加自己的实现,即当有人单击单元格时,如何在单元格中显示文本字段

我有一个应用程序,其中有一个tableview

我从数据库中获取信息并显示数据

有没有一种方法可以让tableview中的底行作为输入新数据的方式

我在网上看到了texfields和add按钮,但我想知道是否可以直接从tableview输入新数据


感谢您提供的任何帮助或建议

您可以通过在自己的自定义类中扩展TableCell来提供此行为。然后,将其CellFactory中的列设置为这种类型的单元格,并在其中提供自定义实现。然后,您可以添加自己的实现,即当有人单击单元格时,如何在单元格中显示文本字段。最后,您需要向tableview添加一个空行

我有一些TreeTableCell的示例代码,它很像TableCell。 您可以以此为例编写自己的自定义TableCell

自定义单元格 包be.vincentnagy.ehka.treetableview.cell

import be.vincentnagy.ehka.activity.Activity;
import be.vincentnagy.ehka.category.Category;
import be.vincentnagy.ehka.treetableview.item.CustomTreeItem;
import be.vincentnagy.ehka.treetableview.item.TotalTreeItem;
import javafx.geometry.Pos;
import javafx.scene.control.TextField;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeTableCell;
import javafx.scene.input.KeyCode;

import java.text.NumberFormat;
import java.text.ParseException;
import java.time.Month;
import java.time.Year;

/**
 * @author Vincent Nagy
 * A MoneyFormatCell is a custom implementation of a TreeTableCell.
 * It provides editing functionality for specific cells
 * and propagates changes to the underlying data items.
 */
public class MoneyFormatCell extends TreeTableCell<CustomTreeItem,Number>{
    private TextField textField;
    private static final NumberFormat NUMBER_FORMAT = NumberFormat.getNumberInstance();
    private static final NumberFormat CURRENCY_FORMAT = NumberFormat.getCurrencyInstance();

    static {
        NUMBER_FORMAT.setMaximumFractionDigits(2);
        NUMBER_FORMAT.setMinimumFractionDigits(2);
    }
    public MoneyFormatCell() {

    }

    /**
     * updateItem gets called whenever a MoneyFormatCell changes state.
     * Editing gets disabled for TotalTreeItem and CategoryTreeItem.
     * Provides the TextBox inside the cell for input.
     * @param item Item being added to the MoneyFormatCell. Only gets called at initial filling of the Table
     * @param empty  Whether or not the cell is empty
     */
    @Override
    protected void updateItem(Number item, boolean empty) {
        super.updateItem(item, empty);
        setAlignment(Pos.CENTER_RIGHT);

        TreeItem<CustomTreeItem> treeItem = getTreeTableRow().getTreeItem();

        //Set editable if it's a leaf(aka if it's an ActivityDataItem
        setEditable(treeItem != null && treeItem.isLeaf());
        //Set editable if it's not the the Totals row and not a Category row
        setEditable(!(treeItem != null && (treeItem.getValue() instanceof TotalTreeItem || treeItem.getValue() instanceof Category)));

        if(empty){
            setText(null);
            setGraphic(null);
        }else {
            if( isEditing()){
                if(textField != null){
                    textField.setText(getString());
                    setText(null);
                    setGraphic(textField);
                }
            } else {
                if(item == null){
                    if(textField != null && !textField.getText().equals("")){
                        stoppedEditing();
                    }
                    setText("");
                }else{
                    setText(NumberFormat.getCurrencyInstance().format(item.doubleValue()));
                }
                setGraphic(null);
            }
        }
    }

    /**
     * startEdit gets called whenever a MoneyFormatCell moves into editing mode.
     * It creates the TextField element if it isn't already created
     * and switches the graphics from string to the TextField.
     */
    @Override
    public void startEdit() {
        if(isEditable()) {
            super.startEdit();
            if (textField == null) {
                createTextField();
            }

            setText(null);
            setGraphic(textField);
            textField.requestFocus();
            textField.selectAll();
        }
    }

    /**
     * createTextField creates a TextField to allow editing of data in the Cell.
     * It initializes the event handlers for the Escape key and the Enter key.
     * It also listens for when it gets unfocused.
     */
    private void createTextField() {
        textField = new TextField(getString());
        textField.setMinWidth(this.getWidth() - this.getGraphicTextGap()* 2);

        textField.setOnKeyReleased(event -> {
            if (event.getCode() == KeyCode.ESCAPE){
                cancelEdit();
            } else if(event.getCode() == KeyCode.ENTER){
                stoppedEditing();
            }
        });
        textField.focusedProperty().addListener((observable, oldValue, newValue) -> {
            if(oldValue){
                stoppedEditing();
            }
        });

    }

    /**
     * stoppedEditing gets called whenever a cell leaves editing mode.
     * This happens whenever the Enter key gets pressed or when the focus shifts away from the cell.
     * If there is no value, it will simple cancel out.
     * Otherwise it will propagate the changes to the respective ActivityTreeItem
     * and commit the edit to the cell.
     */
    private void stoppedEditing(){
        try {
            if (textField.getText().equals("")) {
                cancelEdit();
            } else {
                if (getTreeTableRow().getTreeItem().getValue() instanceof Activity) {
                    Activity activityTreeItem = (Activity) getTreeTableRow().getTreeItem().getValue();

                    activityTreeItem.setActivityDataForDate(Month.valueOf(getTableColumn().getText()).getValue(),
                            Year.parse(getTableColumn().getParentColumn().getText()).getValue(),
                            NUMBER_FORMAT.parse(textField.getText()).doubleValue());
                }
                commitEdit(NUMBER_FORMAT.parse(textField.getText()).doubleValue());
            }
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }


    /**
     * cancelEdit gets called when the cell stops editing and
     * either was left by using the Escape key or there was no new value in the cell
     */
    @Override
    public void cancelEdit() {
        super.cancelEdit();

        setText(getFormatted());
        setGraphic(null);
    }

    /*
        format into double number for editing in text field
     */
    private String getString() {
        //return getItem() == null ? "" : NumberFormat.getNumberInstance().format(((double)getItem()));
        return getItem() == null ? "" : NUMBER_FORMAT.format(((double)getItem()));
    }

    /*
        format into double number with currency locale
     */
    private String getFormatted(){
        return getItem() == null ? "" :CURRENCY_FORMAT.format(getItem().doubleValue());
    }

}
导入be.vincentnagy.ehka.activity.activity;
导入be.vincentnagy.ehka.category.category;
导入be.vincentnagy.ehka.treetableview.item.CustomTreeItem;
导入be.vincentnagy.ehka.treetableview.item.TotalTreeItem;
导入javafx.geometry.Pos;
导入javafx.scene.control.TextField;
导入javafx.scene.control.TreeItem;
导入javafx.scene.control.TreeTableCell;
导入javafx.scene.input.KeyCode;
导入java.text.NumberFormat;
导入java.text.ParseException;
导入java.time.Month;
导入java.time.Year;
/**
*@作者文森特·纳吉
*MoneyFormatCell是TreeTableCell的自定义实现。
*它为特定单元格提供编辑功能
*并将更改传播到基础数据项。
*/
公共类MoneyFormatCell扩展了TreeTableCell{
私有文本字段文本字段;
私有静态final NumberFormat NUMBER_FORMAT=NumberFormat.getNumberInstance();
私有静态最终NumberFormat CURRENCY_FORMAT=NumberFormat.getCurrencyInstance();
静止的{
数字\u格式。setMaximumFractionDigits(2);
数字\u格式。setMinimumFractionDigits(2);
}
公共货币格式单元格(){
}
/**
*每当MoneyFormatCell更改状态时,就会调用updateItem。
*TotalTreeItem和CategoryTreeItem的编辑被禁用。
*提供单元格内用于输入的文本框。
*@param item正在添加到MoneyFormatCell。仅在初始填充表时调用
*@param empty无论单元格是否为空
*/
@凌驾
受保护的void updateItem(数字项,布尔值为空){
super.updateItem(项,空);
设置对齐(位置居中\右侧);
TreeItem TreeItem=getTreeTableRow().getTreeItem();
//如果它是一个叶子,则设置为可编辑(如果它是ActivityDataItem,则称为可编辑)
setEditable(treeItem!=null&&treeItem.isLeaf());
//如果不是总计行且不是类别行,则设置为可编辑
setEditable(!(treeItem!=null&(treeItem.getValue()实例of TotalTreeItem | | treeItem.getValue()实例of Category));
if(空){
setText(空);
设置图形(空);
}否则{
if(isEditing()){
if(textField!=null){
setText(getString());
setText(空);
设置图形(文本字段);
}
}否则{
如果(项==null){
if(textField!=null&&!textField.getText().equals(“”){
停止编辑();
}
setText(“”);
}否则{
setText(NumberFormat.getCurrencyInstance().format(item.doubleValue());
}
设置图形(空);
}
}
}
/**
*startEdit在MoneyFormatCell进入编辑模式时被调用。
*如果尚未创建TextField元素,则会创建该元素
*并将图形从字符串切换到文本字段。
*/
@凌驾
公开作废已启动IT(){
如果(isEditable()){
super.startEdit();
if(textField==null){
createTextField();
}
setText(空);
设置图形(文本字段);
textField.requestFocus();
textField.selectAll();
}
}
/**
*createTextField创建一个TextField以允许编辑单元格中的数据。
*它初始化Escape键和Enter键的事件处理程序。
*它也会在注意力不集中时倾听。
*/
私有void createTextField(){
textField=newtextfield(getString());
textField.setMinWidth(this.getWidth()-this.getGraphicTextGap()*2);
textField.setOnKeyReleased(事件->{
if(event.getCode()==KeyCode.ESCAPE){
取消编辑();
}else if(event.getCode()==KeyCode.ENTER){
停止编辑();
}
});
textField.focusedProperty().addListener((可观察、旧值、新值)->{
如果(旧值){
停止编辑();
}
});
}
/**
*每当单元格离开编辑模式时,都会调用stoppedEditing。
*每当按下Enter键或焦点从单元格移开时,都会发生这种情况。
*如果没有值,它将简单地取消。
*否则,它会将更改传播到相应的ActivityTreeItem
*并将编辑提交到单元格。
*/
私有void stoppedEditing(){
试一试{
if(textField.getText().equals(“”){
取消编辑();
}否则{
if(getTreeTableRow().getTreeItem().getValue()活动实例){
活动activityTreeItem=(活动)getTreeTableRow().getTreeItem().getValue();
activityTreeItem.setActivityDataForDate(Month.valueOf)(getTable
    /**
 * Create a column for the requested months in the specified year. Doesn't need to start at January.
 * Bind the cell to the ActivityTreeItem valueProperty
 *
 * @param yearColumn The column to initialize
 * @param year       The year it belongs to
 * @param startMonth The starting month in case it's not a full year
 * @param endMonth   The ending month in case it's not a full year
 */
private void createMonthColumns(TreeTableColumn<CustomTreeItem, Number> yearColumn, int year, int startMonth, int endMonth) {
    for (int i = startMonth; i <= endMonth; i++) {
        Month month = Month.of(i);
        TreeTableColumn<CustomTreeItem, Number> ttc = new TreeTableColumn<>(month.toString());
        ttc.setMinWidth(MIN_TABLE_WIDTH);

        Month currentMonth = Month.of(i);
        ttc.setCellValueFactory(param -> {
            if (param.getValue().getValue() instanceof Activity) {
                Activity treeItem = (Activity) param.getValue().getValue();
                return treeItem.getActivityDataForDate(currentMonth.getValue(), year);
            } else if (param.getValue().getValue() instanceof TotalTreeItem) {
                TotalTreeItem totalTreeItem = (TotalTreeItem) param.getValue().getValue();
                return totalTreeItem.valueProperty(currentMonth.getValue(), year);
            }
            return null;
        });

        ttc.setCellFactory(param -> new MoneyFormatCell());

        yearColumn.getColumns().add(ttc);
    }
}