2016-05-03 13 views
1

Ich habe einen Anwendungsfall, von dem ich annehmen würde, dass er ziemlich Standard ist, jedoch konnte ich kein Beispiel finden, wie genau dies zu tun ist oder ob es möglich ist.Ist es möglich, editierbare Tabellenspalten in JavaFX8 hintereinander zu deaktivieren?

Nehmen wir an, ich habe folgendes Tableview

First Name Last Name Street NewRecord 

Tom   Smith  Main St.  Yes 
Mike   Smith  First St. No 

In diesem Fall sollte das Gitter bearbeitbare die ersten drei Zellen haben, da der Datensatz neu ist, aber wenn der Datensatz nicht neu ist dann der Nachname Zelle sollte deaktiviert sein.

Ich habe dies in der CellFactory und RowFactory versucht - aber keinen Weg gesehen, dies zu erreichen.

Danke für Ihre Hilfe.

+0

Sowohl 'TableColumn' als auch' TableCell' haben einen bearbeitbaren Zustand. Machen Sie die Spalte editierbar und verwenden Sie eine Zellenfactory, die den bearbeitbaren Zustand der Zelle aktualisiert. Wenn 'NewRecord' unveränderlich ist, können Sie dies einfach und direkt in der 'updateItem'-Methode tun; Wenn es veränderlich ist, dann brauchen Sie ein wenig Trickserei mit Zuhörern, um den 'newRecord'-Zustand richtig zu beobachten. –

+0

Ich habe versucht, das von der CellFactory zu tun - aber ich war nicht in der Lage, genau zu bestimmen, wie man das von dort herausfinden kann? Können Sie ein Snippet bereitstellen? Das könnte alles sein, was ich brauche. Vielen Dank. –

+0

Ist 'newRecord' veränderbar oder nicht? –

Antwort

2

Der einfachste Weg, dies zu tun, ist mit einer Bindungsbibliothek von Drittanbietern: ReactFX 2.0 hat diese Funktionalität eingebaut, wie beschrieben here. Mit, dass Sie

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

tun können (nimmt ein Person Tabelle Modellobjekt mit den offensichtlichen JavaFX Eigenschaften und Methoden).

Ohne die Bibliothek, müssen Sie eine ziemlich miserable verschachtelte Liste der Zuhörer:

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

und dann

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

Eine Alternative eines "legacy Stil" API ist mit

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

Ich mag diese Option nicht, weil es keine Art Sicherheit (oder überhaupt Compiler-Checks) und Werbung fehlt Zusätzlich würde in einigen früheren Versionen von JavaFX fast endlose Warnmeldungen erzeugt werden, wenn eine der Eigenschaften in der "Kette" Nullwerte hätte (was in diesem Fall häufig der Fall ist). Ich glaube, das letztere Problem ist behoben, aber die ReactFX-Version von diesem ist viel besser, imho.

+0

Danke - kann die Bibliothek nicht verwenden, aber das gibt mir den Anstoß, den ich brauche. –

+0

Ich denke, es gibt auch 'Bindings.selectBoolean (cell.tableRowProperty()," item "," newRecord ")', an die Sie 'cell.editableProperty()' binden könnten. Ich habe es vor langer Zeit aufgegeben, da es die Angewohnheit hatte, Warnungen auszugeben, wann immer etwas in der Kette null war (was es häufig, per Entwurf, in einer Tabellenzelle ist), und der Mangel an Typsicherheit ist sehr "Vermächtnis" ; aber es sollte jetzt gut funktionieren. (Ich nehme an, die falschen Warnungen sind jetzt behoben.) –

+0

Ersetzt diese Änderung die Hörer? Ich folge nicht, wie ich diese Logik in der Zellfabrik verwenden würde. –

Verwandte Themen