Javafx : TreeTableView refresh after updateItem - javafx

I have a TreeTableView and I have a custom TreeTableCell in which I override the updateItem method in order to render my cells(set disabled or enabled) depending on some condition. The problem is if I do some scroll, the table doesn't refresh, and as you can see on the attached image some cells become disabled even if they don't satisfy the condition. After heavy scrolling all cells become disabled(grayed out). I tried two things to solve the problem:
add some event listeners to refresh the table "manually" like:
treeTable.addEventFilter(ScrollEvent.ANY, event -> treeTable.refresh());
the rendering problem disappears, but if I do a little heavier scrolling, it becomes so laggy like if the application runs on 10-15 fps because the refreshing event triggers too frequently.
The other thing that I have tried is to make a timer(java.util.Timer) to trigger the refresh for example in only every 50 milliseconds, while scrolling. Then the lag disappears but there is a delay on rendering the cells, so you can observe the change of the cell color from gray to white.
If i choose smaller time interval it becomes laggy, and i could't find a balance between the lag and delay, and I also think both of my solutions are just workarounds, not real solutions for the problem.
Do you have any other idea to solve this problem?
The attached image : TableCells
#Override
public void updateItem(Boolean item, boolean empty) {
MyCustomRow row = getTreeTableRow().getItem();
if (row != null && row.isCondition()) {
editableProperty().set(false);
super.updateItem(item, empty);
}
}

Your updateItem method must:
Always call super.updateItem(), and
Update the state of the cell so that it is consistent for any possible values of item and empty
(see the Cell documentation.)
In your code, if the cell is used for a row where isCondition returns true, and then subsequently reused for a row where isCondition returns false, you don't revert the editable property to true. (So, eventually, all cells can be changed to non-editable, but can never be changed back to editable.)
You should do something like
#Override
public void updateItem(Boolean item, boolean empty) {
super.updateItem(item, empty);
MyCustomRow row = getTreeTableRow().getItem();
if (row != null && row.isCondition()) {
setEditable(false);
} else {
setEditable(true);
}
}

Related

JavaFX DatePicker disable future dates

I want to allow user to select date from DateChooser upto current date. How can I disable future dates in DatePicker of JavaFX?
You should set a DayCellFactory. This allows you to control essentially all style elements of the datepicker, including whether or not dates after a specified date are greyed out.
datePicker.setDayCellFactory(param -> new DateCell() {
#Override
public void updateItem(LocalDate date, boolean empty) {
super.updateItem(date, empty);
setDisable(empty || date.compareTo(LocalDate.now()) > 0 );
}
});
PS: any node that has cells in it (TableView, DatePicker, ListView etc) can have its updateItem method overridden, which allows you to configure the style of that cell based on its data. Use with caution, and always make sure you include the super.updateItem() that comes with it.

JavaFX MenuItem display bug

My first question here so I hope i can describe my problem correct.
What im facing right now is that i want to display a contextmenu for some entries of a JFXTreeTableView. Therefore i created a new cellFactory called "ProjectTreeItemWithContextMenuTreeTableFactory" which handles the creation of the contextMenu based on mouseReleasedEvent and displaying it.
Due to i dont have 10 reputations i cant post images but as an example what isnt working i try to describe it. If i open the contextmenu it will get displayed at the correct position. When hovering over a menu entry the menuItems will get displayed, but not rendered right next to the menu.
There can be some times a huge gab between the menuItems and the menu whic hwas hovered....
What i noticed is, that this problem will only occur when hovering for the first time over the menu. If hovering for the second time over the menu while the contextMenu stays open, everything will get displayed correct.
private class TreeTableCallback extends TreeTableCell<T, ProjectTreeParentItemFX> {
#Override
protected void updateItem(ProjectTreeParentItemFX item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
setText(null);
setGraphic(null);
setContextMenu(null);
} else {
this.setOnMouseReleased(evt -> handleMouseReleased(evt, item));
setText(item.getDisplayText());
}
}
Adding menus and menuItems to the contextMenu and showing the menu.
private void handleMouseReleased(MouseEvent evt, ProjectTreeParentItemFX item) {
if (evt.getButton().equals(MouseButton.SECONDARY)) {
setContentOfContextMenuBasedOnType(item);
contextMenu.show(getTreeTableRow(), evt.getScreenX(), evt.getScreenY());
}
}

Change css for a new row added in TableView Javafx

