-
Bug
-
Resolution: Fixed
-
P3
-
8u20
-
Windows 7, JDK (1.8.0_20-ea-b19)
I created a ButtonClick-Action, to create a new Child-Node for a selected TreeItem, expand the selected TreeItem and enter editing-mode for the newly created Child. Unfortunatly a wrong cell is entering editing-mode, even though the editingCellProperty is set correctly. When the editing-mode is finished, the correct TreeItem gets changed.
My intended workflow was the following: User initiates an action which results in a new TreeItem in a TreeTableView below the currently selected TreeItem. The selected Parent should get expanded and the newly created Item should enter editing-mode, so the user can directly enter the desired name.
In the latest official JDK Version (8u5), I did not succed entering editing-mode most of the time, which is why I created a Stackoverflow post (http://stackoverflow.com/questions/24290072/why-javafx-treetableview-edit-mode-gets-undesirably-canceled), but there I have been told, that with Version 8u20-ea my posted example would work.
After changing to the newest JDK (1.8.0_20-ea-b19) version it indeed entered editmode and everything seemed ok, until I changed the size of the window, then suddenly the TreeTableView mixed up indeces and the described behaviour occured.
The bug occurs in most stage-sizes, for example 400x800, but when I set it to 400x400 it suddenly works as expected. So I am wondering if there is any relationship between the cell-index and the stage-size? Is there anything I am doing wrong? I was not able to find any explanation for this sort of behaviour.
Here the Example, where the described behaviour occurs.
/**
* Small Example to evaluate, why the wrong cell gets targeted when initializing edit mode by index.
*
* Intended Workflow: User clicks a Button to create a new Child-Node for a selected TreeItem, expand the
* selected TreeItem and enter editing-mode for the newly created Child. Unfortunatly a wrong cell is entering
* editing-mode, even though the editingCellProperty is set correctly. When the editing-mode is finished, the
* correct TreeItem gets changed.
*
* @author ymene
*/
import javafx.application.Application;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeTableColumn;
import javafx.scene.control.TreeTablePosition;
import javafx.scene.control.TreeTableView;
import javafx.scene.control.cell.TextFieldTreeTableCell;
import javafx.scene.control.cell.TreeItemPropertyValueFactory;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class TreeTableViewCreateExpandAndEditMain extends Application {
private int id = 0;
@Override
public void start(final Stage primaryStage) {
//Generating Testdata:
TreeItem<Item> root = new TreeItem<>(new Item(++id, "Root"));
TreeItem<Item> item1 = new TreeItem<>(new Item(++id, "Item1"));
TreeItem<Item> item11 = new TreeItem<>(new Item(++id, "Item11"));
TreeItem<Item> item2 = new TreeItem<>(new Item(++id, "Item2"));
TreeItem<Item> item3 = new TreeItem<>(new Item(++id, "Item3"));
TreeItem<Item> item31 = new TreeItem<>(new Item(++id, "Item31"));
root.getChildren().add(item1);
item1.getChildren().add(item11);
root.getChildren().add(item2);
root.getChildren().add(item3);
item3.getChildren().add(item31);
TreeTableColumn<Item, Integer> columnId = new TreeTableColumn<>("ColumnId");
TreeTableColumn<Item, String> columnName = new TreeTableColumn<>("ColumnName");
columnId.setCellValueFactory(new TreeItemPropertyValueFactory<Item, Integer>("id"));
columnName.setCellValueFactory(new TreeItemPropertyValueFactory<Item, String>("name"));
//Using Default-CellFactory:
columnName.setCellFactory(TextFieldTreeTableCell.forTreeTableColumn());
//Commiting Cellcontent-Changes:
columnName.setOnEditCommit(new EventHandler<TreeTableColumn.CellEditEvent<Item, String>>() {
@Override
public void handle(final TreeTableColumn.CellEditEvent<Item, String> event) {
final Item item = event.getRowValue().getValue();
System.out.println("Change Item " + item + " from " + event.getOldValue() + " to new value "
+ event.getNewValue());
item.setName(event.getNewValue());
}
});
//Creating TreeTableView:
final TreeTableView<Item> treeTableView = new TreeTableView<>(root);
//Listener at editingCellProperty, to keep track, what is happening here:
treeTableView.editingCellProperty().addListener(new ChangeListener<TreeTablePosition<Item, ?>>() {
@Override
public void changed(final ObservableValue<? extends TreeTablePosition<Item, ?>> observable,
final TreeTablePosition<Item, ?> oldValue,
final TreeTablePosition<Item, ?> newValue) {
System.out.println("EditingCellProperty changed to: "
+ (newValue != null ? newValue.getTreeItem() : newValue)
+ (newValue != null ? " at row " + newValue.getRow() : ""));
}
});
treeTableView.getColumns().add(columnName);
treeTableView.getColumns().add(columnId);
treeTableView.setShowRoot(false);
treeTableView.setColumnResizePolicy(TreeTableView.CONSTRAINED_RESIZE_POLICY);
treeTableView.setEditable(true);
columnId.setEditable(false);
BorderPane layout = new BorderPane();
Button button = new Button("DoAction!");
button.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(final ActionEvent event) {
createNodeAtSelectedAsChild();
}
private void createNodeAtSelectedAsChild() {
/*
* This Method should create a new node at the currently selected node, expand the selected node and start editing the new created node, after selecting it.
*/
final TreeItem<Item> selectedItem = treeTableView.getSelectionModel().getSelectedItem();
final TreeItem<Item> newItem =
new TreeItem<>(new Item(++id, "newItemFor" + selectedItem.getValue().getName()));
selectedItem.getChildren().add(newItem);
selectedItem.expandedProperty().set(true);
final int rowIndex = treeTableView.getRow(newItem);
// treeTableView.getSelectionModel().select( rowIndex );//The desired row gets selected
//
// System.out.println( "Edit Row: " + rowIndex + " edit Value: " + newItem.getValue().getName() );
// System.out.println( "SelectedIndex: " + treeTableView.getSelectionModel().getSelectedIndex() );
treeTableView.edit(rowIndex, columnName);//Wrong Cell edited, why? Especially this seems to depend on Stage-Size. At 400x400 it works.
}
});
layout.setCenter(treeTableView);
layout.setBottom(button);
Scene scene = new Scene(layout, 400, 800);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(final String[] args) {
launch(args);
}
public static 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;
}
@Override
public String toString() {
return "[Item: " + "name=" + getName() + ", id=" + getId() + "]";
}
}
}
My intended workflow was the following: User initiates an action which results in a new TreeItem in a TreeTableView below the currently selected TreeItem. The selected Parent should get expanded and the newly created Item should enter editing-mode, so the user can directly enter the desired name.
In the latest official JDK Version (8u5), I did not succed entering editing-mode most of the time, which is why I created a Stackoverflow post (http://stackoverflow.com/questions/24290072/why-javafx-treetableview-edit-mode-gets-undesirably-canceled), but there I have been told, that with Version 8u20-ea my posted example would work.
After changing to the newest JDK (1.8.0_20-ea-b19) version it indeed entered editmode and everything seemed ok, until I changed the size of the window, then suddenly the TreeTableView mixed up indeces and the described behaviour occured.
The bug occurs in most stage-sizes, for example 400x800, but when I set it to 400x400 it suddenly works as expected. So I am wondering if there is any relationship between the cell-index and the stage-size? Is there anything I am doing wrong? I was not able to find any explanation for this sort of behaviour.
Here the Example, where the described behaviour occurs.
/**
* Small Example to evaluate, why the wrong cell gets targeted when initializing edit mode by index.
*
* Intended Workflow: User clicks a Button to create a new Child-Node for a selected TreeItem, expand the
* selected TreeItem and enter editing-mode for the newly created Child. Unfortunatly a wrong cell is entering
* editing-mode, even though the editingCellProperty is set correctly. When the editing-mode is finished, the
* correct TreeItem gets changed.
*
* @author ymene
*/
import javafx.application.Application;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeTableColumn;
import javafx.scene.control.TreeTablePosition;
import javafx.scene.control.TreeTableView;
import javafx.scene.control.cell.TextFieldTreeTableCell;
import javafx.scene.control.cell.TreeItemPropertyValueFactory;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class TreeTableViewCreateExpandAndEditMain extends Application {
private int id = 0;
@Override
public void start(final Stage primaryStage) {
//Generating Testdata:
TreeItem<Item> root = new TreeItem<>(new Item(++id, "Root"));
TreeItem<Item> item1 = new TreeItem<>(new Item(++id, "Item1"));
TreeItem<Item> item11 = new TreeItem<>(new Item(++id, "Item11"));
TreeItem<Item> item2 = new TreeItem<>(new Item(++id, "Item2"));
TreeItem<Item> item3 = new TreeItem<>(new Item(++id, "Item3"));
TreeItem<Item> item31 = new TreeItem<>(new Item(++id, "Item31"));
root.getChildren().add(item1);
item1.getChildren().add(item11);
root.getChildren().add(item2);
root.getChildren().add(item3);
item3.getChildren().add(item31);
TreeTableColumn<Item, Integer> columnId = new TreeTableColumn<>("ColumnId");
TreeTableColumn<Item, String> columnName = new TreeTableColumn<>("ColumnName");
columnId.setCellValueFactory(new TreeItemPropertyValueFactory<Item, Integer>("id"));
columnName.setCellValueFactory(new TreeItemPropertyValueFactory<Item, String>("name"));
//Using Default-CellFactory:
columnName.setCellFactory(TextFieldTreeTableCell.forTreeTableColumn());
//Commiting Cellcontent-Changes:
columnName.setOnEditCommit(new EventHandler<TreeTableColumn.CellEditEvent<Item, String>>() {
@Override
public void handle(final TreeTableColumn.CellEditEvent<Item, String> event) {
final Item item = event.getRowValue().getValue();
System.out.println("Change Item " + item + " from " + event.getOldValue() + " to new value "
+ event.getNewValue());
item.setName(event.getNewValue());
}
});
//Creating TreeTableView:
final TreeTableView<Item> treeTableView = new TreeTableView<>(root);
//Listener at editingCellProperty, to keep track, what is happening here:
treeTableView.editingCellProperty().addListener(new ChangeListener<TreeTablePosition<Item, ?>>() {
@Override
public void changed(final ObservableValue<? extends TreeTablePosition<Item, ?>> observable,
final TreeTablePosition<Item, ?> oldValue,
final TreeTablePosition<Item, ?> newValue) {
System.out.println("EditingCellProperty changed to: "
+ (newValue != null ? newValue.getTreeItem() : newValue)
+ (newValue != null ? " at row " + newValue.getRow() : ""));
}
});
treeTableView.getColumns().add(columnName);
treeTableView.getColumns().add(columnId);
treeTableView.setShowRoot(false);
treeTableView.setColumnResizePolicy(TreeTableView.CONSTRAINED_RESIZE_POLICY);
treeTableView.setEditable(true);
columnId.setEditable(false);
BorderPane layout = new BorderPane();
Button button = new Button("DoAction!");
button.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(final ActionEvent event) {
createNodeAtSelectedAsChild();
}
private void createNodeAtSelectedAsChild() {
/*
* This Method should create a new node at the currently selected node, expand the selected node and start editing the new created node, after selecting it.
*/
final TreeItem<Item> selectedItem = treeTableView.getSelectionModel().getSelectedItem();
final TreeItem<Item> newItem =
new TreeItem<>(new Item(++id, "newItemFor" + selectedItem.getValue().getName()));
selectedItem.getChildren().add(newItem);
selectedItem.expandedProperty().set(true);
final int rowIndex = treeTableView.getRow(newItem);
// treeTableView.getSelectionModel().select( rowIndex );//The desired row gets selected
//
// System.out.println( "Edit Row: " + rowIndex + " edit Value: " + newItem.getValue().getName() );
// System.out.println( "SelectedIndex: " + treeTableView.getSelectionModel().getSelectedIndex() );
treeTableView.edit(rowIndex, columnName);//Wrong Cell edited, why? Especially this seems to depend on Stage-Size. At 400x400 it works.
}
});
layout.setCenter(treeTableView);
layout.setBottom(button);
Scene scene = new Scene(layout, 400, 800);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(final String[] args) {
launch(args);
}
public static 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;
}
@Override
public String toString() {
return "[Item: " + "name=" + getName() + ", id=" + getId() + "]";
}
}
}