Views
2 weeks ago

tornadofx-guide

EventBus Query

EventBus Query Parameters In Events Above you saw a signal used to ask for data, and an event returned with that data. The signal could just as well contain query parameters. For example, it could be used to ask for a specific customer. Imagine these events: class CustomerQuery(val id: Int) : FXEvent(false) class CustomerEvent(val customer: Customer) : FXEvent() Using the same procedure as above, we can now signal our need for a specific Customer , but we now need to be more careful with the data we get back. If our UI allows for multiple customers to be edited at once, we need to make sure that we only apply data for the customer we asked for. This is quite easily accounted for though: class CustomerEditor(val customerId: Int) : View() { val model : CustomerModel override val root = form { fieldset("Customer data") { field("Name") { textfield(model.name) } // More fields and buttons here } } } init { subscribe { if (it.customer.id == customerId) model.item = it.customer } fire(CustomerQuery(customerId)) } The UI is created before the interesting bit happens in the init function. First, we subscribe to CustomerEvent s, but we make sure to only act once we retrieve the customer we were asking for. If the customerId matches, we assign the customer to the item property of our ItemViewModel , and the UI is updated. A nice side effect of this is that our customer object will be updated whenever the system emits new data for this customer, no matter who asked for them. Events and Threading 220

EventBus When you create a subclass of FXEvent , you dictate the value of the runOn property. It is ApplicationThread by default, meaning that the subscriber will receive the event on the JavaFX Application Thread. This is useful for events coming from and going to other UI components, as well as backend services sending data to the UI. If you want to signal something to a backend service, one which is likely to perform heavy, long-running work, you should set runOn to BackgroundThread , making sure the subscriber will operate off of the UI thread. The subscriber now no longer needs to make sure that it is off of the UI thread, so you remove a lot of thread-related house keeping calls. Used correctly this is convenient and powerful. Used incorrectly, you will have a non responsive UI. Make sure you understand this completely before playing with events, or always wrap long running tasks in runAsync {} . Scopes The event bus emits messages across all scopes by default. If you want to limit signals to a certain scope, you can supply the second parameter to the FXEvent constructor. This will make sure that only subscribers from the given scope will receive your event. class CustomerListRequest(scope: Scope) : FXEvent(BackgroundThread, scope) The CustomerListRequest is not an object anymore since it needs to contain the scope parameter. You would now fire this event from any UI Component like this: button("Load customers").action { } fire(CustomerListRequest(scope)) The scope parameter from your UIComponent is passed into the CustomerListRequest . When customer data comes back, the framework takes care of discriminating on scope and only apply the results if they are meant for you. You do not need to mention the scope to the subscribe function call, as the framework will associate your subscription with the scope your are in at the time you create the subscription. subscribe { event -> } items.setAll(event.customers) Invalidation of Event Subscribers 221

GUIDE
GUIDE
GUIDE
Guide
Guide
GUIDE
guide
guide
Guide
Guide
GUIDE
GUIDE
GUIDE
Guide
Guide
Guide
GUIDE TO
GUIDE
GUIDE
GUIDE