2014-05-19 61 views
1

以下問題:我需要知道在特定時刻,天氣我的TableView目前正在編輯或不編輯。我使用了editingCellProperty,並綁定了一個特定的業務邏輯,以便在表格切換這些模式時得到通知。如何正確避免beeing可編輯的特定TableViewCells?

不幸的是,狀態並不總是顯示正確,因爲我有特定的單元格(在同一列中),根本不應該被編輯,但仍然點擊不可編輯的單元格時,TablePosition被設置爲editingCellProperty,因此我得到了我的TableView正在編輯的信息,儘管它已經被告知,但是這個單元格是不可編輯的,編輯模式從未真正開始。

我創建了一個小例子,其中ColumnName的所有偶數行都是可編輯的,而奇數行不是。

Small Example

例碼:

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); 
      } 
     } 
     }); 
    } 
    } 
} 

數據類項目:

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

我想你可以按照你的邏輯在變化監聽器。我做了類似於你的事來阻止編輯,但我不需要聽。如果需要,您可以從TablePosition訪問該項目。 – brian

+0

這就是我想要做的,但唯一的問題是,即使當我單擊不可編輯的單元格時,也會使用相應的表格位置(而不是null)調用changelistener方法,因爲TableViews編輯方法不會了解列中的非可編輯單元格(在我的示例中,每隔一行)。你檢查過財產,而在你的情況下阻止編輯?我很好奇你如何實現阻塞方面,而不讓編輯方法改變屬性。 – crusam

+0

看起來你在這個例子中沒有使用你的EditableCell類,但這是我檢查的地方。 '@Override public void startEdit(){if(!MyCondition)return; ''。但是,我添加了您的監聽器,並且它仍然會觸發。 – brian

回答

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); 
    }); 

即使我setEditable(false)在EditableCell構造一些細胞,聽者依然閃光。它不認爲它發生在TableCell編輯方法中,因爲它檢查了!isEditable()。正在發生的是正在編輯的最後一個單元格到未編輯的新單元格的編輯單元發生了變化。我想這有點道理,但是你沒有得到null,但是單元格的TablePosition沒有被編輯。即使沒有正在編輯的單元格,嘗試編​​輯不可編輯的單元格仍會觸發收聽者。

我認爲這需要一個錯誤報告。

相關問題