JavaFX TableView 自定义可编辑状态的切换和监听

JavaFX TableView 自定义可编辑状态的切换和监听

网上的可查到的关于Java FX的表格内的编辑多是以在设置setEditable(true)后,再通过添加各种方法进行可编辑操作和编辑后的提交。但这些均存在一个操作逻辑的问题,均需要双击行列才能进入切换TextField进行编辑,因此在UI界面中若没有添加提示内容,用户将无法直观感知进入编辑操作的方法,会大大提高了用户的使用成本。因此从交互的角度,想到以各种方案

问题描述

最近在写图书馆系统用到了大量表格,也需要对表格内容进行直接编辑,但是经过搜索得到的JavaFX的表格内的编辑是以在设置setEditable(true)后,再通过添加各种方法进行可编辑操作和编辑后的提交。这种存在一个操作逻辑的问题,需要双击行列才能进入切换TextField进行编辑,因此在UI界面中若没有添加提示内容,用户将无法直观感知进入编辑操作的方法,会大大提高了用户的使用成本。因此从交互的角度,想到了各种方案,通过按钮点击、直接显示、点击表格自动切换的思路,实现易于用户使用的对表格操作的UI交互。

PS: 后想到部分博客的内容也用到自定义表格方案,但思路并不清晰,甚至有毫无解释的直接抛代码的,所以没啥心情去认真看。

思路分析

不能通过setCellFactory(TextFieldTableCell.forTableColumn())这样最简单的内置方法实现编辑,需要自己的自定义实现,虽略显麻烦,但十分好用。

自定义表格样式思路:

  • JavaFX中的TableView均是对Column进行操作,因此修改会直接修改整列的样式
  • 若不想将整列变化,可以通过定位聚焦当行的位置,行列的交点则为修改样式的单表格
  • 自定义样式内最好使用布局(HBox, VBox)填充,一是方便其随表格的变化而变化,二是更好设置所需的内容
  • 此次演示均以TextField实现,包含但不限于CheckBox / ChoiceBox / ComboBox / ProgressBar
  • 此次演示数据类型均为String,其他类型需自行调整

交互逻辑思路

  1. 直接显示TextField(不建议)
  2. 通过点击按钮在默认与TextField状态切换
  3. 通过直接点击表格显示TextField

思路实现

直接显示TextField(基础)

column.setCellFactory(new Callback<TableColumn<BookManageRecord, String>, TableCell<BookManageRecord, String>>() {
//column为更改样式的目标列名 

    @Override
    public TableCell<BookManageRecord, String> call(TableColumn<BookManageRecord, String> param) {
        //设置工厂方法并覆盖实现Callback其中的TableCell定义

        TableCell<BookManageRecord, String> cell = new TableCell<BookManageRecord, String>(){
            //通过覆盖其TableCell的定义实现自定义样式

            @Override
            protected void updateItem(String item, boolean empty) {
                //覆盖TableCell的样式更新
                super.updateItem(item, empty);

                if(!empty && item != null){
                    //核心内容
                    HBox hbox = new HBox();                         //通过HBox布局填充表格便于管理
                    hbox.setAlignment(Pos.CENTER);                  //内容居中

                    TextField tf = new TextField(item);             //用获取到的item初始化TextField

                    hbox.getChildren().add(tf);                     //将TextField加入HBox布局
                    this.setGraphic(hbox);                          //将表格样式设置为HBox
                        
                }
            }
        };

        return cell;        //返回该表格样式与内容
    }
)};

该方法缺点在于直接显示TextField无法切换回初始状态,但依旧可以实现当焦点不在该Textfield时提交内容,视情况而定吧!

通过Button点击切换

private int flag = 1;

button.setOnAction(new EventHandler<ActionEvent>() {
    //button添加监听
    @Override
    public void handle(ActionEvent event) {
        if(flag == 1){
            setToTextField();
            flag--;
        }
        else{
            setToLabel();
            flag++;
        }

    }
});

