Compose cross-platform first bomb: experience Compose for Desktop

foreword

Compose is a declarative UI development framework officially provided by Android, and Compose Multiplatform is maintained by JetBrains. For Android development, I personally think that learning Jetpack Compose is a must, because it will become the mainstream development mode of Android, and compose-jb As an expansion capability, we can choose to try. Today, let's take a look at the process of using compose-jb to develop a desktop application.

There will be a second bomb, a third bomb...

Environmental requirements

There are two main requirements for developing Compose for Desktop environment:

  • JDK 11 or later

  • IntelliJ IDEA 2020.3 or later (AS can also be used, here to use the project template provided by IDEA)

Then let's experience the development process of Compose for Desktop step by step.

Development Process

create project

After downloading IDEA, we directly create a new project, select the Compose Multipalteform type, and enter the project name. Here, only select Single platform and the platform is Desktop.

 After creating the project, look at the project directory structure. The directory structure is shown in the figure below.

 

The program entry is specified as MainKt, package name, version number, etc. in the configuration file. The MainKt file code is shown below.

@Composable
@Preview
fun App() {
    var text by remember { mutableStateOf("Hello, World!") }

    MaterialTheme {
        Button(onClick = {
            text = "Hello, Desktop!"
        }) {
            Text(text)
        }
    }
}

fun main() = application {
    Window(onCloseRequest = ::exitApplication) {
        App()
    }
}

In the MainKt file, the App() method is called at the entrance, a button is drawn in the App method, and the program is run, the result is shown in the figure below.

We can see that a Hello World desktop program is displayed. Next let's add some page elements.

Add input box

In order to make the desktop program more "presentable", we first changed the title of the desktop program to "Student Management System", after all, it was our favorite name when we were students. The code looks like this:

fun main() = application {
    Window(onCloseRequest = ::exitApplication, title = "学生管理系统") {
        App()
    }
}

In the App method, add two input boxes for the student number and password, and add a login button, which is written in the same way as Compose in Android, and the code is as follows.

MaterialTheme {
    var name by remember {
        mutableStateOf("")
    }
    var password by remember {
        mutableStateOf("")
    }
    Column {
        TextField(name, onValueChange = {
            name = it
        }, placeholder = {
            Text("请输入学号")
        })
        TextField(password, onValueChange = {
            password = it
        }, placeholder = {
            Text("请输入密码")
        })
        Button(onClick = {

        }) {
            Text("登陆")
        }
    }

}

Run the program again, the page is as shown below.

 

add avatar

Then we will add the avatar display, and we will put the downloaded image resources in the resources directory

Then use the Image component to display the avatar, the code is as follows.

Image(
    painter = painterResource("photo.png"),
    contentDescription = null,
    modifier = Modifier.size(width = 100.dp, height = 100.dp)
        .clip(CircleShape)
)

Run the program again, the result is as follows.

 

Of course, we can modify the layout a little bit to make the layout look better. But that's not the point here.

Add exit popup

When we click the X number in the upper left corner (macOS), the application exits directly. This is because the exit event is specified in the Window function. Let’s take a look at this part of the code, as shown below.

fun main() = application {
    Window(onCloseRequest = ::exitApplication, title = "学生管理系统") {
        App()
    }
}

Next, we add a pop-up reminder to confirm the exit. The code is shown below.

fun main() = application {

    var windowsOpen by remember {
        mutableStateOf(true)
    }
    var isClose by remember {
        mutableStateOf(false)
    }
    if (windowsOpen) {
        Window(onCloseRequest = { isClose = true }, title = "学生管理系统") {
            App()
            if (isClose) {
                Dialog(onCloseRequest = { isClose = false }, title = "确定退出应用程序吗?") {
                    Row {
                        Button(onClick = {
                            windowsOpen = false
                        }) {
                            Text("确定")
                        }
                    }
                }
            }
        }
    }

}

Here we have added two variables windowsOpen and isClose to control whether the Window of the application is displayed and to confirm the display of the pop-up window respectively. I believe anyone who has used Jetpack Compose can understand this part of the code.

Run the program, click the X number, and the exit confirmation pop-up window will pop up, click OK, and the application will exit. Results as shown below.

 

Implement a network request function

In the introduction to Kotlin cross-platform development, we borrowed the "Daily Question" interface in "wanandroid" to implement a network request. Now we port this part of the function to the Desktop program. The network request framework still uses Ktor. Of course, you can also With Retrofit, this doesn't really matter.

First add the dependency of Ktor, the code is as follows.

val jvmMain by getting {
    dependencies {
        implementation(compose.desktop.currentOs)
        implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4")
        val ktorVersion = "2.1.2"
        implementation("io.ktor:ktor-client-core:$ktorVersion")
        implementation("io.ktor:ktor-client-content-negotiation:$ktorVersion")
        implementation("io.ktor:ktor-serialization-kotlinx-json:$ktorVersion")
        implementation("io.ktor:ktor-client-android:$ktorVersion")
    }
}

Add an Api interface

object Api {
    val dataApi = "https://wanandroid.com/wenda/list/1/json"
}

Create the HttpUtil class, which is used to create the HttpClient object and obtain data. The code is as follows.

import io.ktor.client.*
import io.ktor.client.call.*
import io.ktor.client.plugins.contentnegotiation.*
import io.ktor.client.request.*
import io.ktor.serialization.kotlinx.json.*
import kotlinx.serialization.json.Json

class HttpUtil {
    private val httpClient = HttpClient {
        install(ContentNegotiation) {
            json(Json {
                prettyPrint = true
                isLenient = true
                ignoreUnknownKeys = true
            })
        }
    }

    /**
     * 获取数据
     */
    suspend fun getData(): String {
        val rockets: DemoReqData =
            httpClient.get(Api.dataApi).body()
        return "${rockets.data} "
    }
}

DemoReqData is the entity class corresponding to the mapping of the data returned by the interface, so it will not be given here.

Then we write the UI, click the button to start the network request, the code is as follows.

Column() {
    val scope = rememberCoroutineScope()
    var demoReqData by remember { mutableStateOf(DemoReqData()) }
    Button(onClick = {
        scope.launch {
            try {
                demoReqData = HttpUtil().getData()
            } catch (e: Exception) {
            }
        }
    }) {
        Text(text = "请求数据")
    }

    LazyColumn {
        repeat(demoReqData.data?.datas?.size ?: 0) {
            item {
                Message(demoReqData.data?.datas?.get(it))
            }
        }
    }
}

After obtaining the data, display the data through the Message method . Only the author and the title are displayed here. The code is as follows.

@Composable
fun Message(data: DemoReqData.DataBean.DatasBean?) {
    Card(
        modifier = Modifier
            .background(Color.White)
            .padding(10.dp)
            .fillMaxWidth(), elevation = 10.dp
    ) {
        Column(modifier = Modifier.padding(10.dp)) {
            Text(
                text = "作者:${data?.author}"
            )
            Text(text = "${data?.title}")
        }
    }
}

Run the program, click "Request Data", the result is shown in the figure below.

 

In this way, we have realized a simple desktop data request and display function.

write at the end

Of course, there are many components in Compose For Desktop, such as Tooltips, Context Menu, etc., which cannot be introduced here one by one. We need to practice when using them. We will continue to explore in the next N bullets...

Guess you like

Origin blog.csdn.net/huangliniqng/article/details/128579499