JavaFX Binding String to TreeCell Factory Properly - java

I'm getting an issue, where when I expand and unexpand a tree cell. The text I binded to doesn't ever go away.. What could be the cause of this?
This is what I get
Here is my code
treeView.setCellFactory(t -> {
return new TreeCell<Entry>() {
#Override
protected void updateItem(Entry entry, boolean empty) {
super.updateItem(entry, empty);
if (entry != null) {
if (empty) {
setText(null);
setGraphic(null);
} else {
if (entry.getImage() != null) {
Image image = FXUtils.toFXImage(entry.getImage());
setGraphic(new ImageView(image));
} else {
setGraphic(null);
}
textProperty().bind(entry.nameProperty());
}
}
}
};
});

If a cell is empty, the item is also null. However all your logic is only executed, if (entry != null), i.e. never, if the cell is empty or the item is null. Furthermore this should fail, even if you fix this error, since you never unbind the textProperty, but it could be set for empty cells. Change your updateItem method to something like this:
#Override
protected void updateItem(Entry entry, boolean empty) {
super.updateItem(entry, empty);
textProperty().unbind();
if (empty || entry == null) {
setText(null);
setGraphic(null);
} else {
if (entry.getImage() != null) {
Image image = FXUtils.toFXImage(entry.getImage());
setGraphic(new ImageView(image));
} else {
setGraphic(null);
}
textProperty().bind(entry.nameProperty());
}
}

Related

Is this a Bug in my code or a problem with cellfactory

todoitemsListview.setCellFactory(new Callback<ListView<ToDoItems>, ListCell<ToDoItems>>() {
#Override
public ListCell<ToDoItems> call(ListView<ToDoItems> toDoItemsListView) {
ListCell<ToDoItems> cell= new ListCell<ToDoItems>(){
#Override
protected void updateItem(ToDoItems items, boolean empty) {
super.updateItem(items, empty);
if(empty){
setText(null);
}else {
setText(items.getItemName());
if (items.getDeadline().equals(LocalDate.now())){
System.out.println(items.getDeadline().toString());
System.out.println(items.getItemName());
setTextFill(Color.RED);
}else if (items.getDeadline().equals(LocalDate.now().plusDays(1))){
System.out.println(items.getDeadline().toString());
System.out.println(items.getItemName());
setTextFill(Color.BLUE);
}else if (items.getDeadline().equals(LocalDate.now().plusDays(2))){
System.out.println(items.getDeadline().toString());
System.out.println(items.getItemName());
setTextFill(Color.GREEN);
}else if(items.getDeadline().isBefore(LocalDate.now())){
System.out.println(items.getDeadline().toString());
System.out.println(items.getItemName());
setTextFill(Color.GREY);
}
}
}
};
return cell;
}
});
I used a cellfactory in listview to set text color to different values based on their due date. But when i add new items to the list, items which doesn't satisfy the if - else conditions is also highlighted.
This is part of a basic ToDo application based on a ObservabelList , Where ToDoItems class has three attributes, itemName,ItemDesription,Deadline.
Cells in a ListView are reused when needed. So in your case, you have set a specific cell with a red fill, but when that same cell is reused for a different ToDoItems instance (because you scrolled down or added a new item in the list), and that new ToDoItems instance doesn't fullfil any of your conditions that change the fill color, the cell is gonna keep its previous fill color incorrectly.
What you need to do is make sure you fall back to a default color if none of the conditions in your example are met:
todoitemsListview.setCellFactory(new Callback<ListView<ToDoItems>, ListCell<ToDoItems>>() {
#Override
public ListCell<ToDoItems> call(ListView<ToDoItems> toDoItemsListView) {
ListCell<ToDoItems> cell = new ListCell<ToDoItems>() {
#Override
protected void updateItem(ToDoItems items, boolean empty) {
super.updateItem(items, empty);
if (empty) {
setText(null);
setTextFill(Color.BLACK);
} else {
setText(items.getItemName());
if (items.getDeadline().equals(LocalDate.now())) {
System.out.println(items.getDeadline().toString());
System.out.println(items.getItemName());
setTextFill(Color.RED);
} else if (items.getDeadline().equals(LocalDate.now().plusDays(1))) {
System.out.println(items.getDeadline().toString());
System.out.println(items.getItemName());
setTextFill(Color.BLUE);
} else if (items.getDeadline().equals(LocalDate.now().plusDays(2))) {
System.out.println(items.getDeadline().toString());
System.out.println(items.getItemName());
setTextFill(Color.GREEN);
} else if (items.getDeadline().isBefore(LocalDate.now())) {
System.out.println(items.getDeadline().toString());
System.out.println(items.getItemName());
setTextFill(Color.GREY);
} else {
setTextFill(Color.BLACK);
}
}
}
};
return cell;
}
});

Click event on ImageView inside TableCell in JavaFX

