Browse Source

Fixed tutorials.

pull/15/head
Roman Sedaikin 4 years ago
parent
commit
43d9ad87ec
  1. 163
      tutorials/Tray_Notifications_MenuBar/TrayNotifierMenuBar.md
  2. BIN
      tutorials/Tray_Notifications_MenuBar/app_menubar.gif
  3. BIN
      tutorials/Tray_Notifications_MenuBar/notifier.gif
  4. BIN
      tutorials/Tray_Notifications_MenuBar/tray.gif
  5. BIN
      tutorials/Tray_Notifications_MenuBar/window_menubar.gif
  6. 229
      tutorials/Window_API/WindowManagement.md
  7. BIN
      tutorials/Window_API/center_the_window.gif
  8. BIN
      tutorials/Window_API/current_window.gif
  9. BIN
      tutorials/Window_API/focus_the_window.gif
  10. BIN
      tutorials/Window_API/scaling_factor.jpg
  11. BIN
      tutorials/Window_API/window_attr.gif

163
tutorials/Tray_Notifications_MenuBar/TrayNotifierMenuBar.md

@ -15,30 +15,40 @@ You can add an application icon into the system tray. Using Tray, you can also s
```kotlin ```kotlin
import androidx.compose.desktop.AppManager import androidx.compose.desktop.AppManager
import androidx.compose.desktop.Window import androidx.compose.desktop.Window
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.onActive
import androidx.compose.runtime.onDispose import androidx.compose.runtime.onDispose
import androidx.compose.ui.window.Item import androidx.compose.ui.Alignment
import androidx.compose.ui.window.MenuItem
import androidx.compose.ui.window.Tray import androidx.compose.ui.window.Tray
import androidx.compose.ui.Modifier
import java.awt.Color
import java.awt.Graphics2D
import java.awt.image.BufferedImage
fun main() { fun main() {
val count = mutableStateOf(0)
Window { Window {
onActive { onActive {
val tray = Tray().apply { val tray = Tray().apply {
icon(getImageIcon()) // custom function that returns BufferedImage icon(getMyAppIcon())
menu( menu(
Item( MenuItem(
name = "About", name = "Increment value",
onClick = { onClick = {
println("This is MyApp") count.value++
} }
), ),
Item( MenuItem(
name = "Send notification", name = "Send notification",
onClick = { onClick = {
tray.notify("Notification", "Message from MyApp!") notify("Notification", "Message from MyApp!")
} }
), ),
Item( MenuItem(
name = "Exit", name = "Exit",
onClick = { onClick = {
AppManager.exit() AppManager.exit()
@ -50,10 +60,30 @@ fun main() {
tray.remove() tray.remove()
} }
} }
// content
Box(
modifier = Modifier.fillMaxSize(),
alignment = Alignment.Center
) {
Text(text = "Value: ${count.value}")
}
}
} }
fun getMyAppIcon() : BufferedImage {
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
} }
``` ```
![Tray](tray.gif)
## Notifier ## Notifier
You can send system notifications with Notifier without using the system tray. You can send system notifications with Notifier without using the system tray.
Notifier also has 3 types of notifications: Notifier also has 3 types of notifications:
@ -71,15 +101,16 @@ import androidx.compose.ui.window.Notifier
fun main() { fun main() {
val message = "Some message!" val message = "Some message!"
val notifier = Notifier()
Window { Window {
Column { Column {
Button(onClick = { Notifier().notify("Notification.", message) }) { Button(onClick = { notifier.notify("Notification.", message) }) {
Text(text = "Notify") Text(text = "Notify")
} }
Button(onClick = { Notifier().warn("Warning.", message) }) { Button(onClick = { notifier.warn("Warning.", message) }) {
Text(text = "Warning") Text(text = "Warning")
} }
Button(onClick = { Notifier().error("Error.", message) }) { Button(onClick = { notifier.error("Error.", message) }) {
Text(text = "Error") Text(text = "Error")
} }
} }
@ -87,6 +118,8 @@ fun main() {
} }
``` ```
![Notifier](notifier.gif)
## MenuBar ## MenuBar
MenuBar is used to create and customize the common context menu of the application or any particular window. MenuBar is used to create and customize the common context menu of the application or any particular window.
@ -95,39 +128,47 @@ To create a common context menu for all application windows, you need to configu
```kotlin ```kotlin
import androidx.compose.desktop.AppManager import androidx.compose.desktop.AppManager
import androidx.compose.desktop.Window import androidx.compose.desktop.Window
import androidx.compose.ui.window.Item import androidx.compose.foundation.Text
import androidx.compose.ui.window.keyStroke 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.Menu
import androidx.compose.ui.window.MenuBar import androidx.compose.ui.window.MenuBar
import java.awt.event.KeyEvent
fun main() { fun main() {
AppManager.menu( val action = mutableStateOf("Last action: None")
AppManager.setMenu(
MenuBar( MenuBar(
Menu( Menu(
name = "Actions", name = "Actions",
Item( MenuItem(
name = "About", name = "About",
onClick = { println("This is MyApp") }, onClick = { action.value = "Last action: About (Command + I)" },
shortcut = keyStroke(KeyEvent.VK_I) shortcut = KeyStroke(Key.I)
), ),
Item( MenuItem(
name = "Exit", name = "Exit",
onClick = { AppManager.exit() }, onClick = { AppManager.exit() },
shortcut = keyStroke(KeyEvent.VK_X) shortcut = KeyStroke(Key.X)
) )
), ),
Menu( Menu(
name = "File", name = "File",
Item( MenuItem(
name = "Copy", name = "Copy",
onClick = { println("Copy operation.") }, onClick = { action.value = "Last action: Copy (Command + C)" },
shortcut = keyStroke(KeyEvent.VK_C) shortcut = KeyStroke(Key.C)
), ),
Item( MenuItem(
name = "Paste", name = "Paste",
onClick = { println("Paste operation.") }, onClick = { action.value = "Last action: Paste (Command + V)" },
shortcut = keyStroke(KeyEvent.VK_V) shortcut = KeyStroke(Key.V)
) )
) )
) )
@ -135,54 +176,94 @@ fun main() {
Window { Window {
// content // content
Box(
modifier = Modifier.fillMaxSize(),
alignment = Alignment.Center
) {
Text(text = action.value)
}
} }
} }
``` ```
You can to create a MenuBar for a specific window (the rest of the windows will use the common MenuBar, if defined). ![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 ```kotlin
import androidx.compose.desktop.AppManager import androidx.compose.desktop.AppManager
import androidx.compose.desktop.Window import androidx.compose.desktop.Window
import androidx.compose.ui.window.Item import androidx.compose.foundation.Text
import androidx.compose.ui.window.keyStroke 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.Menu
import androidx.compose.ui.window.MenuBar import androidx.compose.ui.window.MenuBar
import java.awt.event.KeyEvent import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.IntSize
fun main() { fun main() {
val action = mutableStateOf("Last action: None")
Window( Window(
menuBar = MenuBar( menuBar = MenuBar(
Menu( Menu(
name = "Actions", name = "Actions",
Item( MenuItem(
name = "About", name = "About",
onClick = { println("This is MyApp") }, onClick = { action.value = "Last action: About (Command + I)" },
shortcut = keyStroke(KeyEvent.VK_I) shortcut = KeyStroke(Key.I)
), ),
Item( MenuItem(
name = "Exit", name = "Exit",
onClick = { AppManager.exit() }, onClick = { AppManager.exit() },
shortcut = keyStroke(KeyEvent.VK_X) shortcut = KeyStroke(Key.X)
) )
), ),
Menu( Menu(
name = "File", name = "File",
Item( MenuItem(
name = "Copy", name = "Copy",
onClick = { println("Copy operation.") }, onClick = { action.value = "Last action: Copy (Command + C)" },
shortcut = keyStroke(KeyEvent.VK_C) shortcut = KeyStroke(Key.C)
), ),
Item( MenuItem(
name = "Paste", name = "Paste",
onClick = { println("Paste operation.") }, onClick = { action.value = "Last action: Paste (Command + V)" },
shortcut = keyStroke(KeyEvent.VK_V) shortcut = KeyStroke(Key.V)
) )
) )
) )
) { ) {
// content // content
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)
}
} }
} }
``` ```
![Window MenuBar](window_menubar.gif)

BIN
tutorials/Tray_Notifications_MenuBar/app_menubar.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 MiB

BIN
tutorials/Tray_Notifications_MenuBar/notifier.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 MiB

BIN
tutorials/Tray_Notifications_MenuBar/tray.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 MiB

BIN
tutorials/Tray_Notifications_MenuBar/window_menubar.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 MiB

229
tutorials/Window_API/WindowManagement.md

@ -6,7 +6,7 @@ In this guide, we'll show you how to work with windows using Compose for Desktop
## Windows creation ## Windows creation
The main class for creating windows is AppWindow. The easiest way to create and launch a new window is to use an instance of the AppWindow class and call its method show(). You can see an example below: The main class for creating windows is AppWindow. The easiest way to create and launch a new window is to use an instance of the AppWindow class and call its method `show()`. You can see an example below:
```kotlin ```kotlin
import androidx.compose.desktop.AppWindow import androidx.compose.desktop.AppWindow
@ -18,15 +18,16 @@ fun main() {
} }
``` ```
There are two types of windows - modal and active. Below are functions for creating each type of window: There are two types of windows - modal and regular. Below are functions for creating each type of window:
1. Window - active window type. 1. Window - regular window type.
2. Dialog - modal window type. Such a window locks its parent window until the user completes working with it and closes the modal window. 2. Dialog - modal window type. Such a window locks its parent window until the user completes working with it and closes the modal window.
You can see an example for both types of windows below. You can see an example for both types of windows below.
```kotlin ```kotlin
import androidx.compose.desktop.Window import androidx.compose.desktop.Window
import androidx.compose.foundation.Text
import androidx.compose.material.Button import androidx.compose.material.Button
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
@ -36,7 +37,9 @@ fun main() {
Window { Window {
val dialogState = remember { mutableStateOf(false) } val dialogState = remember { mutableStateOf(false) }
Button(onClick = { dialogState.value = true }) Button(onClick = { dialogState.value = true }) {
Text(text = "Open dialog")
}
if (dialogState.value) { if (dialogState.value) {
Dialog( Dialog(
@ -51,7 +54,7 @@ fun main() {
## Window attributes ## Window attributes
Each window has 9 parameters listed below: Each window has 9 parameters listed below, all of them could be omitted and have default values:
1. title - window title 1. title - window title
2. size - initial window size 2. size - initial window size
@ -66,33 +69,94 @@ Each window has 9 parameters listed below:
An example of using window parameters at the creation step: An example of using window parameters at the creation step:
```kotlin ```kotlin
import androidx.compose.desktop.AppManager
import androidx.compose.desktop.Window import androidx.compose.desktop.Window
import androidx.compose.desktop.WindowEvents import androidx.compose.desktop.WindowEvents
import androidx.compose.foundation.Text
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
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.unit.IntOffset import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.IntSize import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.window.MenuItem
import androidx.compose.ui.window.KeyStroke
import androidx.compose.ui.window.Menu
import androidx.compose.ui.window.MenuBar
import java.awt.Color
import java.awt.Graphics2D
import java.awt.image.BufferedImage
fun main() { fun main() {
val count = mutableStateOf(0)
val windowPos = mutableStateOf(IntOffset.Zero)
Window( Window(
title = "MyApp", title = "MyApp",
size = IntSize(800, 600), size = IntSize(400, 250),
location = IntOffset(200, 200), location = IntOffset(100, 100),
centered = false, // true - by default centered = false, // true - by default
icon = getMyAppIcon(), // custom function that returns BufferedImage icon = getMyAppIcon(),
menuBar = getMyAppMenuBar(), // custom function that returns MenuBar menuBar = MenuBar(
Menu(
name = "Actions",
MenuItem(
name = "Increment value",
onClick = {
count.value++
},
shortcut = KeyStroke(Key.I)
),
MenuItem(
name = "Exit",
onClick = { AppManager.exit() },
shortcut = KeyStroke(Key.X)
)
)
),
undecorated = true, // false - by default undecorated = true, // false - by default
events = WindowEvents( events = WindowEvents(
onOpen = { println("OnOpen") }, onRelocate = { location ->
... // here may be other events windowPos.value = location
onResize = { size ->
println("Size: $size")
} }
) )
) { ) {
// content // content
Box(
modifier = Modifier.fillMaxSize(),
alignment = Alignment.Center
) {
Column {
Text(text = "Location: ${windowPos.value} Value: ${count.value}")
Button(
onClick = {
AppManager.exit()
}
) {
Text(text = "Close app")
}
}
}
} }
} }
fun getMyAppIcon() : BufferedImage {
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
}
``` ```
![Window attributes](window_attr.gif)
## Window properties ## Window properties
AppWindow parameters correspond to the following properties: AppWindow parameters correspond to the following properties:
@ -112,17 +176,40 @@ To get the properties of a window, it is enough to have a link to the current or
```kotlin ```kotlin
import androidx.compose.desktop.AppWindowAmbient import androidx.compose.desktop.AppWindowAmbient
import androidx.compose.desktop.Window import androidx.compose.desktop.Window
import androidx.compose.foundation.Text
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
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.Modifier
import androidx.compose.ui.unit.IntOffset
fun main() { fun main() {
val windowPos = mutableStateOf(IntOffset.Zero)
Window { Window {
val current = AppWindowAmbient.current val current = AppWindowAmbient.current
// content
Box(
modifier = Modifier.fillMaxSize(),
alignment = Alignment.Center
) {
Column {
Text(text = "Location: ${windowPos.value}")
Button( Button(
onClick = { onClick = {
if (current != null) { if (current != null) {
println("Title: ${current.title} ${current.x} ${current.y}") windowPos.value = IntOffset(current.x, current.y)
}
}
) {
Text(text = "Print window location")
}
} }
} }
)
} }
} }
``` ```
@ -132,21 +219,45 @@ fun main() {
```kotlin ```kotlin
import androidx.compose.desktop.AppManager import androidx.compose.desktop.AppManager
import androidx.compose.desktop.Window import androidx.compose.desktop.Window
import androidx.compose.foundation.Text
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
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.Modifier
import androidx.compose.ui.unit.IntOffset
fun main() { fun main() {
val windowPos = mutableStateOf(IntOffset.Zero)
Window { Window {
// content
Box(
modifier = Modifier.fillMaxSize(),
alignment = Alignment.Center
) {
Column {
Text(text = "Location: ${windowPos.value}")
Button( Button(
onClick = { onClick = {
val current = AppManager.getCurrentFocusedWindow() val current = AppManager.focusedWindow
if (current != null) { if (current != null) {
println("Title: ${current.title} ${current.x} ${current.y}") windowPos.value = IntOffset(current.x, current.y)
}
}
) {
Text(text = "Print window location")
}
} }
} }
)
} }
} }
``` ```
![Window properties](current_window.gif)
Using the following methods, one can change the properties of AppWindow: Using the following methods, one can change the properties of AppWindow:
1. setTitle(title: String) - window title 1. setTitle(title: String) - window title
@ -158,21 +269,29 @@ Using the following methods, one can change the properties of AppWindow:
```kotlin ```kotlin
import androidx.compose.desktop.AppWindowAmbient import androidx.compose.desktop.AppWindowAmbient
import androidx.compose.desktop.Window import androidx.compose.desktop.Window
import androidx.compose.foundation.Text
import androidx.compose.material.Button
fun main() { fun main() {
Window { Window {
val current = AppWindowAmbient.current val current = AppWindowAmbient.current
// content
Button( Button(
onClick = { onClick = {
if (current != null) { if (current != null) {
current.setWindowCentered() current.setWindowCentered()
} }
} }
) ) {
Text(text = "Center the window")
}
} }
} }
``` ```
![Window properties](center_the_window.gif)
## Window events ## Window events
Events could be defined using the events parameter at the window creation step or redefine using the events property at runtime. Events could be defined using the events parameter at the window creation step or redefine using the events property at runtime.
@ -191,71 +310,113 @@ Actions can be assigned to the following window events:
```kotlin ```kotlin
import androidx.compose.desktop.Window import androidx.compose.desktop.Window
import androidx.compose.desktop.WindowEvents import androidx.compose.desktop.WindowEvents
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.Modifier
import androidx.compose.ui.unit.IntSize
fun main() { fun main() {
val windowSize = mutableStateOf(IntSize.Zero)
val focused = mutableStateOf(false)
Window( Window(
events = WindowEvents( events = WindowEvents(
onOpen = { println("OnOpen") }, onFocusGet = { focused.value = true },
... // here may be other events onFocusLost = { focused.value = false },
onResize = { size -> onResize = { size ->
println("Size: $size") windowSize.value = size
} }
) )
) { ) {
// content // content
Box(
modifier = Modifier.fillMaxSize(),
alignment = Alignment.Center
) {
Text(text = "Size: ${windowSize.value} Focused: ${focused.value}")
}
} }
} }
``` ```
![Window events](focus_the_window.gif)
## AppManager ## AppManager
The AppManager class is used to customize the behavior of the entire application. Its main features: The AppManager singleton is used to customize the behavior of the entire application. Its main features:
1. Description of common application events 1. Description of common application events
```kotlin ```kotlin
AppManager.onEvent( AppManager.setEvents(
onAppStart = { println("OnAppStart") }, onAppStart = { println("onAppStart") }, // invoked before the first window is created
onAppExit = { println("OnAppExit") } onAppExit = { println("onAppExit") } // invoked after all windows are closed
) )
``` ```
2. Customization of common application context menu 2. Customization of common application context menu
```kotlin ```kotlin
AppManager.menu( AppManager.setMenu(
getCommonAppMenuBar() // custom function that returns MenuBar getCommonAppMenuBar() // custom function that returns MenuBar
) )
``` ```
3. Access to the application windows list 3. Access to the application windows list
```kotlin ```kotlin
val windows = AppManager.getWindows() val windows = AppManager.windows
``` ```
4. Getting the current focused window 4. Getting the current focused window
```kotlin ```kotlin
val current = AppManager.getCurrentFocusedWindow() val current = AppManager.focusedWindow
``` ```
5. Application exit 5. Application exit
```kotlin ```kotlin
AppManager.exit() // closes all windows AppManager.exit() // closes all windows
``` ```
## Access to javax.swing components ## Access to Swing components
Compose for Desktop uses Swing components as the window system. For more detailed customization, you can access the JFrame (Swing window representation): Compose for Desktop is tightly integrated with Swing on the level of top level windows. For more detailed customization, you can access the JFrame (Swing window representation):
```kotlin ```kotlin
import androidx.compose.desktop.AppManager import androidx.compose.desktop.AppManager
import androidx.compose.desktop.Window import androidx.compose.desktop.Window
import androidx.compose.foundation.Text
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
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.Modifier
fun main() { fun main() {
val scaleFactor = mutableStateOf(0.0)
Window { Window {
// content
Box(
modifier = Modifier.fillMaxSize(),
alignment = Alignment.Center
) {
Column {
Button( Button(
onClick = { onClick = {
val current = AppManager.getCurrentFocusedWindow() val current = AppManager.focusedWindow
if (current != null) { if (current != null) {
val jFrame = current.window val jFrame = current.window
// do whatever you want with it, for example add some new listeners // do whatever you want with it
scaleFactor.value = jFrame.graphicsConfiguration.defaultTransform.scaleX
}
}
) {
Text(text = "Check display scaling factor")
}
Text(text = "Scaling factor: ${scaleFactor.value}}")
} }
} }
)
} }
} }
``` ```
![Access to Swing components](scaling_factor.jpg)

BIN
tutorials/Window_API/center_the_window.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 MiB

BIN
tutorials/Window_API/current_window.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 MiB

BIN
tutorials/Window_API/focus_the_window.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 MiB

BIN
tutorials/Window_API/scaling_factor.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 KiB

BIN
tutorials/Window_API/window_attr.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 MiB

Loading…
Cancel
Save