New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
8325154: resizeColumnToFitContent is slower than it needs to be #1358
Conversation
👋 Welcome back rlichten! A progress list of the required criteria for merging this PR into |
modules/javafx.controls/src/main/java/javafx/scene/control/skin/TableColumnHeader.java
Show resolved
Hide resolved
@andy-goryachev-oracle Can you review this? /reviewers 2 |
@kevinrushforth |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see it working right in macOS 14.2.1, by double-clicking on the column divider in the table header.
Question to @effad : could you provide the measurements for this fix (before/after) please?
A side comment: the default implementation of resizeColumnToFitContent() is to iterate over all the rows, and I think this is not right. The UI locks up if the table has, let's say, 10,000,000 rows. I think in this case it should instead pick a reasonable limited range (maybe a max 1000 rows or so) of rows based on what's currently visible, so as not to lock up the UI. This might be a separate improvement.
Applying the patch improves performance (on my Threadripper 2950X)from: so the speedup is quite remarkable and will probably be even better, if I follow @Maran23 advise to also pull
I agree. However, in order to "not break things" we would have to introduce an API to users to be able to control the number of rows they want to be taken into account. Definitely a separate improvement. |
I agree as well. This is on my todo list for quite a while. I will review this PR soon as well. |
I think the UI "breaking itself" is much worse than us changing the (buggy) behavior. The user gains very little if the UI locks up for several seconds (or minutes) trying to size every row. At the same time the user might simply double click on the header again (or better, just resize the offending column like they used to do since time immemorial) once a wide cell comes into view. Basically, I don't think the new API is required in this particular case; I think it's a bug and it should either size the visible rows or (visible + some margin). Of course, there is one more operation which guarantees a lock up with large models - sorting. There is no easy solution for sorting, and that's where we might need new APIs. And it is a totally separate issue. |
Here is my jtable autofit column that uses sampling to avoid processing all rows: |
Mailing list message from John Hendrikx on openjfx-dev: Hi, just wanted to add my 2 cents, In my opinion, no operation in List/Table/TreeTable should be doing such So, I think that by default it should work on *visible* cells only, and As I think there are wildly different requirements for each view, I - Fixed size I don't think there will be a one size fits all, so I think --John On 05/02/2024 10:48, Marius Hanl wrote: |
I don't agree. Our production application usually loads 200 rows and lets the user load as many more rows as they see fit. It also provides a "fit all columns" function which will fit all columns of the table. So maybe we should:
|
Let's create an RFE. |
At first I had only thought about a simple "setColumnFitSamplSize(int sampleSize)" method. However, @hjohn s suggestion of a strategy pattern seems convincing to me: It allows the client to specify how the required column width is calculated. I'm not quite sure how to approach this however. If we have a "ColumnFitStrategy" interface/baseclass with just a simple "calculateColumnWidth(int column)" this would not help clients since they don't have access to a lot of the stuff that's happening inside resizeColumnToFitContent. |
The discussion about a "bigger" solution aside I think the PR is still of value to improve performance, so I look forward to your review. |
I've filed https://bugs.openjdk.org/browse/JDK-8325390 to prevent this PR from getting too much clutter. I hope this is the right approach for an RFE ... |
for (int row = 0; row < rows; row++) { | ||
tableRow.updateIndex(row); | ||
|
||
cell.updateTableColumn(tc); | ||
cell.updateTableView(tv); | ||
cell.updateTableRow(tableRow); | ||
cell.updateIndex(row); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we could also check if we need/can call tableRow.applyCss();
just only one time (below) (e.g. at first?),
May works and improve performance, or may not work
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That doesn't work unfortunately. I tried this:
boolean tableRowHasCss = false;
for (int row = 0; row < rows; row++) {
tableRow.updateIndex(row);
cell.updateIndex(row);
if ((cell.getText() != null && !cell.getText().isEmpty()) || cell.getGraphic() != null) {
if (!tableRowHasCss) {
tableRow.applyCss();
tableRowHasCss = true;
}
maxWidth = Math.max(maxWidth, cell.prefWidth(-1));
}
}
but if you have a table with this css:
.oddbig .table-row-cell:odd{
-fx-font-size: 36;
}
Then only the css of the first row will be taken into account, i.e. the column wont size correctly.
I've recorded a little video of the effect at https://youtu.be/-p0pv-i4K2s
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for checking!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me.
Checking updateTableColumn
and updateTableView
, I can see that those operation will clean up and register a lot of properties and listener, so it is a good thing to do that just once (since we never change the column or table inbetween).
@effad This change now passes all automated pre-integration checks. ℹ️ This project also has non-automated pre-integration requirements. Please see the file CONTRIBUTING.md for details. After integration, the commit message for the final commit will be:
You can use pull request commands such as /summary, /contributor and /issue to adjust it as needed. At the time when this comment was updated there had been 7 new commits pushed to the
Please see this link for an up-to-date comparison between the source branch of this pull request and the As you do not have Committer status in this project an existing Committer must agree to sponsor your change. Possible candidates are the reviewers of this PR (@andy-goryachev-oracle, @Maran23) but any other Committer may sponsor as well. ➡️ To flag this PR as ready for integration with the above commit message, type |
thank you for filing an RFE, @effad |
/integrate |
/sponsor |
Going to push as commit e2f42c5.
Your commit was automatically rebased without conflicts. |
@andy-goryachev-oracle @effad Pushed as commit e2f42c5. 💡 You may see a message that your pull request was closed with unmerged commits. This can be safely ignored. |
The PR simply moves column and view-updates outside the loop. Since the column or view never changes within the for-loop it is not necessary to call these again and again.
Progress
Issue
Reviewers
Reviewing
Using
git
Checkout this PR locally:
$ git fetch https://git.openjdk.org/jfx.git pull/1358/head:pull/1358
$ git checkout pull/1358
Update a local copy of the PR:
$ git checkout pull/1358
$ git pull https://git.openjdk.org/jfx.git pull/1358/head
Using Skara CLI tools
Checkout this PR locally:
$ git pr checkout 1358
View PR using the GUI difftool:
$ git pr show -t 1358
Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jfx/pull/1358.diff
Webrev
Link to Webrev Comment