Closed thomasnield closed 8 years ago
We could always use reflection to call the method in the skin. It's not ideal, but it will work. If they ever remove the method, we can switch to another implementation but keep the interface. We can even choose different strategies in our extension function based on what's available on the skin. I'll give it a go :)
I've come up with the following implementation. Can you check if it works for you?
fun <T> TableView<T>.resizeColumnsToFitContent(resizeColumns: List<TableColumn<T, *>> = columns, maxRows: Int = 20) {
val resizer = skin.javaClass.getDeclaredMethod("resizeColumnToFitContent", TableColumn::class.java, Int::class.java)
resizer.isAccessible = true
resizeColumns.forEach { resizer.invoke(skin, it, maxRows) }
}
It supports optionally specifying only some columns, as well as the max number of rows to evaluate. Defaults are "all columns" and "20 rows".
I'm committing it so it's easier for you to test.
I like this idea a lot. However I am getting an error...
val tbl = tableview<Person> {
items = persons
column("ID",Person::id)
column("Name", Person::name)
column("Birthday", Person::birthday)
column("Age",Person::age)
}
tbl.resizeColumnsToFitContent()
java.lang.NullPointerException
at tornadofx.MenuView.resizeColumnsToFitContent(MenuTest.kt:41)
at tornadofx.MenuView.resizeColumnsToFitContent$default(MenuTest.kt:40)
at tornadofx.MenuView.<init>(MenuTest.kt:36)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
at java.lang.Class.newInstance(Class.java:442)
at tornadofx.FXKt.find(FX.kt:87)
at tornadofx.App.start(App.kt:20)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$163(LauncherImpl.java:863)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$176(PlatformImpl.java:326)
at com.sun.javafx.application.PlatformImpl.lambda$null$174(PlatformImpl.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$175(PlatformImpl.java:294)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$149(WinApplication.java:191)
at java.lang.Thread.run(Thread.java:745)
That's probably because the skin isn't initialized yet. Try wrapping it in Platform.runLater { }. If that works, I can make sure it is automatically wrapped if the skin isn't available yet. Let me know!
I commited a fix for this :)
Okay awesome, ill play with it again when I get back to my tablet.
Brilliant! Works perfectly. Thanks Edvin, that was pretty clever.
One thing that frustrated me for awhile is having a way to fit
TableView
columns to the header and cell contents. Then I found a little gem in a Stack Overflow post.I was able to come up with this class to expose that
resizeColumnToFitContent()
Then I can apply that
TableViewSkin
to theskinProperty()
, and call aresizeOp
function at any time to re-fit the columns.It would be awesome if we could apply a
resizeColumns()
extension function to theTableView
. The problem is I can't think of an efficient way at the top of my head without extendingTableView
or doing some lazy operation that stores state elsewhere. It's really too bad extension properties can't be fields.