Edit item in JavaFX TreeView - javafx

I have this custom TreeView code:
treeView.setCellFactory(new Callback<TreeView<Tree>, TreeCell<Tree>>()
{
#Override
public TreeCell<Tree> call(TreeView<Tree> treeView)
{
final TreeCell<Tree> cell = new TreeCell<Tree>()
{
#Override
protected void updateItem(Tree item, boolean empty)
{
super.updateItem(item, empty);
if (!empty)
{
setText(item != null ? item.toString() : "");
setGraphic(createImageView(item));
setContextMenu(createContextMenuTreeItem(item));
}
else
{
setText(null);
setGraphic(null);
setContextMenu(null);
}
}
};
return cell;
}
});
I would like to be able to rename the nodes of the tree using Content Menu. Can you help me to implement this?

You could simply start the editing of a tree node in MenuItem's EventHandler. Here is an example code that allow the basic editing by double clicking(I didn't try to alter/prevent that) and also from the context menu:
import javafx.application.Application;
import javafx.event.*;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.cell.TextFieldTreeCell;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.*;
import javafx.util.converter.DefaultStringConverter;
public class TreeViewSample extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Tree View Sample");
TreeItem<String> rootItem = new TreeItem<String> ("Tree");
rootItem.setExpanded(true);
for (int i = 1; i < 6; i++) {
TreeItem<String> item = new TreeItem<String> ("Item" + i);
rootItem.getChildren().add(item);
}
TreeView<String> tree = new TreeView<String> (rootItem);
tree.setEditable(true);
tree.setCellFactory(new Callback<TreeView<String>,TreeCell<String>>(){
#Override
public TreeCell<String> call(TreeView<String> p) {
return new RenameMenuTreeCell();
}
});
StackPane root = new StackPane();
root.getChildren().add(tree);
primaryStage.setScene(new Scene(root, 300, 250));
primaryStage.show();
}
private static class RenameMenuTreeCell extends TextFieldTreeCell<String> {
private ContextMenu menu = new ContextMenu();
public RenameMenuTreeCell() {
super(new DefaultStringConverter());
MenuItem renameItem = new MenuItem("Rename");
menu.getItems().add(renameItem);
renameItem.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent arg0) {
startEdit();
}
});
}
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (!isEditing()) {
setContextMenu(menu);
}
}
}
}
This is basically Oracle's example 13-1 with custom tree cells.

Related

JavaFx treetableview setStyle for rows with NO children

