Updated Window control API and Swing interoperability tutorials.

This commit is contained in:
Roman Sedaikin
2020-12-23 13:46:48 +03:00
parent 48b66451ee
commit 5d3731cac4
4 changed files with 188 additions and 6 deletions

View File

@@ -2,7 +2,7 @@
## What is covered
In this tutorial, we will show you how to use ComposePanel in your Swing application.
In this tutorial, we will show you how to use ComposePanel and SwingPanel in your application.
## Using ComposePanel
@@ -146,4 +146,113 @@ fun Counter(text: String, counter: MutableState<Int>) {
![IntegrationWithSwing](screenshot.png)
### Note. Adding a Swing component to CFD composition is not currently supported.
## Adding a Swing component to CFD composition using SwingPanel.
SwingPanel lets you create a UI using Swing components in a Compose-based UI. To achieve this you need to create Swing component and pass it as a parameter to SwingPanel.
```kotlin
import androidx.compose.desktop.SwingPanel
import androidx.compose.desktop.Window
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.size
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import java.awt.Component
import java.awt.Dimension
import java.awt.event.ActionEvent
import java.awt.event.ActionListener
import javax.swing.BoxLayout
import javax.swing.JButton
import javax.swing.JPanel
fun main() {
Window {
val counter = remember { mutableStateOf(0) }
val inc: () -> Unit = { counter.value++ }
val dec: () -> Unit = { counter.value-- }
Box(
modifier = Modifier.fillMaxWidth().height(60.dp).padding(top = 20.dp),
contentAlignment = Alignment.Center
) {
Text("Counter: ${counter.value}")
}
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Column(
modifier = Modifier.padding(top = 80.dp, bottom = 20.dp)
) {
Button("1. Compose Button: increment", inc)
Spacer(modifier = Modifier.height(20.dp))
Box(
modifier = Modifier.size(270.dp, 90.dp)
) {
SwingPanel(
component = swingBox(dec),
background = Color.White
)
}
Spacer(modifier = Modifier.height(20.dp))
Button("2. Compose Button: increment", inc)
}
}
}
}
@Composable
fun Button(text: String = "", action: (() -> Unit)? = null) {
Button(
modifier = Modifier.size(270.dp, 30.dp),
onClick = { action?.invoke() }
) {
Text(text)
}
}
fun swingBox(action: (() -> Unit)? = null): Component {
val box = JPanel()
box.setLayout(BoxLayout(box, BoxLayout.Y_AXIS))
box.add(actionButton("1. Swing Button: decrement", action))
box.add(actionButton("2. Swing Button: decrement", action))
box.add(actionButton("3. Swing Button: decrement", action))
return box
}
fun actionButton(
text: String,
action: (() -> Unit)? = null
): JButton {
val button = JButton(text)
button.setAlignmentX(Component.CENTER_ALIGNMENT)
button.addActionListener(object : ActionListener {
public override fun actionPerformed(e: ActionEvent) {
action?.invoke()
}
})
return button
}
```
![IntegrationWithSwing](swing_panel.gif)

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 MiB

View File

@@ -75,8 +75,9 @@ Each window has 9 parameters, all of them could be omitted and have default valu
5. icon window icon
6. menuBar window context menu
7. undecorated disable native border and title bar of the window
8. events window events
9. onDismissEvent event when removing the window content from a composition
8. resizable makes the window resizable or unresizable
9. events window events
10. onDismissEvent event when removing the window content from a composition
An example of using window parameters in the creation step:
@@ -177,8 +178,9 @@ AppWindow parameters correspond to the following properties:
3. height window height
4. x position of the left top corner of the window along the X axis
5. y position of the left top corner of the window along the Y axis
6. icon window icon image
7. events window events
6. resizable - returns `true` if the window resizable, `false` otherwise
7. icon window icon image
8. events window events
To get the properties of a window, it is enough to have a link to the current or specific window. There are two ways to get the current focused window:
@@ -276,6 +278,7 @@ Using the following methods, you can change the properties of the AppWindow:
3. setLocation(x: Int, y: Int) window position
4. setWindowCentered() set the window to the center of the display
5. setIcon(image: BufferedImage?) window icon
6. setMenuBar(menuBar: MenuBar) - window menu bar
```kotlin
import androidx.compose.desktop.AppWindowAmbient
@@ -300,6 +303,76 @@ fun main() {
![Window properties](center_the_window.gif)
## Methods
Using the following methods, you can change the state of the AppWindow:
1. show(parentComposition: CompositionReference? = null, content: @Composable () -> Unit) shows a window with the given Compose content,
`parentComposition` is the parent of this window's composition.
2. close() - closes the window.
3. minimize() - minimizes the window to the taskbar. If the window is in fullscreen mode this method is ignored.
4. maximize() - maximizes the window to fill all available screen space. If the window is in fullscreen mode this method is ignored.
5. makeFullscreen() - switches the window to fullscreen mode if the window is resizable. If the window is in fullscreen mode `minimize()` and `maximize()` methods are ignored.
6. restore() - restores the normal state and size of the window after maximizing/minimizing/fullscreen mode.
You can know about window state via properties below:
1. isMinimized - returns true if the window is minimized, false otherwise.
2. isMaximized - returns true if the window is maximized, false otherwise.
3. isFullscreen - returns true if the window is in fullscreen state, false otherwise.
```kotlin
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.Spacer
import androidx.compose.desktop.AppManager
import androidx.compose.desktop.AppWindow
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import javax.swing.SwingUtilities.invokeLater
fun main() = invokeLater {
AppWindow().show {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Column(
modifier = Modifier.padding(top = 20.dp, bottom = 20.dp)
) {
Button("Minimize", { AppManager.focusedWindow?.minimize() })
Button("Maximize", { AppManager.focusedWindow?.maximize() })
Button("Fullscreen", { AppManager.focusedWindow?.makeFullscreen() })
Button("Restore", { AppManager.focusedWindow?.restore() })
Spacer(modifier = Modifier.height(20.dp))
Button("Close", { AppManager.focusedWindow?.close() })
}
}
}
}
@Composable
fun Button(text: String = "", action: (() -> Unit)? = null) {
Button(
modifier = Modifier.size(150.dp, 30.dp),
onClick = { action?.invoke() }
) {
Text(text)
}
Spacer(modifier = Modifier.height(10.dp))
}
```
![Window state](window_state.gif)
## Window events
Events can be defined using the events parameter in the window creation step or redefine using the events property at runtime.

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 MiB