How to remove double click editing for ListCell - java

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

Related

How to keep track of moving object (rectangle) in javafx?

I found this code snippet in a video and I'm trying to integrate it in a ridesharing app. Basically, the rectangle will represent the driver moving on the map and I want to keep track of his location to see when he reaches his destination.
import javafx.animation.AnimationTimer;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.AnchorPane;
import javafx.scene.shape.Rectangle;
import java.net.URL;
import java.util.ResourceBundle;
public class MapController implements Initializable {
private BooleanProperty wPressed = new SimpleBooleanProperty();
private BooleanProperty aPressed = new SimpleBooleanProperty();
private BooleanProperty sPressed = new SimpleBooleanProperty();
private BooleanProperty dPressed = new SimpleBooleanProperty();
private BooleanBinding keyPressed = wPressed.or(aPressed).or(sPressed).or(dPressed);
private double movementVariable = 2;
private int destinationX = 300, destinationY = 300;
#FXML
private Rectangle shape1;
#FXML
private AnchorPane scene;
#FXML
private Button buttonStartRide;
#FXML
void start(ActionEvent event) {
shape1.setVisible(true);
buttonStartRide.setOpacity(0);
shape1.setLayoutY(200);
shape1.setLayoutX(280);
}
AnimationTimer timer = new AnimationTimer() {
#Override
public void handle(long timestamp) {
if(wPressed.get()) {
shape1.setLayoutY(shape1.getLayoutY() - movementVariable);
}
if(sPressed.get()){
shape1.setLayoutY(shape1.getLayoutY() + movementVariable);
}
if(aPressed.get()){
shape1.setLayoutX(shape1.getLayoutX() - movementVariable);
}
if(dPressed.get()){
shape1.setLayoutX(shape1.getLayoutX() + movementVariable);
}
}
};
#Override
public void initialize(URL url, ResourceBundle resourceBundle) {
movementSetup();
shape1.setVisible(false);
keyPressed.addListener(((observableValue, aBoolean, t1) -> {
if(!aBoolean){
timer.start();
} else {
timer.stop();
}
}));
}
public void movementSetup(){
scene.setOnKeyPressed(e -> {
if(e.getCode() == KeyCode.W) {
wPressed.set(true);
}
if(e.getCode() == KeyCode.A) {
aPressed.set(true);
}
if(e.getCode() == KeyCode.S) {
sPressed.set(true);
}
if(e.getCode() == KeyCode.D) {
dPressed.set(true);
}
});
scene.setOnKeyReleased(e ->{
if(e.getCode() == KeyCode.W) {
wPressed.set(false);
}
if(e.getCode() == KeyCode.A) {
aPressed.set(false);
}
if(e.getCode() == KeyCode.S) {
sPressed.set(false);
}
if(e.getCode() == KeyCode.D) {
dPressed.set(false);
}
});
}
public boolean checkReachedDestination()
{
if((shape1.getLayoutX() == destinationX) && (shape1.getLayoutY() == destinationY))
{
return true;
}
return false;
}
}
I thought that I could maybe do this with a Listener for shape1, however it seems like there is no Listener defined for the type Rectangle. Any thoughts?

JavaFX - Combine two CellFactory - TextFieldTableCell.forTableColumn() and custom one

