Comments (54)
By the way, I'll strikethrough controls on the OP list as they get implemented.
from tornadofx.
One suggestion (still thinking though):
class MyView: View() {
override val root = VBox()
val optionGrp = ToggleGroup()
init {
with(root) {
togglebutton("1", optionGrp)
togglebutton("2", optionGrp)
togglebutton("3", optionGrp)
}
}
}
from tornadofx.
Ah, simple indeed. I like it :)
from tornadofx.
Of course, if anybody (including newcomers) want to knock some of these out I'll welcome the help. Many of these are pretty easy to implement.
from tornadofx.
Very good initiative! It would be great if some newcomers would like to add a couple of these! I suggest making a comment on this thread before you start with a control to avoid more people working on the same control.
Look at https://github.com/edvin/tornadofx/blob/master/src/main/java/tornadofx/Builders.kt for inspiration and examples.
from tornadofx.
I will hold off on #57 until this issue is resolved.
from tornadofx.
Good call. We will probably need to do a code freeze in some form when #57 gets implemented.
from tornadofx.
Yeah, but I figure it can be done in a couple of hours, so it shouldn't be a huge problem :)
from tornadofx.
For the PasswordField
, would want to pass in an initial value (such as a saved password)? This can always be done with apply { text = value }
, but is it common enough to add an optional parameter to the Pane.passwordfield
method?
Also, I'm assuming there's no real use case for double binding the text of a password field like there is for a text field, but let me know if I'm wrong.
from tornadofx.
Absolutely. Add a default value for the password() function. We try to streamline towards common use cases and that definitely is one.
I agree with that sentiment regarding binding like a text field. Doesn't feel like that would be very common, and I don't think that would encourage secure design.
from tornadofx.
Sounds good
from tornadofx.
For the ToggleButton
, how should grouping be handled? I'm thinking either create a Pane.togglegroup
method that doesn't add anything to the pane but does return a ToggleGroup
, or have a toggle group scope of some sort in which toggle buttons can be added to the pane and automatically have the group attached. Of course, nothing is stopping us from doing both.
from tornadofx.
The second option has some issues. If we make Pane.togglegroup
return a ToggleGroup
, it's context has no pane to add its buttons. If we have it return something like Pair<Pane, ToggleGroup>
, there is more overhead/boilerplate for adding a button to it later.
Here's what I've thought of so far:
fun Pane.togglebutton(text: String = "", group: ToggleGroup? = null, op: (ToggleButton.() -> Unit)? = null) = opcr(this, ToggleButton(text).apply { if (group != null) toggleGroup = group }, op)
fun Pane.togglegroup(op: (Pair<Pane, ToggleGroup>.() -> Unit)? = null): Pair<Pane, ToggleGroup> {
val group = Pair(this, ToggleGroup())
op?.invoke(group)
return group
}
fun Pair<Pane, ToggleGroup>.button(text: String = "", op: (ToggleButton.() -> Unit)? = null) = opcr(first, ToggleButton(text), op)
which would require something like:
val group = togglegroup {
button("Alice")
}
togglebutton("Bob", group.second)
to add a button to the group after (I don't like the .second
reference).
from tornadofx.
Currently I just have the first option implemented
fun Pane.togglegroup() = ToggleGroup()
fun Pane.togglebutton(text: String = "", group: ToggleGroup? = null, op: (ToggleButton.() -> Unit)? = null)
= opcr(this, ToggleButton(text).apply { if (group != null) toggleGroup = group }, op)
from tornadofx.
(This problem also applies to RadioButton
s)
from tornadofx.
Cafe internet is not cooperating with me. Give me a moment...
from tornadofx.
Okay these are some good points, let me think through this. Hacking my way through this right now.
from tornadofx.
Just a heads up, I've also tried adding the pane as the userdata of the toggle group (though this pretty much bypasses type safety). My next idea either an extension property or a small class that extends from ToggleGroup
from tornadofx.
There's got to be cleaner way to do this without the Pair
. Trying a few things.
from tornadofx.
Okay, maybe we need to step back because I think you and I are abstracting ToggleGroup
into something it is not. Could not, in theory, ToggleButtons in a given ToggleGroup be completely separated? Sometimes ToggleButton
is not used in a group at all.
While it seems natural, we start fighting JavaFX's design (whether we agree with it or not) if we treat ToggleGroup
like it is a Pane
that contains ToggleButtons.
Why not do this?
class MyView: View() {
override val root = VBox()
val grp = ToggleGroup()
init {
with(root) {
togglebutton("1").apply {
toggleGroup = grp
}
togglebutton("2").apply {
toggleGroup = grp
}
togglebutton("3").apply {
toggleGroup = grp
}
}
}
}
If that's too repetitive for you, just create an internal extension function for re-usability.
class MyView: View() {
override val root = VBox()
val optionGrp = ToggleGroup()
init {
with(root) {
togglebutton("1").addToOptionGrp()
togglebutton("2").addToOptionGrp()
togglebutton("3").addToOptionGrp()
}
}
private fun ToggleButton.addToOptionGrp() {
toggleGroup = optionGrp
}
}
What do you think @edvin?
from tornadofx.
I'm here, having a look at togglegroup now :)
from tornadofx.
Hmm... Maybe I'm missing something, but that seems quite simple to implement, and with no major drawbacks as far as I can see :)
from tornadofx.
You mean nesting ToggleButton
builders into a ToggleGroup
builder?
from tornadofx.
The main thing is that it's easy to understand, and not much boiler plate. Ofcourse we could save "the current toggle group" in a state variable, but I fear it will feel a bit magical.
from tornadofx.
I don't know if it's worth having a toggleGroup builder. Hmm.. I could try to mock up an implementation that does magic, and see how it feels though.
from tornadofx.
It certainly would be convenient if there's an elegant way to do it. My guess is it will require creating an extension class or something. But maybe we can use a fake Pane
pattern, but I tried that and got a little dizzy.
I kind of liked your earlier example with the ToggleGroup
being passed as an optional second argument.
from tornadofx.
I've got Hyperlink
and PasswordField
done, as well as the non-magic ToggleButton
and RadioButton
. I'll submit a PR, and magic ToggleGroup
stuff can be done later. :)
PR: #78
from tornadofx.
Very nice @t-boom ! I'll try one more thing with ToggleButton, hang on.
from tornadofx.
Oops, didn't see your message soon enough :)
from tornadofx.
I can pull the radiobutton and togglebutton code out of the PR
from tornadofx.
I think I have an idea, kind of what @t-boom already suggested:
init {
with(root) {
// Create a new togglegroup and assign it to root
togglegroup()
// The togglebutton builder function checks if the node it's added to
// is associated with a togglegroup, and adds it to that group
togglebutton("Alice")
hbox {
// Add another togglegroup
togglegroup()
// Buttons in the hbox will be added to the second group
togglebutton("Bob")
}
}
}
The parent node could populate properties["tornadofx.togglegroup"] with the actual togglegroup. Then we could also add features to Node like hasToggleGroup
and getToggleGroup()
etc.
I can't see type safety becoming an issue with this approach :)
What do you guys think? (Not saying this is the optimal solution though)
from tornadofx.
That is an intriguing idea. I can't think of a way it would backfire so lets go with it. The only drawback I can think of is there is no clear structural relationship between the toggle buttons and the toggle group syntactically, but with some documentation that can quickly be overcome.
from tornadofx.
Edge case: What if we want to not use a toggle group after one is created (such as Charlie below)?
init {
with(root) {
// Create a new togglegroup and assign it to root
togglegroup()
// The togglebutton builder function checks if the node it's added to
// is associated with a togglegroup, and adds it to that group
togglebutton("Alice")
// I don't want this button in the toggle group
togglebutton("Charlie")
hbox {
// Add another togglegroup
togglegroup()
// Buttons in the hbox will be added to the second group
togglebutton("Bob")
}
}
}
Another thing to worry about is trying to add to an earlier toggle group after one has been created
init {
with(root) {
// Create a new togglegroup and assign it to root
togglegroup() // <- This is Fred
// The togglebutton builder function checks if the node it's added to
// is associated with a togglegroup, and adds it to that group
togglebutton("Alice")
// Start a new toggle group
togglegroup()
// The togglebutton builder function checks if the node it's added to
// is associated with a togglegroup, and adds it to that group
togglebutton("Charlie")
// I want to add this one to Fred
togglebutton("Dave")
hbox {
// Add another togglegroup
togglegroup()
// Buttons in the hbox will be added to the second group
togglebutton("Bob")
}
}
}
from tornadofx.
In a way it kind of turns a Pane into a ToggleGroup which I like : )
from tornadofx.
Does the toggle group associate with its parent?
from tornadofx.
Saving private Charlie:
togglebutton("Charlie", null)
Marry Dave and Fred <3:
val fred = togglegroup()
...
togglebutton("Dave", fred)
from tornadofx.
Cool! Then I think we have a winner. You might as well add it to the PR before I merge? :)
from tornadofx.
I agree looks good.
from tornadofx.
I think you can do something like this to solve the togglegroup assignment:
fun Node.getToggleGroup(): ToggleGroup? = properties["tornadofx.togglegroup"] as ToggleGroup?
fun Pane.togglebutton(text: String = "", group: ToggleGroup? = getToggleGroup(), op: (ToggleButton.() -> Unit)? = null) {
...
}
So, default will be to lookup the group in the current Pane, and a passed null value will override that.
from tornadofx.
This was a good talk, I think we landed on a nice solution. Thanks, guys! :)
from tornadofx.
Sorry, someone else will have to. Something came up and I have to go (most likely for the rest of the day). My availability this weekend will be sporadic at best, so I don't know if I'll be around to do much more till next week 😦
from tornadofx.
No worries, @t-boom :) I'm quite busy this weekend myself, and probably Thomas as well, so either you'll have a look next week, or I can merge and do the rest then if you're still busy. Have a nice weekend!
from tornadofx.
I'll see if I can make time to handle the PR in the next day or two. Thanks for getting involved @t-boom. We're glad to have you onboard.
from tornadofx.
Okay I merged and made those tweaks to @t-boom's work. Updated list at top of this thread: 5 down, 7 to go.
from tornadofx.
I also added TextFlow
and Text
builders.
class MyApp: SingleViewApp() {
override val root = VBox()
init {
with(root) {
text("A TextFlow Demo")
textflow {
text("Hello") {
fill = Color.RED
}
text(" World") {
fill = Color.BLUE
font = Font.font(20.0)
}
}
}
}
}
from tornadofx.
Fantastic work!
from tornadofx.
Just to keep information together: slider and separator are merged in now, and I have a PR for htmleditor.
from tornadofx.
Excellent, just crossed those off and I'll follow up with HTMLEditor shortly. Thanks again for spending time on this.
from tornadofx.
HTMLEditor is now merged as well.
from tornadofx.
@thomasnield My pleasure. This is an awesome project.
from tornadofx.
I'm adding chooseFile
in Dialogs.kt
since the FileChooser is not a UI component. Docs and usage:
Ask the user to select one or more files from a file chooser dialog. The mode will dictate how the dialog works, by allowing single selection, multi selection or save functionality. The file dialog will only allow files that match one of the given ExtensionFilters.
This function blocks until the user has made a selection, and can optionally block a specified owner Window.
If the user cancels, the returned file list will be empty.
// Select multiple files
val filters = arrayOf(FileChooser.ExtensionFilter("Text files", "*.txt"))
val files: List<File> = chooseFile("Select some text files", filters, FileChooserMode.Multi)
println("The user chose $files")
// Present save dialog
val files: List<File> = chooseFile("Save document", filters, FileChooserMode.Save)
if (files.isNotEmpty()) save(files.first())
from tornadofx.
Added colorpicker builder with optional initial color an enum to select mode.
colorpicker()
colorpicker(Color.MAROON)
colorpicker(Color.MAROON, ColorPickerMode.MenuButton) {
colorpicker(Color.MAROON, ColorPickerMode.MenuButton) {
customColors.addAll(Color.BLANCHEDALMOND, Color.AQUAMARINE)
}
from tornadofx.
I think that's it :) Any comments, or should we close this issue?
from tornadofx.
Nice!!!
from tornadofx.
Related Issues (20)
- TornadoFx ClassCastException HOT 1
- Accessing nodes with less code HOT 4
- Advanced Data Controls Guide Clarification HOT 1
- Unbind TextField text property from non-String property HOT 2
- Font not loading HOT 1
- AsyncKt cannot access class com.sun.glass.ui.Application HOT 5
- EventBus.fire does not check for listeners of superclass types HOT 1
- Set window icons for Alerts
- Hot reload doesn't work with openjdk
- a bug with toggleClass HOT 2
- TornadoFx stackpane overlapping with menubar
- How can i build a native image using tornadofx HOT 1
- Localization of german Double values
- Data Driven TreeView HOT 1
- how to use field()? | and why field() cant' be used without form()? HOT 2
- Tornadofx with Spring security
- Is this not longer maintained? HOT 8
- Looking for maintainers HOT 1
- Guilde is not available HOT 1
- Documentation does not work HOT 4
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from tornadofx.