private void setToTextField(){
    cat.setCellFactory(new Callback<TableColumn<BookManageRecord, String>, TableCell<BookManageRecord, String>>() {

        @Override
        public TableCell<BookManageRecord, String> call(TableColumn<BookManageRecord, String> param) {

            TableCell<BookManageRecord, String> cell = new TableCell<BookManageRecord, String>(){
                @Override
                protected void updateItem(String item, boolean empty) {
                    super.updateItem(item, empty);

                    if(!empty && item != null){
                        TextField tf = new TextField(item);

                        HBox hbox = new HBox();
                        hbox.setAlignment(Pos.CENTER);
                        hbox.getChildren().add(tf);

                        this.setGraphic(hbox);
                    }
                }
            };

            return cell;
        }
    });
}
private void setToLabel(){
    cat.setCellFactory(new Callback<TableColumn<BookManageRecord, String>, TableCell<BookManageRecord, String>>() {

        @Override
        public TableCell<BookManageRecord, String> call(TableColumn<BookManageRecord, String> param) {

            TableCell<BookManageRecord, String> cell = new TableCell<BookManageRecord, String>(){
                @Override
                protected void updateItem(String item, boolean empty) {
                    super.updateItem(item, empty);

                    if(!empty && item != null){
                        Label label = new Label(item);                  //此处唯一不同便是使用了Label
                                                                        //这样一来和默认的样式区别不大

                        HBox hbox = new HBox();
                        hbox.setAlignment(Pos.CENTER);
                        hbox.getChildren().add(label);

                        this.setGraphic(hbox);
                    }
                }
            };

            return cell;
        }
    });
}

updateItem()是在一列表格中,依次从上到下对每一个表格进行一次update操作,因此只要在setCellFactory()工厂方法中去进行判断全局的状态是该TextField还是Label的话,都会出现TextField和Label间隔出现的问题。
由于是自定义样式,因此在切换回Label的时候是无法监听到TextField内部的修改的,因此需要自定义添加监听,此处只是样式修改,不过多追加描述。

通过点击表格进行修改

table.setRowFactory( tv -> {
    TableRow<BookManageRecord> row = new TableRow<BookManageRecord>();
    row.setOnMouseClicked(event -> {
        //通过对单行的监听,再加单列样式的修改,实现点击坐标位的样式切换

        if (event.getClickCount() == 1 && (! row.isEmpty()) ) {

                cat.setCellFactory(new Callback<TableColumn<BookManageRecord, String>, TableCell<BookManageRecord, String>>() {

                    @Override
                    public TableCell<BookManageRecord, String> call(TableColumn<BookManageRecord, String> param) {

                        TableCell<BookManageRecord, String> cell = new TableCell<BookManageRecord, String>(){
                            @Override
                            protected void updateItem(String item, boolean empty) {
                                super.updateItem(item, empty);

                                if(!empty && item != null){
                                    HBox hbox = new HBox();
                                    hbox.setAlignment(Pos.CENTER);

                                    TextField tf = new TextField(item);
                                    Label label = new Label(item);

                                    if(this.getTableRow().getIndex() == table.getSelectionModel().getSelectedIndex()){
                                        hbox.getChildren().add(tf);
                                        this.setGraphic(hbox);
                                    }
                                    else {
                                        hbox.getChildren().add(label);
                                        this.setGraphic(hbox);
                                    }
                                }
                            }
                        };

                        return cell;
                    }
                });
        }
    });
    return row ;
});

用类似方法一样能实现用button控制的单表格样式切换,只要确定选中的行Index与需要刷新的行Index是否一致就可以实现了。

方法延伸

该方法下,通过判断item内容,可以实现单列表格内不同内容的不同样式。

参考借鉴

  1. Bilibili:JavaFX视频教程第98课,TableView,自定义单元格TableCell
  2. CSDN:使用javafx tableview控件时彻底解决单元格可编辑且可监听
    ——虽然没有认真看,但是写完回头发现这个的方案不错且适用于ComboBox的。
  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值