I'm sorry for mistake I'm french.
So I have a tableView empty. I have a button "Add" when on click added row in a tableView. And when I select an row in my tableView, a new button "Cancel" show.
And when I click on a button "Cancel", the row's css change on my row selected (added a class css ".cancel").
The problem is that I click on button "Cancel", and after I click in the button "Add", the css ".cancel" is applicated at an other row while I don't clicked in the button "Add".
I think that there is a problem in index row.
In my method initialize :
articleTable.setRowFactory(param -> new TableRow<LigneTicket>() {
#Override
protected void updateItem(LigneTicket paramT, boolean empty) {
super.updateItem(paramT, empty);
if (!isEmpty() && paramT != null && paramT.getArticle().isArticleCanceled()) {
getStyleClass().add("cancel");
}
}
});
my code on button "Cancel" :
public void cancelLigneTicket() {
int indexSelected = articleTable.getSelectionModel().getSelectedIndex();
articleTable.getItems().get(indexSelected).getArticle().setArticleAnnuler(true);
articleTable.getSelectionModel().clearSelection();
List<LigneTicket> items = new ArrayList<>(articleTable.getItems());
articleTable.getItems().setAll(items);
buttonAnnulArt.setVisible(false);
Help !!
Thanks.
TableRows are used to display the table items. That doesn't mean however, that it will be used with only one item.
This can result in the following sequence of events for a row r:
The item of r is updated to a canceled item and thus the cancel CSS class is added.
The item of r is updated to a non-canceled item, but the cancel CSS class is not removed.
You need to remove the class again. Furthermore with your code the style class could be added multiple times leading to unnecessary memory consumption.
boolean canceled = !empty && paramT != null && paramT.getArticle().isArticleCanceled());
if (canceled) {
if (!getStyleClass().contains("cancel"))
getStyleClass().add("cancel");
} else {
getStyleClass().remove("cancel");
}
or using PseudoClass:
private static final PseudoClass CANCELED = PseudoClass.getPseudoClass("cancel");
...
pseudoClassStateChanged(CANCELED, !empty && paramT != null && paramT.getArticle().isArticleCanceled());
Furthermore you should prefer the TableView.refresh (available in JavaFX >= 8u60) method to refresh the cell items instead of copying the list and setting the items.

JavaFX, change css tablecell on sort

I have to change the styleclass of a TableCell in function of the data displayed, for example: if the value of a cell is the same in two contiguous rows, the cell has to be highlighted (i.e.: background red). This must work both adding data to the table and sorting by any column.
To do so, on sorting, I added a listener to tableview.getSortOrder() and in its onChange method the logic to do what I described above. By example:
public void onChanged(ListChangeListener.Change<? extends TableColumn> change) {
if (change.getList().size() > 0) {
Platform.runLater(new Runnable() {
#Override
public void run() {
/* set some css on tableview cells */
}
});
}
}
The problem is that doing so css changes are applied on the next refresh of the table not immediately. My suspects are on doing this inside Platform.runLater but I need it to have the data sorted as they should be, before changing styles.
Did I do anything wrong? Does exist a better way to do what I described?
You could do that if you have a specific css file for it and add it.
final String css = getClass.getResource("the_css.css").toExternalForm();
and add this in the Platform.runLater:
scene.getStylesheet.add(css);
remove if necessary with:
scene.getStylesheet.remove(css);
Not exactly sure if this does the trick, but it should change the background color right away and not after a refresh. i hope it's helping you in the right direction.

Grid scrolling after render ZK

I'm trying to scroll down to the bottom of a grid, after the model was setted.
1) I set the model:
myGrid.setModel(new ListModelList<Object>(myList));
2) I override the row renderer
myGrid.setRowRenderer(new RowRenderer<Object>() {
#Override
public synchronized void render(Row row,final Object data, int index) throws Exception {
row.setStyle("commonCellPadding");
.
.
.
row.appendChild(htmlMessage);
}
});
3) Finally if the list used to set the model is too big (the grid in the .zul has fixed height) i want to show the last results (the more recents in this case).
I need to scroll down automatically after the render. How can i do this?
Things i had try
a) Calling a javascript function after the render, this doesn't work due to the fact that the gridEle.scrollHeight attribute returns the fixed height of the grid setted in the zul (or 0 if not) and not the grid's height after the model was setted.
myGrid.addEventListener(ZulEvents.ON_AFTER_RENDER, new EventListener<Event>() {
public void onEvent(Event event) throws Exception
{
Clients.evalJavaScript("var gridEle = document.getElementById('"+myGrid.getUuid()+"-body"+"'); gridEle.scrollTop = gridEle.scrollHeight;alert(gridEle.scrollHeight);");
}
});
Why don't you sort the myList descending at first to make the last row become the first one instead to control the scroll bar?
In my opinion, it would be more easy and matching the users experience.
Just call Clients.scrollIntoView(rows.getLastChild()); after you have set the model and row renderer (provided rows is Rows component id and is already auto wired into your controller). See the live demo on zkfiddle here and source
UPDATE: Clients.scrollIntoView(Component) wouldn't work if you are using Render-On-Demand feature because naturally if the row that you want to scroll to wouldn't have been loaded on initial page load.

Resources