You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

305 lines
9.0 KiB

# Tray and menu notification
## What is covered
In this guide, we'll show you how to work with system tray, create application menu bar and create window specific menu bar, and send system notifications using Compose for Desktop.
## Tray
You can add an application icon into the system tray. Using Tray, you can also send notifications to the user. There are 3 types of notifications:
1. notify - simple notification
2. warn - warning notification
3. error - error notification
```kotlin
import androidx.compose.desktop.AppManager
import androidx.compose.desktop.Window
4 years ago
import androidx.compose.foundation.Text
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.onActive
import androidx.compose.runtime.onDispose
4 years ago
import androidx.compose.ui.Alignment
import androidx.compose.ui.window.MenuItem
import androidx.compose.ui.window.Tray
4 years ago
import androidx.compose.ui.Modifier
import java.awt.Color
import java.awt.Graphics2D
import java.awt.image.BufferedImage
fun main() {
4 years ago
val count = mutableStateOf(0)
4 years ago
Window(
icon = getMyAppIcon()
) {
onActive {
val tray = Tray().apply {
4 years ago
icon(getTrayIcon())
menu(
4 years ago
MenuItem(
name = "Increment value",
onClick = {
4 years ago
count.value++
}
),
4 years ago
MenuItem(
name = "Send notification",
onClick = {
4 years ago
notify("Notification", "Message from MyApp!")
}
),
4 years ago
MenuItem(
name = "Exit",
onClick = {
AppManager.exit()
}
)
)
}
onDispose {
tray.remove()
}
}
4 years ago
// content
Box(
modifier = Modifier.fillMaxSize(),
alignment = Alignment.Center
) {
Text(text = "Value: ${count.value}")
}
}
}
4 years ago
fun getMyAppIcon() : BufferedImage {
4 years ago
val size = 256
val image = BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB)
val graphics = image.createGraphics()
graphics.setColor(Color.green)
graphics.fillOval(size / 4, 0, size / 2, size)
graphics.setColor(Color.blue)
graphics.fillOval(0, size / 4, size, size / 2)
graphics.setColor(Color.red)
graphics.fillOval(size / 4, size / 4, size / 2, size / 2)
graphics.dispose()
return image
}
fun getTrayIcon() : BufferedImage {
4 years ago
val size = 256
val image = BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB)
val graphics = image.createGraphics()
graphics.setColor(Color.orange)
graphics.fillOval(0, 0, size, size)
graphics.dispose()
return image
}
```
4 years ago
![Tray](tray.gif)
## Notifier
You can send system notifications with Notifier without using the system tray.
Notifier also has 3 types of notifications:
1. notify - simple notification
2. warn - warning notification
3. error - error notification
```kotlin
import androidx.compose.desktop.Window
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.Text
import androidx.compose.material.Button
import androidx.compose.ui.window.Notifier
4 years ago
import java.awt.Color
import java.awt.Graphics2D
import java.awt.image.BufferedImage
fun main() {
val message = "Some message!"
4 years ago
val notifier = Notifier()
4 years ago
Window(
icon = getMyAppIcon()
) {
Column {
4 years ago
Button(onClick = { notifier.notify("Notification.", message) }) {
Text(text = "Notify")
}
4 years ago
Button(onClick = { notifier.warn("Warning.", message) }) {
Text(text = "Warning")
}
4 years ago
Button(onClick = { notifier.error("Error.", message) }) {
Text(text = "Error")
}
}
}
}
4 years ago
fun getMyAppIcon() : BufferedImage {
val size = 256
val image = BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB)
val graphics = image.createGraphics()
graphics.setColor(Color.green)
graphics.fillOval(size / 4, 0, size / 2, size)
graphics.setColor(Color.blue)
graphics.fillOval(0, size / 4, size, size / 2)
graphics.setColor(Color.red)
graphics.fillOval(size / 4, size / 4, size / 2, size / 2)
graphics.dispose()
return image
}
```
4 years ago
![Notifier](notifier.gif)
## MenuBar
MenuBar is used to create and customize the common context menu of the application or any particular window.
To create a common context menu for all application windows, you need to configure the AppManager.
```kotlin
import androidx.compose.desktop.AppManager
import androidx.compose.desktop.Window
4 years ago
import androidx.compose.foundation.Text
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.Alignment
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.Modifier
import androidx.compose.ui.window.KeyStroke
import androidx.compose.ui.window.MenuItem
import androidx.compose.ui.window.Menu
import androidx.compose.ui.window.MenuBar
fun main() {
4 years ago
val action = mutableStateOf("Last action: None")
AppManager.setMenu(
MenuBar(
Menu(
name = "Actions",
4 years ago
MenuItem(
name = "About",
4 years ago
onClick = { action.value = "Last action: About (Command + I)" },
shortcut = KeyStroke(Key.I)
),
4 years ago
MenuItem(
name = "Exit",
onClick = { AppManager.exit() },
4 years ago
shortcut = KeyStroke(Key.X)
)
),
Menu(
name = "File",
4 years ago
MenuItem(
name = "Copy",
4 years ago
onClick = { action.value = "Last action: Copy (Command + C)" },
shortcut = KeyStroke(Key.C)
),
4 years ago
MenuItem(
name = "Paste",
4 years ago
onClick = { action.value = "Last action: Paste (Command + V)" },
shortcut = KeyStroke(Key.V)
)
)
)
)
Window {
// content
4 years ago
Box(
modifier = Modifier.fillMaxSize(),
alignment = Alignment.Center
) {
Text(text = action.value)
}
}
}
```
4 years ago
![Application MenuBar](app_menubar.gif)
You can to create a MenuBar for a specific window (while others will use the common MenuBar, if defined).
```kotlin
import androidx.compose.desktop.AppManager
import androidx.compose.desktop.Window
4 years ago
import androidx.compose.foundation.Text
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.Button
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.Alignment
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.Modifier
import androidx.compose.ui.window.KeyStroke
import androidx.compose.ui.window.MenuItem
import androidx.compose.ui.window.Menu
import androidx.compose.ui.window.MenuBar
4 years ago
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.IntSize
fun main() {
4 years ago
val action = mutableStateOf("Last action: None")
Window(
menuBar = MenuBar(
Menu(
name = "Actions",
4 years ago
MenuItem(
name = "About",
4 years ago
onClick = { action.value = "Last action: About (Command + I)" },
shortcut = KeyStroke(Key.I)
),
4 years ago
MenuItem(
name = "Exit",
onClick = { AppManager.exit() },
4 years ago
shortcut = KeyStroke(Key.X)
)
),
Menu(
name = "File",
4 years ago
MenuItem(
name = "Copy",
4 years ago
onClick = { action.value = "Last action: Copy (Command + C)" },
shortcut = KeyStroke(Key.C)
),
4 years ago
MenuItem(
name = "Paste",
4 years ago
onClick = { action.value = "Last action: Paste (Command + V)" },
shortcut = KeyStroke(Key.V)
)
)
)
) {
// content
4 years ago
Button(
onClick = {
Window(
title = "Another window",
size = IntSize(350, 200),
location = IntOffset(100, 100),
centered = false
) {
}
}
) {
Text(text = "New window")
}
Box(
modifier = Modifier.fillMaxSize(),
alignment = Alignment.Center
) {
Text(text = action.value)
}
}
}
```
4 years ago
![Window MenuBar](window_menubar.gif)