我可以通过 Compose Multiplatform 中的单独按钮更改组件的值吗?

发布于 2025-01-11 03:52:34 字数 5048 浏览 0 评论 0 原文

我正在尝试制作一个桌面应用程序,允许您搜索存储在单独目录中的 Kotlin 类中的许多预定义位置。为了实现这一点,我使用了 反射compose-jb 库。

我遇到的问题是,当我在输入要搜索的标签后按下搜索按钮时,我无法弄清楚如何更新框列(位于另一个框组件中)以进行更改。

下面是我的代码(针对 Main.kt 文件),它描述了整个桌面应用程序。

val reflections = Reflections("io.github.mobomega.project.attractions")
var display = mutableSetOf<Attraction>()

fun main() = application {
    val stateVertical = rememberScrollState(0)
    val stateHorizontal = rememberScrollState(0)
    var state = Box(
        modifier = Modifier
            .fillMaxSize()
            .verticalScroll(stateVertical)
            .padding(end = 12.dp, bottom = 12.dp)
            .horizontalScroll(stateHorizontal)
    )
    Window(
        onCloseRequest = ::exitApplication,
        title = "Search",
        state = rememberWindowState(width = 2256.dp, height = 1504.dp)
    ) {
        val count = remember { mutableStateOf(1) }
        MaterialTheme {
            Column {
                val text = remember { mutableStateOf("") }
                OutlinedTextField(
                    value = text.value,
                    singleLine = true,
                    onValueChange = { text.value = it },
                    modifier = Modifier.align(Alignment.CenterHorizontally)
                )
                Row (modifier = Modifier.size(2256.dp, 50.dp), horizontalArrangement = Arrangement.Center) {
                    Button(modifier = Modifier.align(Alignment.Top),
                        onClick = {
                            val tags = text.value.split(", ", ",")
                            for (tag in tags) {
                                search(tag.lowercase())
                                println("$display have tag $tag")
                            }
                            // Setting the new value of the Box
                            state = create(stateVertical, stateHorizontal)
                            // Creates error:
                            // "@Composable invocations can only happen from the context of a @Composable function"

                        }) {
                        Text("Search")
                    }
                    Button (modifier = Modifier.align(Alignment.Top),
                        onClick = {
                            display.clear()
                        }) {
                        Text("Reset")
                    }
                }
                Row (horizontalArrangement = Arrangement.Center) {
                    Box(
                        modifier = Modifier.fillMaxSize()
                            .background(color = Color(red = 0xFF, green = 0xFF, blue = 0xFF))
                            .padding(10.dp)

                    ) {

                        state // Creating the state Box component in the Row

                        VerticalScrollbar(
                            modifier = Modifier.align(Alignment.CenterEnd)
                                .fillMaxHeight(),
                            adapter = rememberScrollbarAdapter(stateVertical)
                        )
                        HorizontalScrollbar(
                            modifier = Modifier.align(Alignment.BottomStart)
                                .fillMaxWidth()
                                .padding(end = 12.dp),
                            adapter = rememberScrollbarAdapter(stateHorizontal)
                        )
                    }
                }
            }
        }
    }
}

@Composable
fun textBox(text: String = "Item") {
    Box(
        modifier = Modifier.height(32.dp)
            .width(400.dp)
            .background(color = Color(200, 0, 0, 20))
            .padding(start = 10.dp),
        contentAlignment = Alignment.CenterStart
    ) {
        Text(text = text)
    }
}

@Composable
fun create(stateVertical: ScrollState, stateHorizontal: ScrollState) = Box(
    modifier = Modifier
        .fillMaxSize()
        .verticalScroll(stateVertical)
        .padding(end = 12.dp, bottom = 12.dp)
        .horizontalScroll(stateHorizontal)
    ) {
        Column {
            var x = 0
            for (attr in display) {
                x++
                textBox(attr.name)
                if (x < display.size) {
                    Spacer(modifier = Modifier.height(5.dp).align(Alignment.CenterHorizontally))
                }
            }
        }
}

fun search(text: String) {
    for (attr in reflections.getSubTypesOf(Attraction::class.java)) {
        val temp = attr.getConstructor().newInstance()
        println("${temp.name} has tags ${temp.tags}")
        if (temp.matches(text) && (temp !in display)) {
            display += temp
        }
    }
}

我尝试更新包含与任何搜索条件匹配的所有项目的 Box 的值,但遇到了许多问题,例如在“onClick”函数中我设置了“状态”变量(存储所有匹配项)不是可组合函数,因此我无法更改该值。

我如何完成从另一个组件(例如按钮)更改组件(例如框)的值?

I am trying to make a desktop application that allows you to search through a number of predefined locations stored in Kotlin classes in a separate directory. To accomplish this, I've used the reflections and compose-jb libraries.

The problem I've run into is that I can't figure out how to update a Column of Boxes (located in another Box component) to change when I press the search button after entering tags that I want to search by.

My code is below (for the Main.kt file) that describes the entire desktop application.

val reflections = Reflections("io.github.mobomega.project.attractions")
var display = mutableSetOf<Attraction>()

