Closed toplinuxsir closed 7 years ago
In JavaFX, you don't refresh the table, you refresh the data that your table is bound to. Worst case you can also reassign the items
property of the TableView, but under must circumstances you would simply call myData.setAll(newData)
to change the data and consequently update the TableView. You omitted the items assignment in your example, but consider something like this:
val myData = FXCollections.observableArrayList<KingdeeOrderEntry>()
You can now bind this data to your TableView:
tableview(myData) {
...
}
Notice that you no longer need to specify the type for the TableView, since it can be inferred from the data.
Lastly, to update that data:
button("Refresh").action {
myData.setAll(newDataHere)
}
If you are getting your data from a remoting call for example, you should look into asyncItems:
myData.asyncItems { someCallThatReturnsItems() }
The refreshable
statement is for use with the Workspace, so unless your app is Workspace based you shouldn't use that.
Another optimization hint: You can get away with a single style
block in your cellFormat
functions if you change the logic around a little:
style {
backgroundColor += if (rowItem.authId == null) Color.RED else Color.GREEN
}
Thanks 1
Hello, how can I add items one by one? I have a loop(getting lines from console app) and want to add info to tableview after each iteration.
We usually bind the TableView to a backing ObservableList. Then, your loop can update the ObservableList using add() and changes will be reflected in the TableView (because of the binding).
The class MyView in the link below has a studentList variable bound to the table. You would call studentList.add(item) to add additional students.
https://courses.bekwam.net/~walkerro/bkcourse_tornadofx_style_tableview.html
Good luck!
fun startScanner() {
val foundFoo = FXCollections.observableArrayList<MyObject>()
val process = Runtime.getRuntime().exec(SCANNER_PATH)
while (process.isAlive) {
val source = process.inputStream.bufferedReader().readLine()
if (source != null ) {
val line = source.split(" ")
ScanView().myObservableList.add(MyObject(line[0], line[1], line[2], line[3], line[4], line[5], line[6]))
/*foundFoo.add(MyObject(line[0], line[1], line[2], line[3], line[4], line[5], line[6]))
println(findFoo.size)
ScanView().myObservableList.setAll(foundFoo)*/
}
}
}
I tried some ways, but it didn't refresh (I save all tryings in comments)
It looks like you have two ScanView() instances and you're not updating the one visible on the screen. You're updating a newly-created ScanView which is never displayed. With TornadoFX dependency injection, you'll need to call find
Once you get your data on the screen, you'll want to use Tasks to keep the application lively during a long scan operation. Check out this article which also adds a cancel example.
https://courses.bekwam.net/public_tutorials/bkcourse_tornadofx_cancelapp.html
If you need more help like this, I recommend joining the TornadoFX channel on the Kotlin Slack at kotlinlang.slack.com.
Thanks! find method made magic
@edvin It's not working now for some reason
class AdminView : View() {
val controller : AdminController by inject()
var users = mutableListOf<UserModel>().observable()
override val root = vbox {
tableview(users) {
column("Id", UserModel::id.getter)
column("Login", UserModel::login.getter)
column("Password", UserModel::password.getter)
column("Admin", UserModel::admin.getter)
}
button("refresh").action {
users.asyncItems { controller.getUsers() }
}
}
override fun onDock() {
super.onDock()
users.asyncItems { controller.getUsers() }
}
}
class UserModel : ViewModel {
var id: SimpleIntegerProperty
var login: SimpleStringProperty
var password: SimpleStringProperty
var admin: SimpleBooleanProperty
constructor() : super() {
this.id = bind { SimpleIntegerProperty() }
this.login = bind { SimpleStringProperty() }
this.password = bind { SimpleStringProperty() }
this.admin = bind { SimpleBooleanProperty() }
}
constructor(user: User) : super() {
this.id = bind { SimpleIntegerProperty(user.id) }
this.login = bind { SimpleStringProperty(user.login) }
this.password = bind { SimpleStringProperty(user.password) }
this.admin = bind { SimpleBooleanProperty(user.admin) }
}
}
Table updates only after second docking and refresh
button does not affect anything
You should not use a ViewModel in the table like this, and you should absolutely not reference the getters, but rather the observable properties. Your use class should look like:
class User {
val idProperty = SimpleIntegerProperty()
var id by idProperty
// Same for the rest of the properties
}
Then you should bind against the property in the tableview, like this:
column("Id", User::idProperty)
Define the user list like this:
val users = SortedFilteredList<User>()
Create an onRefresh
callback and put your refresh code there, and only there:
override fun onRefresh() {
users.asyncItems { controller.getUsers() }
}
Then call this function from onDock
and your Button action
.
Lastly, don't highjack other threads, create a new if you have an issue, and post a complete runnable sample :)
Edvin
Example: I have a tableview :
I found a memeber function "refreshableWhen " for tableview , Can I via " refreshableWhen " to refresh the tableview for loose coupling? Thanks !