以下问题:我需要知道,在特定时刻,我的TableView目前正在编辑天气。我使用editingCellProperty并将特定的businesslogic绑定到它,以便在表格切换这些模式时获得通知。
不幸的是状态并不总是正确显示,因为我有特定的单元格(在同一列中)根本不应该编辑,但是当点击不可编辑的单元格时,TablePosition被设置到editingCellProperty中,因此我得到了我的TableView正在编辑的信息,尽管它已被告知,这个单元格是不可编辑的,编辑模式永远不会真正开始。
我创建了一个小例子,其中所有偶数行的ColumnName都是可编辑的,而奇数行则不是。
实施例-代码:
public class TableViewEditableStateError extends Application
{
public static void main( final String[] args )
{
launch( args );
}
@Override
public void start( final Stage primaryStage )
{
Item item1 = new Item( 1, "Item1" );
Item item2 = new Item( 2, "Item2" );
Item item3 = new Item( 3, "Item3" );
Item item4 = new Item( 4, "Item4" );
ObservableList<Item> itemList = FXCollections.observableArrayList( item1, item2, item3, item4 );
TableColumn<Item, Integer> columnId = new TableColumn<>( "ColumnId" );
TableColumn<Item, String> columnName = new TableColumn<>( "ColumnName" );
columnId.setCellValueFactory( new PropertyValueFactory<Item, Integer>( "id" ) );
columnName.setCellValueFactory( new PropertyValueFactory<Item, String>( "name" ) );
// columnName.setCellFactory( TextFieldTableCell.forTableColumn() ); -> Using own implementation for editablestate-behaviour
columnName.setCellFactory( new Callback<TableColumn<Item, String>, TableCell<Item, String>>()
{
@Override
public TableCell<Item, String> call( final TableColumn<Item, String> column )
{
TableCell<Item, String> cell = new EditableTableCell<Item>()
{
@Override
public void startEdit()//Business-Rule to deceide, which cell is editable.
{
if ( getTableRow().getIndex() % 2 != 0/* Only Odd Values are editable. -> Any Random Condition */)
{
System.out.println( "Do not initiate Editing." );
return;
}
System.out.println( "initiate Editing." );
super.startEdit();
}
};
return cell;
}
} );
columnName.setOnEditCommit( new EventHandler<CellEditEvent<Item, String>>()
{
@Override
public void handle( final CellEditEvent<Item, String> event )
{
final Item item = event.getRowValue();
System.out.println( "Change Item " + item + " from " + event.getOldValue() + " to new value "
+ event.getNewValue() );
item.setName( event.getNewValue() );
}
} );
final TableView<Item> tableView = new TableView<>( itemList );
tableView.getColumns().add( columnId );
tableView.getColumns().add( columnName );
tableView.setColumnResizePolicy( TableView.CONSTRAINED_RESIZE_POLICY );
tableView.setEditable( true );
columnId.setEditable( false );
Label label = new Label( "Editing-State: is not editing..." );
//Listener to record editing behaviour:
tableView.editingCellProperty().addListener( new ChangeListener<TablePosition<Item, ?>>()
{
@Override
public void changed( final ObservableValue<? extends TablePosition<Item, ?>> observable,
final TablePosition<Item, ?> oldValue, final TablePosition<Item, ?> newValue )
{
System.out.println( "Editstate changed to: " + newValue );
if ( newValue != null )
label.setText( "Editing-State: is editing..." );
else
label.setText( "Editing-State: is not editing..." );
}
} );
BorderPane layout = new BorderPane();
layout.setCenter( tableView );
layout.setTop( label );
Scene scene = new Scene( layout, 400, 400 );
scene.getStylesheets().add( getClass().getResource( "application.css" ).toExternalForm() );
primaryStage.setScene( scene );
primaryStage.show();
}
class EditableTableCell<S> extends TableCell<S, String>
{
protected TextField textField;
@Override
public void startEdit()
{
super.startEdit();
if ( textField == null )
{
createTextField();
}
setGraphic( textField );
setContentDisplay( ContentDisplay.GRAPHIC_ONLY );
Platform.runLater( new Runnable()
{
@Override
public void run()
{
textField.selectAll();
textField.requestFocus();
}
} );
}
@Override
public void cancelEdit()
{
super.cancelEdit();
setText( getItem() == null ? "" : getItem().toString() );
setContentDisplay( ContentDisplay.TEXT_ONLY );
textField = null;
}
@Override
public void updateItem( final String item, final boolean empty )
{
super.updateItem( item, empty );
if ( empty )
{
setText( null );
setGraphic( null );
}
else
{
if ( isEditing() )
{
if ( textField != null )
{
textField.setText( getItem() == null ? "" : getItem().toString() );
}
setGraphic( textField );
setContentDisplay( ContentDisplay.GRAPHIC_ONLY );
}
else
{
setText( getItem() == null ? "" : getItem().toString() );
setContentDisplay( ContentDisplay.TEXT_ONLY );
}
}
}
private void createTextField()
{
textField = new TextField( getItem() == null ? "" : getItem().toString() );
textField.setOnKeyPressed( new EventHandler<KeyEvent>()
{
@Override
public void handle( final KeyEvent keyEvent )
{
if ( keyEvent.getCode() == KeyCode.ENTER )
{
commitEdit( textField.getText() );
}
else if ( keyEvent.getCode() == KeyCode.ESCAPE )
{
cancelEdit();
}
}
} );
textField.focusedProperty().addListener( new ChangeListener<Boolean>()
{
@Override
public void changed( final ObservableValue<? extends Boolean> observable, final Boolean oldValue,
final Boolean newValue )
{
if ( !newValue && textField != null )
{
final String text = textField.getText();
commitEdit( text );
}
}
} );
}
}
}
DataClass项目:
public class Item
{
private final IntegerProperty id = new SimpleIntegerProperty();
private final StringProperty name = new SimpleStringProperty();
public Item( final int id, final String name )
{
this.id.set( id );
this.name.set( name );
}
public int getId()
{
return id.get();
}
public String getName()
{
return name.get();
}
public void setId( final int id )
{
this.id.set( id );
}
public void setName( final String name )
{
this.name.set( name );
}
public IntegerProperty idProperty()
{
return id;
}
public StringProperty nameProperty()
{
return name;
}
}
我将问题缩小到TableView的editCell方法,因为它没有对特定于细胞的可编辑状态做出反应:
/**
* Causes the cell at the given row/column view indexes to switch into
* its editing state, if it is not already in it, and assuming that the
* TableView and column are also editable.
*/
public void edit(int row, TableColumn<S,?> column) {
if (!isEditable() || (column != null && ! column.isEditable())) {
return;
}
if (row < 0 && column == null) {
setEditingCell(null);
} else {
setEditingCell(new TablePosition<>(this, row, column));
}
}
但是因为setEditingCell()是一个私有方法,所以我无法以我想要的方式覆盖edit-Method。所以我很好奇:有人能告诉我在同一列中实现动态可编辑表格单元的正确方法,而TableView的editingCell-State总是保持正确吗?
答案 0 :(得分:0)
在侦听器中有这样的内容,只是忽略编辑您不想要的单元格更改
editingCellProperty().addListener((obs,ov,nv) -> {
if (nv!=null && nv.getRow() % 2 != 0/* Only Odd Values are editable. -> Any Random Condition */)
{
System.out.println( "Pretend this never happened" );
}
else
System.out.println("Editstate changed to: " + nv);
});
即使I setEditable(false)
对于EditableCell构造函数中的某些单元格,侦听器仍然会触发。它不认为它发生在TableCell编辑方法中,因为它检查!isEditable()
。正在发生的是editCell更改,从正在编辑的最后一个单元格到未编辑的新单元格。我想这有点意义,但是你没有得到null,但是没有编辑单元格的TablePosition。即使没有编辑单元格,尝试编辑不可编辑的单元格仍然会激活侦听器。
我认为这需要一个错误报告。