I have a TableColumn:
TableColumn<Foo, String> colStatus = new TableColumn("Status");
colStatus.setCellValueFactory(new PropertyValueFactory<>("statusElement"));
On this table I want to apply this cellFactory TextFieldTableCell.forTableColumn() which will make cell editable.
But I also want to combine this one with a custom cellFactory:
colStatus.setCellFactory(new Callback<>() {
public TableCell<Foo, String> call(TableColumn param) {
return new TableCell<>() {
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (!isEmpty()){
if(item.equals("error")){
this.setTextFill(Color.RED);
setText(item);
}else{
this.setTextFill(Color.Black);
setText(item);
}
}
}
};
}
});
This cell factory sets text color of cell, based by cell value.
But I don't know how to make the cell editable but also to customize his color, based on value.
Here is MCVE:
#Override
public void start(Stage primaryStage){
List<String> test = new ArrayList<>();
test.add("done(green)");
test.add("done(green)");
test.add("fail(red)");
test.add("done(green)");
TableView<String> tableView = new TableView<>();
tableView.setColumnResizePolicy(TableView.UNCONSTRAINED_RESIZE_POLICY);
tableView.setEditable(true);
TableColumn<String, String> col = new TableColumn<>("Column");
col.setCellValueFactory(data -> new SimpleStringProperty(data.getValue()));
col.setCellFactory(TextFieldTableCell.forTableColumn());
//I want to apply a color based by value from cell
tableView.getColumns().add(col);
tableView.setItems(FXCollections.observableArrayList(test));
primaryStage.setScene(new Scene(tableView));
primaryStage.show();
}
I finally found I can use TextFieldTableCell.forTableColumn() with customization.
Just need to override TextFieldTableCell.
private static class CustomCell extends TextFieldTableCell<String, String>{
#Override
public void updateItem(String item, boolean empty){
super.updateItem(item, empty);
if(item == null || empty) {
setText(null);
return;
}
if(!isEmpty()){
if(item.equals("error")){
this.setTextFill(Color.RED);
setText(item);
}else{
this.setTextFill(Color.BLACK);
setText(item);
}
}
}
}
I was fixed on idea that setCellFactory get as parameter a CallBack.
So I was tried a lot of ways to get a CallBack which returns a TableCell
After I saw the answer of #Sedrick.
I found I can send an lambda implementation like: setCellFactory(e -> new CustomCell()).
Thanks to #Sedrick and #kleopatra.
The key is to extend TableCell as #fabian suggested.
Main
import java.util.ArrayList;
import java.util.List;
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.scene.Scene;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.stage.Stage;
import javafx.util.Callback;
/**
*
* #author blj0011
*/
public class JavaFXTestingGround extends Application
{
/**
* #param args the command line arguments
*/
public static void main(String[] args)
{
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception
{
List<String> test = new ArrayList<>();
test.add("done(green)");
test.add("done(green)");
test.add("fail(red)");
test.add("done(green)");
TableView<String> tableView = new TableView<>();
tableView.setColumnResizePolicy(TableView.UNCONSTRAINED_RESIZE_POLICY);
tableView.setEditable(true);
TableColumn<String, String> col = new TableColumn<>("Column");
col.setCellValueFactory(data -> new SimpleStringProperty(data.getValue()));
col.setCellFactory((param) -> new CustomCellFactory());
//I want to apply a color based by value from cell
tableView.getColumns().add(col);
tableView.setItems(FXCollections.observableArrayList(test));
primaryStage.setScene(new Scene(tableView));
primaryStage.show();
}
}
CustomCellFactory
import javafx.application.Platform;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.TableCell;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.paint.Color;
import javafx.scene.text.Text;
/**
*
* #author blj0011
*/
public class CustomCellFactory<T> extends TableCell<T, String>
{
TextField textField = new TextField();
Text text = new Text();
public CustomCellFactory()
{
textField.setOnKeyPressed(keyEvent -> {
if (keyEvent.getCode() == KeyCode.ENTER) {
commitEdit(textField.getText());
}
});
}
#Override
public void commitEdit(String newValue)
{
super.commitEdit(newValue);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
}
#Override
public void startEdit()
{
super.startEdit();
if (!isEmpty()) {
setGraphic(textField);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
textField.setText(text.getText());
Platform.runLater(() -> textField.requestFocus());
}
}
#Override
public void cancelEdit()
{
super.cancelEdit();
setContentDisplay(ContentDisplay.TEXT_ONLY);
}
#Override
protected void updateItem(String item, boolean empty)
{
super.updateItem(item, empty);
if (item == null || empty) {
setText(null);
}
else {
if (item.equals("error")) {
text.setFill(Color.RED);
}
else {
text.setFill(Color.BLACK);
}
text.setText(item);
setGraphic(text);
}
}
}
Update: I found This while failing to live up to #kleopatra suggestion.
Main
import java.util.ArrayList;
import java.util.List;
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.scene.Scene;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.stage.Stage;
import javafx.util.Callback;
/**
*
* #author blj0011
*/
public class JavaFXTestingGround extends Application
{
/**
* #param args the command line arguments
*/
public static void main(String[] args)
{
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception
{
List<String> test = new ArrayList<>();
test.add("done(green)");
test.add("done(green)");
test.add("fail(red)");
test.add("done(green)");
TableView<String> tableView = new TableView<>();
tableView.setColumnResizePolicy(TableView.UNCONSTRAINED_RESIZE_POLICY);
tableView.setEditable(true);
TableColumn<String, String> col = new TableColumn<>("Column");
col.setCellValueFactory(data -> new SimpleStringProperty(data.getValue()));
col.setCellFactory(column -> EditCell.createStringEditCell());
//I want to apply a color based by value from cell
tableView.getColumns().add(col);
tableView.setItems(FXCollections.observableArrayList(test));
primaryStage.setScene(new Scene(tableView));
primaryStage.show();
}
}
EditCell
import javafx.event.Event;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.CellEditEvent;
import javafx.scene.control.TablePosition;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyEvent;
import javafx.scene.paint.Color;
import javafx.util.StringConverter;
public class EditCell<S, T> extends TableCell<S, T>
{
// Text field for editing
// TODO: allow this to be a plugable control.
private final TextField textField = new TextField();
// Converter for converting the text in the text field to the user type, and vice-versa:
private final StringConverter<T> converter;
public EditCell(StringConverter<T> converter)
{
this.converter = converter;
itemProperty().addListener((obx, oldItem, newItem) -> {
if (newItem == null) {
setText(null);
}
else {
setText(converter.toString(newItem));
}
});
setGraphic(textField);
setContentDisplay(ContentDisplay.TEXT_ONLY);
textField.setOnAction(evt -> {
commitEdit(this.converter.fromString(textField.getText()));
});
textField.focusedProperty().addListener((obs, wasFocused, isNowFocused) -> {
if (!isNowFocused) {
commitEdit(this.converter.fromString(textField.getText()));
}
});
textField.addEventFilter(KeyEvent.KEY_PRESSED, event -> {
if (null != event.getCode()) {
switch (event.getCode()) {
case ESCAPE:
textField.setText(converter.toString(getItem()));
cancelEdit();
event.consume();
break;
case RIGHT:
getTableView().getSelectionModel().selectRightCell();
event.consume();
break;
case LEFT:
getTableView().getSelectionModel().selectLeftCell();
event.consume();
break;
case UP:
getTableView().getSelectionModel().selectAboveCell();
event.consume();
break;
case DOWN:
getTableView().getSelectionModel().selectBelowCell();
event.consume();
break;
default:
break;
}
}
});
}
/**
* Convenience converter that does nothing (converts Strings to themselves
* and vice-versa...).
*/
public static final StringConverter<String> IDENTITY_CONVERTER = new StringConverter<String>()
{
#Override
public String toString(String object)
{
return object;
}
#Override
public String fromString(String string)
{
return string;
}
};
/**
* Convenience method for creating an EditCell for a String value.
*
* #param <S>
* #return
*/
public static <S> EditCell<S, String> createStringEditCell()
{
return new EditCell<>(IDENTITY_CONVERTER);
}
// set the text of the text field and display the graphic
#Override
public void startEdit()
{
super.startEdit();
textField.setText(converter.toString(getItem()));
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
textField.requestFocus();
}
// revert to text display
#Override
public void cancelEdit()
{
super.cancelEdit();
setContentDisplay(ContentDisplay.TEXT_ONLY);
}
// commits the edit. Update property if possible and revert to text display
#Override
public void commitEdit(T 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...
if (!isEditing() && !item.equals(getItem())) {
TableView<S> table = getTableView();
if (table != null) {
TableColumn<S, T> column = getTableColumn();
CellEditEvent<S, T> event = new CellEditEvent<>(table,
new TablePosition<>(table, getIndex(), column),
TableColumn.editCommitEvent(), item);
Event.fireEvent(column, event);
}
}
if (item.equals("error")) {
setTextFill(Color.RED);
}
else {
setTextFill(Color.BLACK);
}
super.commitEdit(item);
setContentDisplay(ContentDisplay.TEXT_ONLY);
}
}
import javafx.geometry.Pos;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.util.Callback;
import javafx.util.StringConverter;
class className {
private void initColumnTableValue() {
TableColumn<User, Number> columnId = new TableColumn<>("ID");
columnId.setCellFactory(getTextFieldCellFactoryId());
}
/*
* Returns the factory to a cell with a text field for editing
* but with the ability to customize cells
*/
private Callback<TableColumn<User, Number>, TableCell<User, Number>> getTextFieldCellFactoryId() {
return CustomTextFieldTableCell.<User, Number>forTableColumn(
new StringConverter<Number>() {
#Override
public String toString(Number number) {
return number == null ? "" : number.toString();
}
#Override
public Number fromString(String s) {
try {
return Integer.valueOf(s);
} catch (Exception e) {
return null;
}
}
}
);
}
}
/**
* Creates a changed factory for the production of editable cells,
* but with the ability to customize cells
*/
public class CustomTextFieldTableCell extends TextFieldTableCell<User, Number> {
public CustomTextFieldTableCell(StringConverter<Number> var0) {super(var0);}
{ setAlignment(Pos.TOP_CENTER); }
#Override
public void updateItem(Number value, boolean empty){
super.updateItem(value, empty);
if (value == null || empty)
setText("");
else {
if ((int)value % 2 == 0)
setBorder(new Border(new BorderStroke(Color.BLUE, BorderStrokeStyle.DASHED,
new CornerRadii(4), new BorderWidths(1))));
setText(value.toString());
}
}
public static <User, Number> Callback<TableColumn<User, Number>, TableCell<User, Number>> forTableColumn(StringConverter<Number> var0) {
return new Callback<TableColumn<User, Number>, TableCell<User, Number>>() {
#Override
public TableCell<User, Number> call(TableColumn<User, Number> var1) {
return (TableCell<User, Number>) new CustomTextFieldTableCell((StringConverter<java.lang.Number>) var0);
}
};
}
}

change text of treeitem when click on button

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

JavaFX 8 TreeView displays incorrect String when cell is clicked to edit

I'm using the following code from Oracle:
import java.util.Arrays;
import java.util.List;
import javafx.application.Application;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.util.Callback;
import javafx.beans.property.SimpleStringProperty;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.layout.VBox;
public class TreeViewSample extends Application {
List<Employee> employees = Arrays.<Employee>asList(
new Employee("Ethan Williams", "Sales Department"),
new Employee("Emma Jones", "Sales Department"),
new Employee("Michael Brown", "Sales Department"),
new Employee("Anna Black", "Sales Department"),
new Employee("Rodger York", "Sales Department"),
new Employee("Susan Collins", "Sales Department"),
new Employee("Mike Graham", "IT Support"),
new Employee("Judy Mayer", "IT Support"),
new Employee("Gregory Smith", "IT Support"),
new Employee("Jacob Smith", "Accounts Department"),
new Employee("Isabella Johnson", "Accounts Department"));
TreeItem<String> rootNode =
new TreeItem<String>("MyCompany Human Resources");
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(Stage stage) {
rootNode.setExpanded(true);
for (Employee employee : employees) {
TreeItem<String> empLeaf = new TreeItem<String>(employee.getName());
boolean found = false;
for (TreeItem<String> depNode : rootNode.getChildren()) {
if (depNode.getValue().contentEquals(employee.getDepartment())){
depNode.getChildren().add(empLeaf);
found = true;
break;
}
}
if (!found) {
TreeItem depNode = new TreeItem(employee.getDepartment());
rootNode.getChildren().add(depNode);
depNode.getChildren().add(empLeaf);
}
}
stage.setTitle("Tree View Sample");
VBox box = new VBox();
final Scene scene = new Scene(box, 400, 300);
scene.setFill(Color.LIGHTGRAY);
TreeView<String> treeView = new TreeView<String>(rootNode);
treeView.setEditable(true);
treeView.setCellFactory(new Callback<TreeView<String>,TreeCell<String>>(){
#Override
public TreeCell<String> call(TreeView<String> p) {
return new TextFieldTreeCellImpl();
}
});
box.getChildren().add(treeView);
stage.setScene(scene);
stage.show();
}
private final class TextFieldTreeCellImpl extends TreeCell<String> {
private TextField textField;
private ContextMenu addMenu = new ContextMenu();
public TextFieldTreeCellImpl() {
MenuItem addMenuItem = new MenuItem("Add Employee");
addMenu.getItems().add(addMenuItem);
addMenuItem.setOnAction(new EventHandler() {
public void handle(Event t) {
TreeItem newEmployee =
new TreeItem<String>("New Employee");
getTreeItem().getChildren().add(newEmployee);
}
});
}
#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();
}
}
public static class Employee {
private final SimpleStringProperty name;
private final SimpleStringProperty department;
private Employee(String name, String department) {
this.name = new SimpleStringProperty(name);
this.department = new SimpleStringProperty(department);
}
public String getName() {
return name.get();
}
public void setName(String fName) {
name.set(fName);
}
public String getDepartment() {
return department.get();
}
public void setDepartment(String fName) {
department.set(fName);
}
}
}
This code produces a GUI with a very basic, editable TreeView. However, when clicking around the cells that populate the tree, eventually, the text fields used for editing will begin to display incorrect information (information that is contained within the tree, but that is not represented by the cell being edited). I do not understand why this is happening, and I haven't found any reference of this happening anywhere on Google or elsewhere on StackOverflow. If anyone could help me understand why this is occuring, I'd be very happy.
Thanks!
I checked your application and I have found only one weird thing. When you create the edit textfield once, the unsaved information will be visible in that textfield later.
This modification will solve it:
# Override
public void cancelEdit() {
super.cancelEdit();
this.setText(this.getItem());
this.textField.setText(this.getItem());
this.setGraphic(this.getTreeItem().getGraphic());
}

JavaFx TalbleView Scroll Down/Up issue

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

Categories