Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't use fontawesomefx with kotlin and tornadofx

I'm trying create some JavaFX buttons with FontAwesomeFX icons using TornadoFX. This is the code

    data class ButtonInfo(val texto: String, val icon: GlyphIcon<*>)

    val list = listOf(
        ButtonInfo("Cadastro", FontAwesomeIconView(FontAwesomeIcon.ADDRESS_BOOK)),
        ButtonInfo("Corrida", MaterialDesignIconView(MaterialDesignIcon.RUN)),
        ButtonInfo("Classificacao", FontAwesomeIconView(FontAwesomeIcon.LIST)))

    list.forEach {
        it.icon.size = "3em"
        val bt = Button(it.texto, it.icon)
        bt.contentDisplay = ContentDisplay.TOP
        bt.minWidth = 200.0
        root += bt
    }

In compilation I get this error:

Type parameter bound for T in var <T : Enum<T!>!> GlyphIcon<T>.size: String! where T : GlyphIcons!

is not satisfied: inferred type CapturedTypeConstructor(*) is not a subtype of GlyphIcons!

The GlyphIcon is a Java abstract class with this declaration:

public abstract class GlyphIcon<T extends Enum<T> & GlyphIcons> extends Text

I don't know how turn around this error. If I declare:

data class ButtonInfo(val texto: String, val icon: Text)

I don't get the above mentioned error, but I miss '.size' property. How I can declare my class 'ButtonInfo' so that this code works?

like image 445
Mauricio Kanada Avatar asked Feb 22 '17 02:02

Mauricio Kanada


1 Answers

You didn't post your complete class, but it looks like you try to run the list.forEach instruction outside any method or init block? Kotlin gets confused by the size accessor, use setSize() to avoid the issue.

Here is a complete class with minimal changes to your sample that compiles and runs, and shows you the icons in a vbox.

data class ButtonInfo(val texto: String, val icon: GlyphIcon<*>)

class IconView : View() {
    val list = listOf(
            ButtonInfo("Cadastro", FontAwesomeIconView(FontAwesomeIcon.ADDRESS_BOOK)),
            ButtonInfo("Corrida", MaterialDesignIconView(MaterialDesignIcon.RUN)),
            ButtonInfo("Classificacao", FontAwesomeIconView(FontAwesomeIcon.LIST)))

    override val root = vbox {
        list.forEach {
            it.icon.setSize("3em")
            button(it.texto, it.icon) {
                contentDisplay = ContentDisplay.TOP
                minWidth = 200.0
            }
        }
    }
}

I used the button builder instead of manually adding to the root node.

Let me offer an alternative:

class IconView : View() {
    override val root = vbox {
        button("Cadastro").icon(FontAwesomeIcon.ADDRESS_BOOK)
        button("Corrida").icon(MaterialDesignIcon.RUN)
        button("Classificacao").icon(FontAwesomeIcon.LIST)
    }
}

Then you define this function in a utility file:

fun Button.icon(icon: GlyphIcons, minButtonWidth: Double = 200.0) {
    graphic = when (icon) {
        is FontAwesomeIcon -> FontAwesomeIconView(icon)
        is MaterialDesignIcon -> MaterialDesignIconView(icon)
        else -> throw IllegalArgumentException("Unknown font family ${icon.fontFamily}")
    }
    with(graphic as GlyphIcon<*>) {
        contentDisplay = ContentDisplay.TOP
        setSize("3em")
    }
    minWidth = minButtonWidth
}

It makes it much easier to see what's going on at the call site.

Also, the setSize("3em") is only there to support Scene Builder. Consider using the glyphSize accessor instead.

like image 107
Edvin Syse Avatar answered Oct 09 '22 20:10

Edvin Syse