In my desktop app I have a main window. How would ...
# compose-desktop
z
In my desktop app I have a main window. How would I instantiate another instance of the application? I'm trying to create a New Window button basically
r
Create multiple instances of
Window
that show the same content. You could make a
MyMainWindow
composable that encapsulates the window and it's content.
Copy code
fun main() = application {
    // Keep track of which windows should be open
    // Use a unique key (id) for each window so we can remove it later
    val openWindowKeys = remember { mutableStateListOf<Int>() }

    // Open an initial window, so it's possible to spawn more
    remember {
        openWindowKeys.add(Random.nextInt())
    }

    // Display the windows which should be open
    openWindowKeys.forEach { windowKey ->
        // key() {} is important to prevent windows being recycled in unexpected ways
        // -- without a key, content can shuffle between windows as they are closed
        key(windowKey) {
            MyMainWindow(
                onCloseRequest = { openWindowKeys.remove(windowKey) },
                onNewWindowRequest = { openWindowKeys.add(Random.nextInt()) }
            )
        }
    }
}

@Composable
fun MyMainWindow(onCloseRequest: () -> Unit, onNewWindowRequest: () -> Unit) {
    Window(onCloseRequest = onCloseRequest) {
        Button(onClick = onNewWindowRequest) { Text("Open new window") }
    }
}
(code is untested because I'm on my phone, but hopefully that's enough to go from)
Sidenote: it always feels ugly using
mutableStateList
for what should really be a set. Is there something like
mutableStateSet
that perhaps I'm not aware of?
a
I use this, together with `mutableStateMap`:
Copy code
/**
 * Returns a [MutableSet] backed by the given map. This allows using a [SnapshotStateMap] as a set.
 */
fun <T> MutableMap<T, Unit>.asMutableSet(): MutableSet<T> = object: AbstractMutableSet<T>() {

    override fun add(element: T): Boolean {
        return this@asMutableSet.put(element, Unit) == null
    }

    override fun remove(element: T): Boolean {
        return this@asMutableSet.keys.remove(element)
    }

    override fun isEmpty(): Boolean {
        return this@asMutableSet.isEmpty()
    }

    override fun iterator(): MutableIterator<T> {
        return this@asMutableSet.keys.iterator()
    }

    override val size: Int
        get() = this@asMutableSet.size

}