是否可以在JavaFX8中基于行禁用可编辑的表列?

时间:2016-05-03 17:18:31

标签: tableview javafx-8 tablecolumn

我有一个用例,我认为这是非常标准的,但是我无法找到关于如何做到这一点的示例,或者是否可能。

我们假设我有以下TableView

 android {
     packagingOptions {
         pickFirst 'META-INF/LICENSE.txt' // picks the JavaMail license file
     }
 }

 repositories { 
     jcenter()
     maven {
         url "https://maven.java.net/content/groups/public/"
     }
 }

 dependencies {
     compile 'com.sun.mail:android-mail:1.5.5'
     compile 'com.sun.mail:android-activation:1.5.5'
 }

在这种情况下,网格应该可以编辑前三个单元格,因为记录是新的,但是当记录不是新的时候,应该禁用“姓氏”单元格。

我在CellFactory和RowFactory中尝试过这个 - 但还没有看到实现这个目标的方法。

感谢您的帮助。

2 个答案:

答案 0 :(得分:2)

最简单的方法是使用第三方绑定库:ReactFX 2.0内置了此功能,如here所述。使用它你可以做

TableColumn<Person, String> lastNameColumn = new TableColumn<>("Last Name");
lastNameColumn.setEditable(true);
lastNameColumn.setCellFactory(tc -> {
    TableCell<Person, String> cell = new TextFieldTableCell<>();
    cell.editableProperty().bind(
        // horrible cast needed because TableCell.tableRowProperty inexplicably returns a raw type:
        Val.flatMap(cell.tableRowProperty(), row -> (ObservableValue<Person>)row.itemProperty())
           .flatMap(Person::newRecordProperty)
           .orElseConst(false));
    return cell ;
});

(假设Person表模型对象具有明显的JavaFX属性和方法。)

没有库,你需要一个非常悲惨的嵌套侦听器列表:

TableColumn<Person, String> lastNameColumn = new TableColumn<>("Last Name");
lastNameColumn.setEditable(true);
lastNameColumn.setCellFactory(tc -> {
    TableCell<Person, String> cell = new TextFieldTableCell<>();
    ChangeListener<Boolean> newRecordListener = (obs, wasNewRecord, isNewRecord) -> updateEditability(cell);
    ChangeListener<Person> rowItemListener = (obs, oldPerson, newPerson) -> {
        if (oldPerson != null) {
            oldPerson.newRecordProperty().removeListener(newRecordListener);
        }
        if (newPerson != null) {
            newPerson.newRecordProperty().addListener(newRecordListener);
        }
        updateEditability(cell);
    };
    ChangeListener<TableRow> rowListener = (obs, oldRow, newRow) -> {
        if (oldRow != null) {
            ((ObservableValue<Person>)oldRow.itemProperty()).removeListener(rowItemListener);
            if (oldRow.getItem() != null) {
                ((Person)oldRow.getItem()).newRecordProperty().removeListener(newRecordListener);
            }
        }
        if (newRow != null) {
            ((ObservableValue<Person>)newRow.itemProperty()).addListener(rowItemListener);
            if (newRow.getItem() != null) {
                ((Person)newRow.getItem()).newRecordProperty().addListener(newRecordListener);
            }
        }
        updateEditability(cell);
    };
    cell.tableRowProperty().addListener(rowListener);
    return cell ;
});

然后

private void updateEditability(TableCell<Person, String> cell) {
    if (cell.getTableRow() == null) {
        cell.setEditable(false);
    } else {
        TableRow<Person> row = (TableRow<Person>) cell.getTableRow();
        if (row.getItem() == null) {
            cell.setEditable(false);
        } else {
            cell.setEditable(row.getItem().isNewRecord());
        }
    }
}

使用&#34;传统风格的另一种选择&#34; API是

TableColumn<Person, String> lastNameColumn = new TableColumn<>("Last Name");
lastNameColumn.setEditable(true);
lastNameColumn.setCellFactory(tc -> {
    TableCell<Person, String> cell = new TextFieldTableCell<>();
    cell.editableProperty().bind(
        Bindings.selectBoolean(cell.tableRowProperty(), "item", "newRecord"));
    return cell ;
});

我不喜欢这个选项,因为它缺少任何类型安全性(或者根本没有任何编译器检查),而且在某些早期版本的JavaFX中,如果&#34;链中的任何属性都会生成几乎无穷无尽的警告消息#34;具有空值(在这种情况下,它们经常会出现)。我相信后一个问题是固定的,但ReactFX版本的效果要好得多,imho。

答案 1 :(得分:0)

您始终可以通过设置事件处理程序来检查操作是否合法来停止编辑。

        columnName.setOnEditStart(
            new EventHandler<CellEditEvent<ItemClass, String>>(){
                @Override
                public void handle(CellEditEvent<ItemClass, String> event) {
                    if(event.getTableColumn().getCellData(3).compareTo("yes") == 0) {
                        event.getTableView().edit(-1, null); 
                       //this prevents the editing in "progress"
                    }                       
                }   
            }
    );