fun main() = application {
    val stateVertical = rememberScrollState(0)
    val stateHorizontal = rememberScrollState(0)
    var state = Box(
        modifier = Modifier
            .fillMaxSize()
            .verticalScroll(stateVertical)
            .padding(end = 12.dp, bottom = 12.dp)
            .horizontalScroll(stateHorizontal)
    )
    Window(
        onCloseRequest = ::exitApplication,
        title = "Search",
        state = rememberWindowState(width = 2256.dp, height = 1504.dp)
    ) {
        val count = remember { mutableStateOf(1) }
        MaterialTheme {
            Column {
                val text = remember { mutableStateOf("") }
                OutlinedTextField(
                    value = text.value,
                    singleLine = true,
                    onValueChange = { text.value = it },
                    modifier = Modifier.align(Alignment.CenterHorizontally)
                )
                Row (modifier = Modifier.size(2256.dp, 50.dp), horizontalArrangement = Arrangement.Center) {
                    Button(modifier = Modifier.align(Alignment.Top),
                        onClick = {
                            val tags = text.value.split(", ", ",")
                            for (tag in tags) {
                                search(tag.lowercase())
                                println("$display have tag $tag")
                            }
                            // Setting the new value of the Box
                            state = create(stateVertical, stateHorizontal)
                            // Creates error:
                            // "@Composable invocations can only happen from the context of a @Composable function"

                        }) {
                        Text("Search")
                    }
                    Button (modifier = Modifier.align(Alignment.Top),
                        onClick = {
                            display.clear()
                        }) {
                        Text("Reset")
                    }
                }
                Row (horizontalArrangement = Arrangement.Center) {
                    Box(
                        modifier = Modifier.fillMaxSize()
                            .background(color = Color(red = 0xFF, green = 0xFF, blue = 0xFF))
                            .padding(10.dp)

                    ) {

                        state // Creating the state Box component in the Row

                        VerticalScrollbar(
                            modifier = Modifier.align(Alignment.CenterEnd)
                                .fillMaxHeight(),
                            adapter = rememberScrollbarAdapter(stateVertical)
                        )
                        HorizontalScrollbar(
                            modifier = Modifier.align(Alignment.BottomStart)
                                .fillMaxWidth()
                                .padding(end = 12.dp),
                            adapter = rememberScrollbarAdapter(stateHorizontal)
                        )
                    }
                }
            }
        }
    }
}

@Composable
fun textBox(text: String = "Item") {
    Box(
        modifier = Modifier.height(32.dp)
            .width(400.dp)
            .background(color = Color(200, 0, 0, 20))
            .padding(start = 10.dp),
        contentAlignment = Alignment.CenterStart
    ) {
        Text(text = text)
    }
}

@Composable
fun create(stateVertical: ScrollState, stateHorizontal: ScrollState) = Box(
    modifier = Modifier
        .fillMaxSize()
        .verticalScroll(stateVertical)
        .padding(end = 12.dp, bottom = 12.dp)
        .horizontalScroll(stateHorizontal)
    ) {
        Column {
            var x = 0
            for (attr in display) {
                x++
                textBox(attr.name)
                if (x < display.size) {
                    Spacer(modifier = Modifier.height(5.dp).align(Alignment.CenterHorizontally))
                }
            }
        }
}

fun search(text: String) {
    for (attr in reflections.getSubTypesOf(Attraction::class.java)) {
        val temp = attr.getConstructor().newInstance()
        println("${temp.name} has tags ${temp.tags}")
        if (temp.matches(text) && (temp !in display)) {
            display += temp
        }
    }
}

I have tried to update the value of the Box that contains all of the items that match any of the search criteria, but I have run into a number of issues, such as the "onClick" function in which I set the new value of the "state" variable (storing all of the matching items) not being a Composable function, and therefore I can't change the value.

How would I accomplish changing the value of a Component such as a Box from another Component, such as a Button?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

ゝ偶尔ゞ 2025-01-18 03:52:34

在 Compose 中,您无法像使用 state 变量那样创建视图。调用的结果只是 Unit,当您稍后调用它时,您应该会看到一条警告“表达式未使用”。创建变量时,视图将添加到树层次结构中。

要解决您的问题,您需要将 display 声明为可变状态 - 这是专门为 Compose 制作的新事物,它允许在状态更改时触发重组:

val display by mutableStateOf<Attraction>(setOf())

然后在您的 搜索中进行更新

val mutableDisplay = mutableSetOf<Attraction>()
// for 
// ...
mutableDisplay += temp
// ...
display = mutableDisplay

请注意,您不能在可变状态中使用可变集,因为可变状态将无法跟踪该集的更改。

要了解有关 Compose 中状态的更多信息,我建议您查看此 YouTube 视频,其中解释了基本原理,并了解 Compose 心理模型,以便更好地理解如何使用它。

In Compose you can't create a view like you're doing with state variable. Result of your call is just Unit, and when you later call it you should see a warning "The expression is unused". The view is added at the tree hierarchy at the moment your variable is created.

To solve your problem you need to declare display as a mutable state - it's a new thing made especially for Compose, which allows triggering recomposition when this state changes:

val display by mutableStateOf<Attraction>(setOf())

And then update like this in your search:

val mutableDisplay = mutableSetOf<Attraction>()
// for 
// ...
mutableDisplay += temp
// ...
display = mutableDisplay

Note that you can't use mutable set inside your mutable state, as mutable state won't be able to track changes of this set.

To learn more about state in Compose I suggest you checking this youtube video which explains the basic principles, and Compose mental model for better understanding of how to work with it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文