I have a JavaFX TableView populated with many TableColumns, one of which is matImageColumn. The code for it looks like:
matImageColumn.setCellFactory(new Callback<TableColumn<CustomObject, ImageView>, TableCell<CustomObject, ImageView>>() {
#Override
public TableCell call(final TableColumn<CustomObject, ImageView> param) {
final TableCell<CustomObject, ImageView> cell = new TableCell<CustomObject, ImageView>() {
ImageView img = new ImageView();
#Override
public void updateItem(ImageView item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setGraphic(null);
setText(null);
} else {
CustomObject co = getTableView().getItems().get(getIndex());
img = co.getImageViewOfMat();
setGraphic(img);
setText(null);
}
}
};
return cell;
}
});
Now as it is, I am looking to include a click event on my imageview but I am clueless from where to start.Can you show me possible solutions to this issue? Thanks in advance.

Not able to get javafx Listview variable height of rows

view.setCellFactory(lst ->
new ListCell<AnchorPane>() {
int k=1;
#Override
protected void updateItem(AnchorPane item,boolean empty) {
super.updateItem(item, empty);
if (empty) {
setPrefHeight(0.0);
setGraphic(null);
} else {
if(k == 1){
setPrefHeight(100.00);
k++;
}
else{
setPrefHeight(10.00);
}
setGraphic(item);
}
}
});
Setting different height of row by overriding the update Item and passing anchor pane but not getting different height for the rows.

How to get row value inside updateItem() of CellFactory

ageColumn.setCellFactory(param -> new TableCell<Person, String>(){
#Override
protected void updateItem(String item, boolean empty) {
param.getCellFactory().
super.updateItem(item, empty);
setText(empty ? null : String.valueOf(item));
if(person.getName.equals("MATEUS")) {
setStyle("-fx-background-color: red;");
}
}
});
How to get this "Person" which is the row value from the Table? I can only get the value from the cell, but not the entire object.
You can do
Person person = getTableView().getItems().get(getIndex());
You can also do
Person person = (Person) getTableRow().getItem();
but this is less desirable (in my opinion) because getTableRow() returns a raw type, and consequently it requires the unchecked downcast.
Obviously either of these only works if empty is false, so they should be inside a check for that:
ageColumn.setCellFactory(param -> new TableCell<Person, String>(){
#Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
setStyle("");
} else {
setText(item);
Person person = getTableView().getItems().get(getIndex());
if(person.getName.equals("MATEUS")) {
setStyle("-fx-background-color: red;");
} else {
setStyle("");
}
}
}
});

Stop multiple ListCell Context Menus from Showing

I made a Custom ListView Cell so i can add a Context Menu but it keeps opening multiple context menus when you click more than once and the old ones just raise Exceptions when used.
Here is my SongCell class
public SongCell(ListView<Song> list, Playlist playlist) {
setAlignment(Pos.CENTER_LEFT);
ContextMenu listContextMenu = new ContextMenu();
MenuItem removeItem = new MenuItem("Remove");
MenuItem editID3Item = new MenuItem("Edit ID3");
MenuItem playNextItem = new MenuItem("Play Next");
removeItem.setOnAction((ActionEvent event) -> {
list.getItems().remove(getIndex());
});
editID3Item.setOnAction((ActionEvent event) -> {
Optional<Pair<String, String>> show = new FXID3Edit(getItem()).show();
});
playNextItem.setOnAction((ActionEvent event) -> {
Song song = getItem();
list.getItems().remove(song);
playlist.addSongRequest(new SongRequest(song, SongRequest.type.NEXT));
});
listContextMenu.getItems().add(removeItem);
listContextMenu.getItems().add(playNextItem);
listContextMenu.getItems().add(editID3Item);
setOnMousePressed(event -> {
if (event.getButton().equals(MouseButton.SECONDARY)) {
if (getItem() != null) {
if (getItem().equals(playlist.getSong())) {
playNextItem.setDisable(true);
removeItem.setDisable(true);
} else {
playNextItem.setDisable(false);
removeItem.setDisable(false);
}
listContextMenu.show(list, event.getScreenX(), event.getScreenY());
}
}
if (event.getButton().equals(MouseButton.PRIMARY) && event.getClickCount() == 2) {
playlist.setIndex(this.getIndex());
playlist.play();
}
event.consume();
});
}
#Override
protected void updateItem(Song item, boolean empty) {
super.updateItem(item, empty);
if (!empty && item != null) {
this.setText(item.toString());
} else {
this.setText("");
}
}
I also greatly appreciate help on my Coding Style
Instead of registering a mouse listener to show the context menu, use the built-in setContextMenu(...) property. I.e.:
public SongCell(ListView<Song> list, Playlist playlist) {
// ...
setOnMousePressed(event -> {
if (event.getButton().equals(MouseButton.PRIMARY) && event.getClickCount() == 2) {
playlist.setIndex(this.getIndex());
playlist.play();
}
event.consume();
});
}
#Override
public void updateItem(Song item, boolean empty) {
super.updateItem(item, empty);
if (!empty && item != null) {
this.setText(item.toString());
this.setContextMenu(listContextMenu);
} else {
this.setText("");
this.setContextMenu(null);
}
}

Categories