I have a problem on JavaFx TableView with large data such as whats happened on the items on the picture.
With huge data,the TableView do crazy works when i select a row or a cell.
I repeated the Number '131004' more than once for reference only
How can i solve this problem with large data?!? i didn't find any resource for that.
EDITED
also i have the same problem when i use scroll to up/down
The class is
import javafx.application.Platform;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.TableCell;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
/**
*
* #author mohammad
*/
public class EditingCellNew extends TableCell<Object, Integer> {
private TextField textField;
public EditingCellNew() {
this.setAlignment(Pos.CENTER);
}
#Override
public void startEdit() {
if (!isEmpty()) {
super.startEdit();
if (textField == null) {
createTextField();
}
textField.setText(getString());
//setText(null);
setGraphic(textField);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
textField.selectAll();
Platform.runLater(new Runnable() {
#Override
public void run() {
textField.requestFocus();
}
});
}
}
#Override
public void cancelEdit() {
super.cancelEdit();
setText(String.valueOf(getItem()));
setContentDisplay(ContentDisplay.TEXT_ONLY);
}
#Override
public void updateItem(Integer item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
setGraphic(null);
} else {
if (isEditing()) {
if (textField != null) {
textField.setText(getString());
}
setGraphic(textField);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
} else {
setText(getString());
setContentDisplay(ContentDisplay.TEXT_ONLY);
}
}
}
private void createTextField() {
textField = new TextField(getString());
textField.setAlignment(Pos.CENTER);
textField.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2);
textField.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent t) {
if (t.getCode() == KeyCode.ENTER) {
commitEdit(Integer.parseInt(textField.getText()));
System.out.println("table row : " + getTableRow().getIndex());
updateTableRow(getTableRow());
updateTableColumn(getTableColumn());
updateTableView(getTableView());
} else if (t.getCode() == KeyCode.ESCAPE) {
cancelEdit();
}
}
});
textField.setOnKeyReleased(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent t) {
if (t.getCode() == KeyCode.ENTER) {
updateTableRow(getTableRow());
updateTableView(getTableView());
//bondTable.getItems().set(bondTable.getSelectionModel().getSelectedIndex(), bondTable.getSelectionModel().getSelectedItem());
System.out.println("realesed enter");
}
}
});
}
private String getString() {
return String.valueOf(getItem()) == null ? "" : String.valueOf(getItem());
}
}
Related
Good Day
When on an editable cell, I would like the user to start typing a number without having to press the Enter key first. I have this partly working with the following code :
tableView.setEditable(true);
tableView.getSelectionModel().cellSelectionEnabledProperty().set(true);
tableView.setOnKeyReleased(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event) {
TablePosition tp;
if(event.getCode().isDigitKey()){
tp = tableView.getFocusModel().getFocusedCell();
tableView.edit(tp.getRow() , tp.getTableColumn());
}
}
});
setColumnStyling();
updateOrderColumn.setMaxWidth(1500);
updateOrderColumn.setCellFactory(TextFieldTableCell.forTableColumn(new DoubleStringConverter()));
updateOrderColumn.setEditable(true);
As soon as a Numeric key is press, the cell does go into editing mode. However, the Numeric key that is initially pressed is not entered into the TextFieldTableCell. Therefor if the user types "1234", only "234" is captured.
How do I overcome this?
I could save the key press to a String variable, but then how do I insert it into the cell?
It is not possible to do with the standard TextFieldTableCell you get from
TextFieldTableCell.forTableColumn(), but you can create a custom table cell like this:
package org.example;
import javafx.application.Application;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.event.Event;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.stage.Stage;
import java.util.stream.IntStream;
public class CustomTableCellTestApp extends Application {
#Override
public void start(Stage stage) {
TableView<Item> tableView = new TableView<>();
tableView.setEditable(true);
tableView.getSelectionModel().setCellSelectionEnabled(true);
TableColumn<Item, Integer> intCol = new TableColumn<>("int col");
tableView.getColumns().add(intCol);
intCol.setCellValueFactory(cellData -> cellData.getValue().myIntProperty().asObject());
intCol.setCellFactory(c -> new CustomTableCell());
intCol.setMinWidth(150);
// Enter edit mode on digit key pressed:
tableView.setOnKeyPressed(event -> {
TablePosition<Item, ?> pos = tableView.getFocusModel().getFocusedCell();
if (pos != null && event.getCode().isDigitKey())
tableView.edit(pos.getRow(), pos.getTableColumn());
});
IntStream.range(23, 28).forEach(i -> tableView.getItems().add(new Item(i)));
stage.setScene(new Scene(tableView));
stage.show();
}
class CustomTableCell extends TableCell<Item, Integer> {
private TextField textField;
boolean initValue;
private void createTextField() {
textField = new TextField(getItem().toString());
// This fixes "initially pressed [digit] is not entered into the TextFieldTableCell"
initValue = false;
textField.addEventHandler(KeyEvent.KEY_RELEASED, keyEvent -> {
if (!initValue && !(keyEvent.getCode() == KeyCode.ENTER)) {
textField.setText(keyEvent.getText());
textField.positionCaret(textField.getText().length());
}
initValue = true;
});
textField.addEventHandler(KeyEvent.KEY_PRESSED, keyEvent -> {
if (keyEvent.getCode() == KeyCode.ENTER) {
try {
commitEdit(Integer.parseInt(textField.getText()));
} catch (NumberFormatException ignored) {
cancelEdit();
} finally {
keyEvent.consume();
}
}
});
// Commit value on focus lost:
textField.focusedProperty().addListener((obs, wasFocused, isNowFocused) -> {
if (wasFocused) {
try {
commitEdit(Integer.parseInt(textField.getText()));
} catch (NumberFormatException ignored) {
cancelEdit();
}
}
});
// Allow only ten digits:
textField.setTextFormatter(new TextFormatter<>(change -> {
String text = change.getControlNewText();
if (text.matches("\\d*") && text.length() < 10)
return change;
return null;
}));
}
#Override
public void startEdit() {
super.startEdit();
setText(null);
createTextField();
setGraphic(textField);
textField.requestFocus();
textField.selectAll();
}
#Override
public void cancelEdit() {
super.cancelEdit();
setText(getItem().toString());
setGraphic(null);
textField = null;
}
#Override
public void commitEdit(Integer item) {
// This block is necessary to support commit on losing focus, because the baked-in mechanism
// sets our editing state to false before we can intercept the loss of focus.
// The default commitEdit(...) method simply bails if we are not editing...
// See: https://gist.github.com/james-d/be5bbd6255a4640a5357
if (!isEditing() && !item.equals(getItem())) {
TableView<Item> table = getTableView();
if (table != null) {
TableColumn<Item, Integer> column = getTableColumn();
TableColumn.CellEditEvent<Item, Integer> event = new TableColumn.CellEditEvent<>(table,
new TablePosition<>(table, getIndex(), column), TableColumn.editCommitEvent(), item);
Event.fireEvent(column, event);
}
}
super.commitEdit(item);
setText(item.toString());
setGraphic(null);
textField = null;
}
#Override
protected void updateItem(Integer item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty)
setText(null);
else
setText(item.toString());
}
}
class Item {
private final IntegerProperty myInt;
public Item(int age) {
this.myInt = new SimpleIntegerProperty(age);
}
public int getMyInt() {
return myInt.get();
}
public IntegerProperty myIntProperty() {
return myInt;
}
public void setMyInt(int myInt) {
this.myInt.set(myInt);
}
}
}
I have a ListView with the languages one employee can speak. It uses custom ListCells implemented with the help of setCellFactory. I have a ListCellFactory class where I stored the call for my custom ListCell. In my LanguageListCell (my custom ListCell class) I have a ContextMenu in which I have a MenuItem. The MenuItem fires an event to edit the selected ListCell. The only problem I have encountered in my project is having this double click editing. Whenever I click more than once (when the Cell is not selected) or once (when the Cell is selected) the startEdit gets called. What I want to accomplish is remove this double click editing. But what I have managed to write as a code causes too many problems. For example, when I click on the TextField which is used for the editing, the cancelEdit method is called. And, basically, I can't even click on the TextField without removing it.
See my code for reference
This is the LanguageListCell class
package application;
import javafx.beans.binding.Bindings;
import javafx.event.EventHandler;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
public class LanguageListCell extends ListCell<String> {
private TextField textField;
LanguageListCell cell = this;
int i = 0;
public LanguageListCell(ListView<String> languages) {
ContextMenu contextMenu = new ContextMenu();
cell.setEditable(true);
MenuItem editItem = new MenuItem();
editItem.textProperty().bind(Bindings.format("Edit \"%s\"", cell.itemProperty()));
editItem.setOnAction(event -> {
languages.edit(cell.getIndex());
//cell.startEdit();
});
contextMenu.getItems().add(editItem);
cell.textProperty().bind(cell.itemProperty());
cell.emptyProperty().addListener((obs, wasEmpty, isNowEmpty) -> {
if (isNowEmpty) {
cell.setContextMenu(null);
} else {
if (getString() != "Add") {
cell.setContextMenu(contextMenu);
}
}
});
//This is what I have tried but i get the issue with cancelEdit
//where when I press the TextField it cancels the editing
cell.addEventFilter(MouseEvent.MOUSE_PRESSED, (MouseEvent e) -> {
if (e.getButton().equals(MouseButton.PRIMARY)) {
if (cell.isSelected() && e.getClickCount() >= 1) {
languages.getSelectionModel().clearSelection();
languages.getSelectionModel().select(cell.getItem());
e.consume();
}
if (e.getClickCount() > 1) {
e.consume();
}
}
});
}
public String getString() {
return getItem() == null ? "" : getItem().toString();
}
#Override
public void startEdit() {
super.startEdit();
if (textField == null) {
createTextField();
}
setText(null);
setGraphic(textField);
textField.selectAll();
textField.requestFocus();
}
#Override
public void cancelEdit() {
super.cancelEdit();
setGraphic(null);
setText(getItem());
textField = null;
}
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
cell.textProperty().unbind();
if (empty) {
setText(null);
setGraphic(null);
} else {
if (isEditing()) {
if (textField != null) {
textField.setText(getString());
}
setText(null);
setGraphic(textField);
} else {
setText(getString());
setGraphic(getGraphic());
}
}
}
private void createTextField() {
textField = new TextField(getString());
textField.setOnKeyReleased(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent t) {
if (t.getCode() == KeyCode.ENTER) {
if (textField.getText().trim() != "" && textField.getText().trim().length() > 3) {
commitEdit(textField.getText());
setGraphic(null);
setGraphic(getGraphic());
}
} else if (t.getCode() == KeyCode.ESCAPE) {
cancelEdit();
}
}
});
}
}
This is the LanguageCellFactory class
package application;
import javafx.beans.binding.Bindings;
import javafx.scene.Node;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.MenuItem;
import javafx.scene.layout.Pane;
import javafx.util.Callback;
import application.LanguageListCell;
public class LanguageCellFactory implements Callback<ListView<String>, ListCell<String>> {
public LanguageCellFactory()
{
}
#Override
public ListCell<String> call(ListView<String> languages)
{
return new LanguageListCell(languages);
}
}
And this is the Main class
package application;
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.control.ListView;
import java.util.ArrayList;
import application.LanguageCellFactory;
public class Main extends Application {
private ListView<String> languages;
private Stage stage;
#Override
public void init()
{
}
public void start(Stage primaryStage) {
try {
Pane root = new Pane();
Scene scene = new Scene(root,800,600);
ArrayList<String> list_items = new ArrayList<String>();
list_items.add("Russian");
list_items.add("English");
languages = new ListView<String>();
languages.relocate(150, 62);
languages.getItems().addAll(list_items);
root.getChildren().add(languages);
//languages.setEditable(true);
languages.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
languages.setCellFactory(new LanguageCellFactory());
primaryStage.setScene(scene);
primaryStage.setTitle("First JavaFX App");
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
If someone wants to know how to fix this, I tried removing the editing events for the ListCell and provided my own "editing" behaviour for the cells and now it is working
Here is the modified version of the LanguageListCell class
package application;
import javafx.beans.binding.Bindings;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
public class LanguageListCell extends ListCell<String> {
private TextField textField;
LanguageListCell cell = this;
int i = 0;
private boolean textfield_state = false;
ContextMenu contextMenu = new ContextMenu();
MenuItem editItem = new MenuItem();
public LanguageListCell(ListView<String> languages) {
editItem.textProperty().bind(Bindings.format("Edit \"%s\"", cell.itemProperty()));
contextMenu.getItems().add(editItem);
cell.textProperty().bind(cell.itemProperty());
cell.emptyProperty().addListener((obs, wasEmpty, isNowEmpty) -> {
if (isNowEmpty) {
cell.setContextMenu(null);
} else {
if (getString() != "Add") {
cell.setContextMenu(contextMenu);
}
}
});
}
public String getString() {
return getItem() == null ? "" : getItem().toString();
}
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
cell.textProperty().unbind();
//String thecellValue = getString();
if (empty) {
setText(null);
setGraphic(null);
} else {
if (textfield_state) {
if (textField != null) {
textField.setText(getString());
}
setText(null);
setGraphic(textField);
} else {
setText(getString());
setGraphic(getGraphic());
editItem.setOnAction(event -> {
textfield_state = true;
if(textField == null)
{
createTextField();
}
setText(null);
setGraphic(textField);
textField.requestFocus();
textField.selectAll();
});
}
}
}
private void createTextField() {
textField = new TextField(getString());
String CellValue = getString();
textField.setOnKeyReleased(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent t) {
if (t.getCode() == KeyCode.ENTER) {
if (textField.getText().trim() != "" && textField.getText().trim().length() > 3) {
setText(textField.getText().trim());
setGraphic(null);
}
} else if (t.getCode() == KeyCode.ESCAPE) {
//cancelEdit();
setGraphic(null);
setText(CellValue);
textField = null;
}
}
});
textField.focusedProperty().addListener((obs, isNotFocused, isFocused) -> {
if(isFocused)
{
LanguageListCell parent = (LanguageListCell) textField.getParent();
ListView<String> list = parent.getListView();
list.getSelectionModel().clearSelection();
list.getSelectionModel().select(parent.getIndex());
}
else
{
setGraphic(null);
setText(CellValue);
textField = null;
}
});
}
}
Is there a way to change the text of a TreeItem of TreeView, when I click a button?
I tried to do something like shown in the oracle example
http://docs.oracle.com/javafx/2/ui_controls/tree-view.htm
but I don't want to change the TreeItem by click on it, but rather clicking on the button. In a second step, I want to work with context menu to open a window with a Textfield, where I can manually insert the text to change the treeitems naming.
package treeviewexample;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.Callback;
public class TreeViewExample extends Application {
#Override
public void start(Stage primaryStage) {
TreeItem root = new TreeItem ("root");
TreeItem item1 = new TreeItem ("Level1");
TreeItem item2 = new TreeItem ("Level1");
TreeItem item11 = new TreeItem ("Level2");
TreeView tree = new TreeView ();
item1.getChildren().add(item11);
tree.setRoot(root);
tree.getRoot().getChildren().addAll(item1, item2);
tree.getRoot().setExpanded(true);
StackPane rootPane = new StackPane();
tree.setEditable(true);
tree.setCellFactory(new Callback<TreeView<String>, TreeCell<String>>(){
#Override
public TreeCell<String> call(TreeView<String> param) {
return new TextFieldTreeCellImpl();
}
});
rootPane.getChildren().add(tree);
Button btn = new Button();
btn.setText("Change Name to 'TEST'");
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
//CHANGE TEXT OF SELECTED TreeItem to "TEST"?
}
});
rootPane.getChildren().add(btn);
Scene scene = new Scene(rootPane);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
public class TextFieldTreeCellImpl extends TreeCell<String> {
private TextField textField;
public TextFieldTreeCellImpl (){
}
#Override
public void startEdit() {
super.startEdit();
if (textField == null) {
createTextField();
}
setText(null);
setGraphic(textField);
textField.selectAll();
}
public void cancelEdit() {
super.cancelEdit();
setText((String) getItem());
setGraphic(getTreeItem().getGraphic());
}
#Override
public void updateItem(String item, boolean empty){
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(getTreeItem().getGraphic());
}
}
};
private void createTextField() {
textField = new TextField(getString());
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();
}
}
}
You can simply use setValue() method to change the text of TreeItem.
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
desired_tree_item.setValue("TEST");
}
});
I'm working with a JavaFx TreeTableView in Java. Most of my cells are editable, but some are not. When editing a cell, pressing tab jumps to the next editable cell - as expected, but when at the end of a row, it just exits editing. Is there a way to change this behavior, so that the next row is selected with its first editable cell?
Custom factories when adding a new column:
/**
* Create a column. The column is also added to the billing table.
*
* #param columnName
* Name of the column.
* #return Created column.
*/
public TreeTableColumn<BillingTableRow, Double> addColumn(String columnName) {
TreeTableColumn<BillingTableRow, Double> column = new TreeTableColumn<>(columnName);
// Bind column data
column.setCellValueFactory(new Callback<TreeTableColumn.CellDataFeatures<BillingTableRow, Double>, ObservableValue<Double>>() {
#Override
public ObservableValue<Double> call(CellDataFeatures<BillingTableRow, Double> param) {
return new ObservableValueBase<Double>() {
#Override
public Double getValue() {
if (param.getValue().getValue().getType() == BillingTableRow.TYPE_SERVICE) {
if (param.getValue().getValue().getService().getAll().containsKey(columnName)) {
return param.getValue().getValue().getService().getAll().get(columnName).getTime();
}
}
return null;
}
};
}
});
// Cell editing
column.setCellFactory(new Callback<TreeTableColumn<BillingTableRow, Double>, TreeTableCell<BillingTableRow, Double>>() {
#Override
public TreeTableCell<BillingTableRow, Double> call(TreeTableColumn<BillingTableRow, Double> p) {
return new EditableTreeTableDoubleCell() {
#Override
public void updateItem(Double item, boolean empty) {
super.updateItem(item, empty);
BillingTableRow row = getTreeTableRow().getItem();
if (!empty && row != null) {
// Styling
if (row.getType() == BillingTableRow.TYPE_CLIENT) {
setStyle("-fx-font-weight: bold;");
} else {
setStyle("");
}
// Update total values
BillingTableRow parentRow = (BillingTableRow) getTreeTableRow().getTreeItem().getParent().getValue();
parentRow.updateTotal();
row.getTable().getRoot().getValue().updateTotal();
} else {
// Clear cell if it's empty
setText(null);
setGraphic(null);
}
// if (empty) {
// setEditable(false);
// }
}
};
}
});
// Edit event handler
column.setOnEditCommit(new EventHandler<TreeTableColumn.CellEditEvent<BillingTableRow, Double>>() {
#Override
public void handle(CellEditEvent<BillingTableRow, Double> t) {
BillingTableRow row = t.getTreeTablePosition().getTreeItem().getValue();
if (t.getNewValue() != null) {
if (row.getType() == BillingTableRow.TYPE_SERVICE && row.getService().getAll().containsKey(columnName)) {
row.getService().getAll().get(columnName).setTime(t.getNewValue());
}
}
if (row.getChildren().size() > 0) {
if (t.getTreeTablePosition().getTreeItem().getParent().getParent() != null)
t.getTreeTablePosition().getTreeItem().getParent().getParent().getValue().updateTotal();
}
}
});
table.getColumns().add(column);
return column;
}
Custom cells:
package gui;
import java.util.ArrayList;
import java.util.List;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.EventHandler;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.TextField;
import javafx.scene.control.TreeTableCell;
import javafx.scene.control.TreeTableColumn;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
/**
* Editable TreeTableCell of type double.
*
* #author Peter Jonsson, Graham Smith
*
*/
public class EditableTreeTableDoubleCell extends TreeTableCell<BillingTableRow, Double> {
private TextField textField;
public EditableTreeTableDoubleCell() {
}
#Override
public void startEdit() {
super.startEdit();
if (textField == null) {
if (isEditable()) {
createTextField();
} else {
return;
}
}
setGraphic(textField);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
Platform.runLater(new Runnable() {
#Override
public void run() {
textField.requestFocus();
textField.selectAll();
}
});
}
#Override
public void cancelEdit() {
super.cancelEdit();
if (getItem() != null) {
setText(Double.toString(getItem()));
}
setContentDisplay(ContentDisplay.TEXT_ONLY);
}
#Override
public void updateItem(Double item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
setGraphic(null);
} else {
if (isEditing()) {
if (textField != null) {
textField.setText(getString());
}
setGraphic(textField);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
} else {
setText(getString());
setContentDisplay(ContentDisplay.TEXT_ONLY);
}
}
// Cell locking
if (item == null) {
setEditable(false);
} else {
setEditable(true);
}
}
private void createTextField() {
textField = new TextField(getString());
if (textField.getText().isEmpty()) {
textField.setText("0");
}
textField.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2);
textField.setOnKeyPressed(new EventHandler<KeyEvent>() {
#SuppressWarnings({ "unchecked", "rawtypes" })
#Override
public void handle(KeyEvent t) {
if (t.getCode() == KeyCode.ENTER) {
commitEdit(Double.parseDouble(sanitizeInput(textField.getText())));
} else if (t.getCode() == KeyCode.ESCAPE) {
cancelEdit();
} else if (t.getCode() == KeyCode.TAB) {
commitEdit(Double.parseDouble(sanitizeInput(textField.getText())));
TreeTableColumn nextColumn = getNextColumn(!t.isShiftDown());
if (nextColumn != null) {
getTreeTableView().edit(getTreeTableRow().getIndex(), nextColumn);
}
}
}
});
textField.focusedProperty().addListener(new ChangeListener<Boolean>() {
#Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
if (!newValue && textField != null) {
commitEdit(Double.parseDouble(sanitizeInput(textField.getText())));
}
}
});
}
private String getString() {
return getItem() == null ? "" : getItem().toString();
}
/**
*
* #param forward
* true gets the column to the right, false the column to the
* left of the current column
* #return next column
*/
private TreeTableColumn<BillingTableRow, ?> getNextColumn(boolean forward) {
List<TreeTableColumn<BillingTableRow, ?>> columns = new ArrayList<>();
for (TreeTableColumn<BillingTableRow, ?> column : getTreeTableView().getColumns()) {
columns.addAll(getLeaves(column));
}
// There is no other column that supports editing.
if (columns.size() < 2) {
return null;
}
int currentIndex = columns.indexOf(getTableColumn());
int nextIndex = currentIndex;
if (forward) {
nextIndex++;
if (nextIndex > columns.size() - 1) {
nextIndex = 0;
}
} else {
nextIndex--;
if (nextIndex < 0) {
nextIndex = columns.size() - 1;
}
}
return columns.get(nextIndex);
}
private List<TreeTableColumn<BillingTableRow, ?>> getLeaves(TreeTableColumn<BillingTableRow, ?> root) {
List<TreeTableColumn<BillingTableRow, ?>> columns = new ArrayList<>();
if (root.getColumns().isEmpty()) {
// We only want the leaves that are editable.
if (root.isEditable()) {
columns.add(root);
}
return columns;
} else {
for (TreeTableColumn<BillingTableRow, ?> column : root.getColumns()) {
columns.addAll(getLeaves(column));
}
return columns;
}
}
/**
* Sanitize an inputted string.
*
* #param string
* String to sanitize.
* #return Sanitized string.
*/
private String sanitizeInput(String string) {
if (string != null && !string.isEmpty()) {
return string;
}
return "0";
}
}
I´m currently working on a TreeView and want to implement a ContextMenu which pops up on rightClick on a TreeCell. I´ve studied the examples but I´m not sure of how I can set the ContextMenu to popup on every cell, not just the ones that are filled with children.
Here my code (pretty much the sample code):
Constructor
.
.
.
this.setCellFactory(new Callback<TreeView<String>,TreeCell<String>>()
{
#Override
public TreeCell<String> call(TreeView<String> p)
{
return new TextFieldTreeCellImpl();
}
});
}
private final class TextFieldTreeCellImpl extends TreeCell<String>
{
private TextField textField;
private ContextMenu addMenu = new ContextMenu();
#SuppressWarnings({ "rawtypes", "unchecked" })
public TextFieldTreeCellImpl()
{
MenuItem addMenuItem = new MenuItem("Add Note");
addMenu.getItems().add(addMenuItem);
addMenuItem.setOnAction(new EventHandler()
{
public void handle(Event t)
{
ImageView noteIcon = new ImageView(new Image(getClass().getResourceAsStream("../icons/note.png")));
noteIcon.setFitHeight(16);
noteIcon.setFitWidth(16);
TreeItem newNote = new TreeItem<String>("New Note");
getTreeItem().getChildren().add(newNote);
}
});
}
#Override
public void startEdit()
{
super.startEdit();
if (textField == null)
{
createTextField();
}
setText(null);
setGraphic(textField);
textField.selectAll();
}
#Override
public void cancelEdit()
{
super.cancelEdit();
setText((String) getItem());
setGraphic(getTreeItem().getGraphic());
}
#Override
public void updateItem(String item, boolean empty)
{
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(getTreeItem().getGraphic());
if (!getTreeItem().isLeaf()&&getTreeItem().getParent()!= null)
{
setContextMenu(addMenu);
}
}
}
}
private void createTextField()
{
textField = new TextField(getString());
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();
}
}
}
Showing contextMenu to "filled with children" cells only is controlled with lines:
if (!getTreeItem().isLeaf() && getTreeItem().getParent() != null) {
setContextMenu(addMenu);
}
remove if control to popup contextMenu to all nodes/cells.