In TreeTableView I need to find and setStyle rows with NO children.
In below code example, problematic code is in method: markRows.
public class Controller {
public TreeTableView<MyTreeObject> fuses_ttv;
private ArrayList<MyTreeObject> data = new ArrayList<>();
private void createTreeTableView(){}
private void markRows(){
fuses_ttv.setRowFactory(row -> new TreeTableRow<MyTreeObject>(){
#Override
protected void updateItem(MyTreeObject item, boolean empty) {
super.updateItem(item, empty);
if (item==null){
setStyle(null);
} else if (item.getType().equals("FRC")){
setStyle("-fx-background-color: lightslategray;");
} else if(item.getType().equals("wire")){
setStyle("-fx-background-color: lightyellow;");
} //***** else if (ROW HAS NOW CHILDREN) - HOW TO DO IT????? ******
}
});
}
}
Like in picture below - rows with SLOT "A1" and "A2" have no children.
How to identify such rows?
Thanks in advance for any help.
In JavaFX 19 and later you can do:
fuses_ttv.setRowFactory(row -> new TreeTableRow<MyTreeObject>(){
{
treeItemProperty().flatMap(TreeItem::leafProperty)
.orElse(false)
.addListener((obs, wasLeaf, isLeaf) -> {
if (isLeaf) {
// set style for leaf (no children)
} else {
// set style for non-leaf (has children)
}
});
}
#Override
protected void updateItem(MyTreeObject item, boolean empty) {
super.updateItem(item, empty);
if (item==null){
setStyle(null);
} else if (item.getType().equals("FRC")){
setStyle("-fx-background-color: lightslategray;");
} else if(item.getType().equals("wire")){
setStyle("-fx-background-color: lightyellow;");
} //***** else if (ROW HAS NOW CHILDREN) - HOW TO DO IT????? ******
}
});
I would actually recommend setting custom PseudoClasses, and an external style sheet, instead of using inline styles.
Here is a complete working example:
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.css.PseudoClass;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class TreeTableStyleExample extends Application {
private int itemCount ;
#Override
public void start(Stage stage) throws IOException {
TreeTableView<Integer> table = new TreeTableView<>();
TreeTableColumn<Integer, Number> column = new TreeTableColumn<>("Item");
table.getColumns().add(column);
column.setCellValueFactory(data -> new SimpleIntegerProperty(data.getValue().getValue()));
column.setCellFactory(ttv -> new TreeTableCell<>() {
#Override
protected void updateItem(Number item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
setText("");
} else {
setText("Item "+item);
}
}
});
PseudoClass leaf = PseudoClass.getPseudoClass("leaf");
PseudoClass odd = PseudoClass.getPseudoClass("odd-value");
PseudoClass even = PseudoClass.getPseudoClass("even-value");
table.setRowFactory( ttv -> new TreeTableRow<>() {
{
treeItemProperty().flatMap(TreeItem::leafProperty).orElse(false)
.addListener((obs, wasLeaf, isNowLeaf) -> pseudoClassStateChanged(leaf, isNowLeaf));
}
#Override
protected void updateItem(Integer item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
pseudoClassStateChanged(odd, false);
pseudoClassStateChanged(even, false);
} else {
pseudoClassStateChanged(odd, item % 2 == 1);
pseudoClassStateChanged(even, item % 2 == 0);
}
}
});
table.setRoot(buildTable(20));
Button add = new Button("Add item");
add.disableProperty().bind(Bindings.isEmpty(table.getSelectionModel().getSelectedItems()));
add.setOnAction(e -> {
TreeItem<Integer> treeItem = new TreeItem<>(++itemCount);
treeItem.setExpanded(true);
table.getSelectionModel().getSelectedItem().getChildren().add(treeItem);
});
Button remove = new Button("Remove");
remove.disableProperty().bind(Bindings.isEmpty(table.getSelectionModel().getSelectedItems())
.or(Bindings.equal(table.getSelectionModel().selectedItemProperty(), table.getRoot())));
remove.setOnAction(e -> {
TreeItem<Integer> selection = table.getSelectionModel().getSelectedItem();
selection.getParent().getChildren().remove(selection);
});
HBox controls = new HBox(5, add, remove);
controls.setAlignment(Pos.CENTER);
controls.setPadding(new Insets(5));
BorderPane root = new BorderPane(table);
root.setBottom(controls);
Scene scene = new Scene(root);
scene.getStylesheets().add(getClass().getResource("style.css").toExternalForm());
stage.setScene(scene);
stage.show();
}
private TreeItem<Integer> buildTable(int numItems) {
Random rng = new Random();
TreeItem<Integer> root = new TreeItem<>(1);
root.setExpanded(true);
List<TreeItem> items = new ArrayList<>();
items.add(root);
for (itemCount = 2; itemCount <= numItems ; itemCount++) {
TreeItem<Integer> item = new TreeItem<>(itemCount);
item.setExpanded(true);
items.get(rng.nextInt(items.size())).getChildren().add(item);
items.add(item);
}
return root ;
}
public static void main(String[] args) {
launch();
}
}
with style.css:
.tree-table-row-cell:odd-value {
-fx-background: lightslategray ;
}
.tree-table-row-cell:even-value {
-fx-background: lightyellow;
}
.tree-table-row-cell:leaf {
-fx-background: lightgreen ;
}
Sample output:

How to set text and color of multiple ListView items when clicked

