Closed radicaled closed 8 years ago
Thanks for reporting this! I had missed the ButtonBar builder, so I'll add that right away. To solve your problem with using builders inside an object that is not a Pane, I propose adding a small function called children
that will change the scope so that builders created inside will be added to a designated list of nodes. Then your example can be written like this:
class NewDocumentDialog : Fragment() {
override val root = VBox()
init {
title = "New Document"
with(root) {
label("New Document")
textfield { promptText = "New Document Name" }
add(ButtonBar().apply {
prefHeight = 20.0
prefWidth = 410.0
// Append any builders created inside to `ButtonBar.buttons`
children(buttons) {
button("Create").setOnAction { createDocument() }
button("Cancel").setOnAction { close() }
}
})
}
}
fun createDocument() {
}
fun close() {
this.closeModal()
}
}
Also note the setOnAction
function that reduces boilerplate when adding action listeners to buttons.
Does this seem reasonable to you?
I've commited the children
function above as well as the buttonbar
builder, so your example can now be written like this:
with(root) {
label("New Document")
textfield { promptText = "New Document Name" }
buttonbar {
prefHeight = 20.0
prefWidth = 410.0
children(buttons) {
button("Create").setOnAction { createDocument() }
button("Cancel").setOnAction { close() }
}
}
}
@thomasnield The children
function should probably be mentioned in the guide, I'll add it to the Wiki now :)
I also added special support for adding buttons to a buttonbar, so the above example is now down to:
buttonbar {
prefHeight = 20.0
prefWidth = 410.0
button("Create").setOnAction { createDocument() }
button("Cancel").setOnAction { close() }
}
I have explained this further with examples and more info in the Wiki:
@edvin noted!
I noticed the children()
function operates in Pane scope (which makes sense as all the builders are made for Pane). What would happen if you added something it wasn't expecting? For example:
with(root) {
label("New Document")
textfield { promptText = "New Document Name" }
buttonbar {
prefHeight = 20.0
prefWidth = 410.0
children(buttons) {
button("Create").setOnAction { createDocument() }
vbox { label("Uh-oh") } // What happens here?
button("Cancel").setOnAction { close() }
}
}
}
I can't just test it out right now, which is why I'm asking.
That works fine, since ButtonBar.buttons
is basically an HBox with some alignment tricks for buttons :)
I didn't realize that. Good to know.
Are you satisfied @radicaled ? Should we close the issue?
Would this basically be the same workflow for ToolBar?
Yeah, for ToolBar you would use children(items)
, but ToolBar also have direct support for the button
builder.
I know that, but I was testing an idea a couple days ago that required more than buttons on a toolbar. This children trick should make that a lot easier.
Are you satisfied @radicaled ? Should we close the issue?
Yeah, thanks, this looks really good @edvin ! Better than what I was going to do.
Great @radicaled :) @t-boom The builder pattern we use have certain limitations, and this is one of them. The alternative is to subclass everything though, and that sucks more IMO :) Once you know about the caveats though, it works really well :)
Here's a modal dialog I have:
I've been using the
pattern to work with controls that don't have builders available, usually custom ones. I'm wondering now if I'm using the right approach of
add
andapply
, and if those with more experience have come up with a better way to handle custom controls.Also, this feels kind of like a misappropriation of the issues tracker -- is there a mailing list for tornadofx that's not listed in the README?