kotlinswingawt

Is there a way to fix the error "Unresolved reference 'build'." in my code Kotlin?


I want to create a Kotlin library as a wrapper for Java Swing, but my code has error. The error is Unresolved reference 'build'.. My code Kotlin:

(Components.kt)

package swingcustomized
import javax.swing.JButton
import javax.swing.JLabel
import javax.swing.JPanel
import javax.swing.BoxLayout

abstract class SwingComponent {
    abstract fun build(): java.awt.Component
}

class Text(private val text: String) : SwingComponent() {
    override fun build() = JLabel(text)
}

class Button(private val text: String, private val onClick: () -> Unit) : SwingComponent() {
    override fun build() = JButton(text).apply {
        addActionListener { onClick() }
    }
}

fun SwingWindow.text(text: String) = addComponent(Text(text))
fun SwingWindow.button(text: String, onClick: () -> Unit) = addComponent(Button(text, onClick))

// Layout
class Column : SwingComponent() {
    private val components = mutableListOf<SwingComponent>()

    fun addComponent(component: SwingComponent) {
        components.add(component)
    }

    override fun build() = JPanel().apply {
        layout = BoxLayout(this, BoxLayout.Y_AXIS)
        components.forEach { add(it.build()) }
    }
}

fun SwingWindow.column(content: Column.() -> Unit) {
    val column = Column()
    column.content()
    addComponent(column)
}

(SwingWindow.kt):

package swingcustomized
import java.awt.Dimension
import javax.swing.JFrame
class SwingWindow(private val title: String, width: Int, height: Int) {
    private val components = mutableListOf<SwingComponent>()
    private val frame = JFrame(title).apply {
        defaultCloseOperation = JFrame.EXIT_ON_CLOSE
        size = Dimension(width, height)
        layout = java.awt.FlowLayout()
    }

    init {
        frame.isVisible = true
    }

    fun add(component: SwingComponent) {
        components.add(component)
        frame.add(component.build())
        frame.revalidate()
        frame.repaint()
    }
    fun addComponent(component: SwingComponent) {
        components.add(component)
        frame.add(component.build())
        frame.revalidate()
        frame.repaint()
    }
}

fun swingApp(title: String, width: Int, height: Int, content: SwingWindow.() -> Unit) {
    SwingWindow(title, width, height).apply(content)
}

The error is at Components.kt
My environment:

The full error is:
e: file:///home/ratratarmy/IdeaProjects/swingcustomized/lib/src/main/kotlin/Components.kt:34:37 Unresolved reference 'build'.

I tried to fix this error by change the add() to addComponent() in the code, but it not fixed that error. I expected changing this to will be fix the error, but it not fix that.


Solution

  • components in the apply lambda does not refer to the components property you declared in Column. It refers to getComponents declared in java.awt.Container. You are calling getComponents on the JPanel that has just been created. Therefore, it in forEach is of type java.awt.Component, which does not declare a build method.

    To refer to the Column instance, you should use a qualified this.

    override fun build() = JPanel().apply {
        layout = BoxLayout(this, BoxLayout.Y_AXIS)
        this@Column.components.forEach { add(it.build()) }
    }