I know there are many related questions about this but maybe I'm missing something because I can't get the behavior I'm expecting, to work.
#FXML
private ListView<String> guiList;
void performAction(Actions action) {
try {
Task<String> task = new Task<>() {
#Override
public String call() {
String mySelection = Context.getInstance().getSelected();
ArrayList<String> selectedList = Context.getInstance().getItemsClicked();
if (selectedList == null) {
selectedList = new ArrayList<>();
}
selectedList.add(mySelection);
Context.getInstance().setItemsClicked(selectedList);
guiList.setCellFactory(new Callback<ListView<String>, ListCell<String>>() {
#Override
public ListCell<String> call(ListView<String> param) {
ListCell<String> cell = new ListCell<String>() {
#Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if(item != null && item.matches(mySelection)) {
setText(mySelection + " [" + action + "]");
setFont(Font.font(Font.getDefault().getFamily(), FontWeight.BOLD, Font.getDefault().getSize()));
setStyle("-fx-text-fill: green;");
} else {
setText(item);
}
}
};
return cell;
}
});
return "";
}
};
} catch (Exception e) {
}
}
When I click in an item of guiList, the text is changed, gets bold and shows in green color but I don't understand why I need the else statement. If I don't use it, all the other items of the list disappear.
I ask this because I want to change ALL of the items I click and in the current behavior, the changes are only made in the last one clicked.
Here is on approach. Use an object that has a Boolean variable to keeps up with if the item has been selected.
KeyCode 1
lvMain.getSelectionModel().selectedItemProperty().addListener(((ov, t, t1) - > {
if (t1 != null) {
t1.setSelected(true);
}
}));
Key Code 2
lvMain.setCellFactory(lv - > new ListCell < MyItem > () {
#Override
public void updateItem(MyItem item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
setGraphic(null);
} else {
setText(item.getText());
if (item.isSelected()) {
setTextFill(Color.RED);
}
}
}
});
Main
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.SelectionMode;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
/**
*
* #author blj0011
*/
public class App extends Application {
#Override
public void start(Stage primaryStage) {
ListView<MyItem> lvMain = new ListView();//Create ListView
lvMain.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);//Change ListView selection mode to multiple
ObservableList<MyItem> items = FXCollections.observableArrayList(new MyItem("Julia"), new MyItem("Ian"), new MyItem("Sue"), new MyItem("Matthew"), new MyItem("Hannah"));//ObseravableList that will be used to set the ListView
lvMain.setItems(items);//Set the ListView's items
lvMain.setCellFactory(lv -> new ListCell<MyItem>()
{
#Override
public void updateItem(MyItem item, boolean empty)
{
super.updateItem(item, empty);
if (empty) {
setText(null);
setGraphic(null);
}
else {
setText(item.getText());
if(item.isSelected())
{
setTextFill(Color.RED);
}
}
}
});
lvMain.getSelectionModel().selectedItemProperty().addListener(((ov, t, t1) -> {
if(t1 != null)
{
t1.setSelected(true);
}
}));
VBox vbox = new VBox();
vbox.getChildren().addAll(lvMain);
StackPane root = new StackPane();
root.getChildren().add(vbox);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
MyItem
/**
*
* #author Sed
*/
public class MyItem {
private String text;
private boolean selected;
public MyItem(String text) {
this.text = text;
this.selected = false;
}
public boolean isSelected() {
return selected;
}
public void setSelected(boolean isSelected) {
this.selected = isSelected;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
Output
I think a better solution would be to use the ListView's built in multiple selection or have your cells have a ToggleButton. When the ToggleButton is on, change the color of the text. When it is off, change the color back to it's original state.

Syntax error on token ">>", Expression expected after this token

I'm getting Syntax error on token “>>”, Expression expected after this token when calling setCellFactory below but do not understand why.
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class TableVieww extends Application {
private static TableView<TableData> table;
public static void main(String[] args) {
launch(args);
}
#SuppressWarnings("unchecked")
public void start(Stage primaryStage) throws Exception {
Stage s = primaryStage;
s.setTitle("The Title");
TableColumn<TableData, String> column1 = new TableColumn<>("String");
column1.setMinWidth(150);
column1.setCellValueFactory(new PropertyValueFactory<TableData, String>("s"));
column1.setEditable(true);
column1.setCellFactory(TextFieldTableCell.forTableColumn());
column1.setOnEditCommit(e -> {
});
TableColumn<TableData, Double> column2 = new TableColumn<>("Double");
column2.setMinWidth(50);
column2.setCellValueFactory(new PropertyValueFactory<TableData, Double>("d"));
column2.setEditable(true);
// Error within this line (The line below)
column2.setCellFactory(TextFieldTableCell.forTableColumn());
column2.setOnEditCommit(e -> {
});
// set up a table
table = new TableView<>();
table.setItems(getData());
table.getColumns().addAll(column1, column2);
table.setEditable(true);
// setting up a layout
VBox layout = new VBox(10);
layout.getChildren().add(table);
// Setting up a scene
Scene scene = new Scene(layout, 500, 200);
s.setScene(scene);
s.show();
}
private static ObservableList<TableData> getData(){
ObservableList<TableData> list = FXCollections.observableArrayList();
TableVieww view = new TableVieww();
list.add(view.new TableData("BlaBlaBla", 10));
list.add(view.new TableData("TraTraTra", 5.1));
return list;
}
public class TableData{
double d;
String s;
public TableData(String s, double d) {
this.d = d;
this.s = s;
}
public double getD() {
return d;
}
public void setD(double d) {
this.d = d;
}
public String getS() {
return s;
}
public void setS(String s) {
this.s = s;
}
}
}
What is wrong? Thanks for your help in advance!
This is not entirely flawless, but it works. You will probaly need to adjust it too fit your needs a lot, but...it works.
public class SpinnerTableCell<S, T> extends TableCell<S, T> {
private Spinner spinner;
private String text;
public SpinnerTableCell(int min, int max) {
this.spinner = new Spinner(min, max, 0.0);
spinner.focusedProperty().addListener((observable, oldBoolean, newBoolean)->{
if(!newBoolean){
setText(spinner.getValue().toString());
text = getText();
setGraphic(null);
}
});
}
public void startEdit() {
if (this.isEditable() && this.getTableView().isEditable() && this.getTableColumn().isEditable()) {
super.startEdit();
if (this.isEditing()) {
setText("");
setGraphic(spinner);
}
}
}
public void cancelEdit() {
super.cancelEdit();
setText(text);
setGraphic(null);
}
public void updateItem(T item, boolean empty) {
super.updateItem(item, empty);
setText(empty ? "" : item.toString());
spinner.getValueFactory().setValue(empty ? 0.0 : item);
}
}
You can set the factory with tableCell.setCellFactory((e)->new SpinnerTableCell(min, max));

Custom ListCell implements InvalidationListener, repaint components

I have a custom ListCell implemented that contains a BorderPane layout with some components.
The cell registers itself to the item. So when the duration of the item changes the invalidated method is called.
In this method I set the text of the duration label. My problem is now the method is called but the label is not repainted.
I think if setText is called the cell should repaint. It is possible to manually repaint the cell or the Label.?
public static class ListItemCell extends ListCell<MusicListItem> implements InvalidationListener{
private AnchorPane listItem;
private Label artist;
private Label title;
private Label duration;
private BorderPane borderPane;
private FlowPane flowPane;
public ListItemCell() {
initCellLayout();
}
public ListItemCell(final LogicInterfaceFX logic) {
...
}
public void initCellLayout() {
try {
this.listItem = (AnchorPane) FXMLLoader.load(getClass().getResource("/de/roth/jsona/view/themes/" + Config.getInstance().THEME + "/" + "layout_list_item.fxml"));
} catch (Exception e) {
e.printStackTrace();
}
this.borderPane = (BorderPane) listItem.getChildren().get(0);
this.flowPane = (FlowPane) borderPane.getLeft();
this.artist = (Label) flowPane.getChildren().get(0);
this.artist.getStyleClass().add(defaultTextClass);
this.title = (Label) flowPane.getChildren().get(1);
this.title.getStyleClass().add(defaultTextClass);
this.duration = (Label) borderPane.getRight();
this.duration.getStyleClass().add(defaultTextClass);
this.setGraphic(listItem);
}
#Override
public void updateItem(MusicListItem item, boolean empty) {
super.updateItem(item, empty);
if (!empty && item != null) {
item.addListener(this);
item.durationProperty().addListener(this);
// Duration
this.duration.setText(item.getDuration());
// Artist / Title
if (item.getArtist() != null) {
this.artist.setText(item.getArtist());
this.title.setText(" - " + item.getTitle());
} else {
this.artist.setText("");
this.title.setText(item.getFile().getName());
}
} else {
this.artist.setText("");
this.title.setText("");
this.duration.setText("");
}
}
#Override
public void invalidated(Observable observable) {
System.out.println("INVALIDATE!!!" + getItem().getFile().getAbsolutePath());
this.duration.setText(getItem().getDuration());
}
}
You have a bug in there: you need to make sure you remove listeners from old items when the item is updated. Remember that ListCells are reused, so updateItem(...) is called multiple times during the lifespan of your ListView.
I don't know if that's what is causing it to fail to update. This works for me:
import java.util.Random;
import javafx.application.Application;
import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.SelectionMode;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
import javafx.util.Callback;
public class ListViewUpdatableProperties extends Application {
#Override
public void start(Stage primaryStage) {
final ListView<Item> listView = new ListView<>();
listView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
final Random rng = new Random();
for (int i=1; i<=20; i++) {
listView.getItems().add(new Item("Item "+i, rng.nextInt(100)));
}
BorderPane root = new BorderPane();
root.setCenter(listView);
listView.setCellFactory(new Callback<ListView<Item>, ListCell<Item>>() {
#Override
public ListCell<Item> call(ListView<Item> param) {
return new ItemListCell();
}
});
HBox controls = new HBox();
controls.setPadding(new Insets(5));
Button incButton = new Button("Increment selected");
incButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
for (Item item : listView.getSelectionModel().getSelectedItems()) {
item.increment();
}
}
});
controls.getChildren().add(incButton);
root.setBottom(controls);
Scene scene = new Scene(root, 250, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
public static class ItemListCell extends ListCell<Item> implements InvalidationListener {
private final HBox hbox ;
private final Label nameLabel ;
private final Label valueLabel ;
public ItemListCell() {
hbox = new HBox(5);
nameLabel = new Label();
valueLabel = new Label();
hbox.getChildren().addAll(nameLabel, valueLabel);
setGraphic(hbox);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
}
#Override
public void updateItem(Item item, boolean empty) {
Item oldItem = getItem();
if (oldItem != null) {
oldItem.valueProperty().removeListener(this);
}
super.updateItem(item, empty);
if (item != null) {
nameLabel.setText(item.getName());
valueLabel.setText(String.valueOf(item.getValue()));
item.valueProperty().addListener(this);
} else {
nameLabel.setText("");
valueLabel.setText("");
}
}
#Override
public void invalidated(Observable observable) {
final int value = getItem().getValue();
System.out.println("Invalidated: item is "+getItem().getName() + " with value "+value);
valueLabel.setText(String.valueOf(value));
}
}
public static class Item {
public Item(String name, int value) {
setName(name);
setValue(value);
}
private final StringProperty name = new SimpleStringProperty(this, "name");
public StringProperty nameProperty() {
return name ;
}
public String getName() {
return name.get();
}
public void setName(String name) {
this.name.set(name);
}
private final IntegerProperty value = new SimpleIntegerProperty(this, "value");
public IntegerProperty valueProperty() {
return value ;
}
public int getValue() {
return value.get();
}
public void setValue(int value) {
this.value.set(value);
}
public void increment() {
value.set(value.get()+1);
}
}
public static void main(String[] args) {
launch(args);
}
}
As stated in the other answer, there is no repaint() method in JavaFX. If you wire things up correctly, when the properties are invalidated, it will know to repaint.
JavaFX uses a "retained mode" rendering model whereas Swing uses an "immediate mode".
See: Retained Mode Versus Immediate Mode (Windows)
So, you don't have a direct repaint() method.

JavaFX editable table cell having display errors

Editing the question as per Brian's suggestion:
I have now trimmed it down to just a single integer column.
I am simply not able to find the problem in the code. THe values show up only when the columns are selected once for edit.
Please suggest of i am making some mistake in the EditingCell class.
The single classfile code that i am trying is as follows.
package javafxtest;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.CellEditEvent;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
//import javafx.scene.control.cell.CheckBoxTableCell;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.stage.Stage;
import javafx.util.Callback;
/**
* FXML Controller class
*
* #author balz
*/
public class UploadTemplateController extends Application {
#Override public void start(Stage primaryStage) throws Exception {
init(primaryStage);
primaryStage.show();
}
public static void main(String[] args) { launch(args); }
private void init(Stage primaryStage) {
Group root = new Group();
primaryStage.setScene(new Scene(root));
MasterUploadParameter objMasterUploadParameter=new MasterUploadParameter();
MasterUploadParameter objMasterUploadParameter1=new MasterUploadParameter();
MasterUploadParameter objMasterUploadParameter2=new MasterUploadParameter();
final ObservableList<MasterUploadParameter> tableContent =
FXCollections.observableArrayList
(
objMasterUploadParameter,
objMasterUploadParameter1,
objMasterUploadParameter2
);
TableColumn ColumnID = new TableColumn();
ColumnID.setText("columnId");
ColumnID.setCellValueFactory(new PropertyValueFactory("columnId"));
Callback<TableColumn, TableCell> cellFactory =
new Callback<TableColumn, TableCell>() {
public TableCell call(TableColumn p) {
return new EditingCell();
}
};
ColumnID.setCellFactory(cellFactory);
TableView tableView = new TableView();
tableView.setItems(tableContent);
//Enabling editing
tableView.setEditable(true);
tableView.getColumns().addAll(ColumnID);
root.getChildren().add(tableView);
}
private void updateObservableListProperties(TableColumn<MasterUploadParameter, Integer> ColumnFieldNo, TableColumn<MasterUploadParameter, Boolean> ColumnLPad, TableColumn<MasterUploadParameter, Integer> ColumnStarting, TableColumn<MasterUploadParameter, Integer> ColumnEnding, TableColumn<MasterUploadParameter, String> ColumnSheetID, TableColumn<MasterUploadParameter, Integer> ColumnID, TableColumn<MasterUploadParameter, Integer> ColumnStartingRow, TableColumn<MasterUploadParameter, Integer> ColumnEnding0) {
ColumnFieldNo.setOnEditCommit(new EventHandler<CellEditEvent<MasterUploadParameter, Integer>>() {
#Override public void handle(CellEditEvent<MasterUploadParameter, Integer> t) {
((MasterUploadParameter) t.getTableView().getItems().get(
t.getTablePosition().getRow())).setcolumnId(new SimpleIntegerProperty(t.getNewValue()));
}
});
}
public static class MasterUploadParameter {
private SimpleIntegerProperty columnId;
public SimpleIntegerProperty columnIdProperty() {return columnId;}
public void setcolumnId(SimpleIntegerProperty columnId) {this.columnId = columnId;}
public MasterUploadParameter() {
this.columnId=new SimpleIntegerProperty(0);
}
}
// EditingCell - for editing capability in a TableCell
public static class EditingCell extends TableCell<MasterUploadParameter, Integer> {
private TextField textField;
public EditingCell() {
System.out.println("find value of textField: "+textField);
}
#Override public void startEdit() {
super.startEdit();
System.out.println("find value of textField: "+textField);
if (textField == null) {
createTextField();
}
setText(null);
setGraphic(textField);
textField.selectAll();
}
#Override public void cancelEdit() {
super.cancelEdit();
setText(String.valueOf(getItem()));
setGraphic(null);
}
public void updateItem(Integer item, boolean empty) {
System.out.println("find value of update: "+empty+item);
super.updateItem(item, empty);
if (empty) {
setText(null);
setGraphic(null);
} else {
if (isEditing()) {
if (textField != null) {
textField.setText(getString());
}
setText(null);
setGraphic(textField);
} else {
setText(getString());
setGraphic(null);
}
}
}
private void createTextField() {
textField = new TextField(getString());
textField.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2);
textField.setOnKeyReleased(new EventHandler<KeyEvent>() {
#Override public void handle(KeyEvent t) {
if (t.getCode() == KeyCode.ENTER) {
commitEdit(Integer.parseInt(textField.getText()));
} else if (t.getCode() == KeyCode.ESCAPE) {
cancelEdit();
}
}
});
}
private String getString() {
return getItem() == null ? "" : getItem().toString();
}
}
}
You don't need separate editing cell types. You can use the col.setOnEditCommit method
Just use public static class EditingCell extends TableCell{ with no type information. (I guess that's why you left out #override before.)
Change the updateItem to #Override public void updateItem(Object item, boolean empty) {
Then whenever you call commitEdit use a string (all textfields have strings anyway). commitEdit(textField.getText())
Then for each column depending, on the type you can commit the edit however you want.
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.application.Platform;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.CellEditEvent;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
//import javafx.scene.control.cell.CheckBoxTableCell;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.stage.Stage;
import javafx.util.Callback;
/**
* FXML Controller class
*
* #author balz
*/
public class UploadTemplateController extends Application {
#Override public void start(Stage primaryStage) throws Exception {
init(primaryStage);
primaryStage.show();
}
public static void main(String[] args) { launch(args); }
private void init(Stage primaryStage) {
Group root = new Group();
primaryStage.setScene(new Scene(root));
MasterUploadParameter objMasterUploadParameter=new MasterUploadParameter();
MasterUploadParameter objMasterUploadParameter1=new MasterUploadParameter();
MasterUploadParameter objMasterUploadParameter2=new MasterUploadParameter();
final ObservableList<MasterUploadParameter> tableContent =
FXCollections.observableArrayList
(
objMasterUploadParameter,
objMasterUploadParameter1,
objMasterUploadParameter2
);
Callback<TableColumn, TableCell> cellFactory = new Callback<TableColumn, TableCell>() {
public TableCell call(TableColumn p) {
return new EditingCell();
}
};
TableColumn ColumnID = new TableColumn();
ColumnID.setText("columnId");
ColumnID.setCellValueFactory(new PropertyValueFactory("columnId"));
ColumnID.setCellFactory(cellFactory);
ColumnID.setOnEditCommit(new EventHandler<CellEditEvent<MasterUploadParameter, String>>() {
#Override
public void handle(CellEditEvent<MasterUploadParameter, String> evt) {
try {
evt.getTableView().getItems().get(evt.getTablePosition().getRow())
.columnId.set(Integer.parseInt(evt.getNewValue()));
} catch (NumberFormatException numberFormatException) {
//do whatever if a non int is entered
}
}
});
TableColumn columnDesc = new TableColumn("Desc");
columnDesc.setCellValueFactory(new PropertyValueFactory("desc"));
columnDesc.setCellFactory(cellFactory);
columnDesc.setOnEditCommit(new EventHandler<CellEditEvent<MasterUploadParameter, String>>() {
#Override
public void handle(CellEditEvent<MasterUploadParameter, String> evt) {
evt.getTableView().getItems().get(evt.getTablePosition().getRow())
.desc.set(evt.getNewValue());
}
});
TableView tableView = new TableView();
tableView.setItems(tableContent);
//Enabling editing
tableView.setEditable(true);
tableView.getColumns().addAll(ColumnID, columnDesc);
root.getChildren().add(tableView);
}
public static class MasterUploadParameter {
private SimpleIntegerProperty columnId;
public SimpleIntegerProperty columnIdProperty() {return columnId;}
private StringProperty desc;
public StringProperty descProperty() {return desc;}
public MasterUploadParameter() {
this.columnId=new SimpleIntegerProperty(0);
this.desc = new SimpleStringProperty("hi");
}
}
// EditingCell - for editing capability in a TableCell
public static class EditingCell extends TableCell{
private TextField textField;
#Override public void startEdit() {
if (!isEmpty()) {
super.startEdit();
createTextField();
setText(null);
setGraphic(textField);
textField.selectAll();
Platform.runLater(new Runnable() {
#Override
public void run() {
textField.requestFocus();
}
});
}
}
#Override public void cancelEdit() {
super.cancelEdit();
try {
setText(getItem().toString());
} catch (Exception e) {
}
setGraphic(null);
}
#Override public void updateItem(Object item, boolean empty) {
System.out.println("find value of update: "+empty+item);
super.updateItem(item, empty);
if (empty) {
setText(null);
setGraphic(null);
} else {
if (isEditing()) {
if (textField != null) {
textField.setText(getString());
}
setText(null);
setGraphic(textField);
} else {
setText(getString());
setGraphic(null);
}
}
}
private void createTextField() {
textField = new TextField(getString());
textField.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2);
textField.setOnKeyReleased(new EventHandler<KeyEvent>() {
#Override public void handle(KeyEvent t) {
if (t.getCode() == KeyCode.ENTER) {
commitEdit(textField.getText());
} else if (t.getCode() == KeyCode.ESCAPE) {
cancelEdit();
}
}
});
}
private String getString() {
return getItem() == null ? "" : getItem().toString();
}
}
}

Resources