diff --git a/.idea/dictionaries/project.xml b/.idea/dictionaries/project.xml
new file mode 100644
index 0000000..531ae63
--- /dev/null
+++ b/.idea/dictionaries/project.xml
@@ -0,0 +1,7 @@
+
+
+
+ msksbr
+
+
+
\ No newline at end of file
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
index 76dcf82..f53b6f6 100644
--- a/.idea/gradle.xml
+++ b/.idea/gradle.xml
@@ -11,6 +11,7 @@
+
diff --git a/lesson3/build.gradle.kts b/lesson3/build.gradle.kts
new file mode 100644
index 0000000..fc57a4a
--- /dev/null
+++ b/lesson3/build.gradle.kts
@@ -0,0 +1,23 @@
+plugins {
+ kotlin("jvm")
+}
+
+group = "com.msksbr.jfxLearn"
+version = "unspecified"
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ testImplementation(kotlin("test"))
+}
+
+tasks.test {
+ useJUnitPlatform()
+}
+kotlin {
+ jvmToolchain(17)
+}
+
+application.mainClass.set("com.msksbr.jfxLearn.lesson3.MainKt")
\ No newline at end of file
diff --git a/lesson3/src/main/kotlin/Main.kt b/lesson3/src/main/kotlin/Main.kt
new file mode 100644
index 0000000..49c9671
--- /dev/null
+++ b/lesson3/src/main/kotlin/Main.kt
@@ -0,0 +1,100 @@
+/*
+ * Lesson: Stage
+ */
+
+package com.msksbr.jfxLearn.lesson3
+
+import javafx.application.Application
+import javafx.scene.Scene
+import javafx.scene.control.Alert
+import javafx.scene.control.Button
+import javafx.scene.control.Label
+import javafx.scene.image.Image
+import javafx.scene.input.KeyCode
+import javafx.scene.input.KeyEvent
+import javafx.scene.layout.AnchorPane
+import javafx.scene.layout.BorderPane
+import javafx.stage.Modality
+import javafx.stage.Stage
+import javafx.stage.StageStyle
+
+class MainApplication : Application() {
+ override fun start(stage: Stage?) {
+ val label = Label("Hello Kotlin\nPress G to view event test dialog")
+ val button0 = Button("APPLICATION MODAL")
+ button0.layoutX = 100.0
+ button0.layoutY = 100.0
+ val button1 = Button("WINDOW MODAL")
+ button1.layoutX = 100.0
+ button1.layoutY = 130.0
+ val button2 = Button("NONE MODAL")
+ button2.layoutX = 100.0
+ button2.layoutY = 160.0
+ val anchorPane = AnchorPane(label, button0, button1, button2)
+ val scene = Scene(anchorPane)
+
+ // modality test window
+ val label0 = Label("stage 0, APPLICATION_MODAL")
+ val borderPane0 = BorderPane(label0)
+ val scene0 = Scene(borderPane0, 300.0, 300.0)
+ val stage0 = Stage()
+ stage0.scene = scene0
+
+ val label1 = Label("stage 1, WINDOW_MODAL")
+ val borderPane1 = BorderPane(label1)
+ val scene1 = Scene(borderPane1, 300.0, 300.0)
+ val stage1 = Stage()
+ stage1.scene = scene1
+
+ val label2 = Label("stage 2, NONE_MODAL")
+ val borderPane2 = BorderPane(label2)
+ val scene2 = Scene(borderPane2, 300.0, 300.0)
+ val stage2 = Stage()
+ stage2.scene = scene2
+
+ // 1, title: set window title
+ stage?.title = "lesson3"
+ // 2, icons: set window icon
+ stage?.icons?.add(Image("mskbot.png"))
+ // 3, isResizable: set window size adjustable
+ stage?.isResizable = false
+ // 4. x, y, width and height
+ // x,y is omitted
+ stage?.width = 300.0
+ stage?.height = 300.0
+ // 5. style:
+ // DECORATED: default on current operating system
+ // UNDECORATED: non-border window
+ // TRANSPARENT: transparent background and non-border, complete transparent, but ONLY THIS STAGE IS TRANSPARENT
+ // UTILITY: only close button and title, just like a dialog
+ stage?.initStyle(StageStyle.DECORATED)
+ // 6. modality
+ // when application modal selected, other stage of this application can't use
+ stage0.initModality(Modality.APPLICATION_MODAL)
+ stage1.initModality(Modality.WINDOW_MODAL)
+ // when window modal selected, it's own stage can't use
+ stage1.initOwner(stage)
+ // default and normal modal option
+ stage2.initModality(Modality.NONE)
+ button0.setOnAction { stage0.show() }
+ button1.setOnAction { stage1.show() }
+ button2.setOnAction { stage2.show() }
+ // 7. event
+ stage?.addEventHandler(KeyEvent.KEY_PRESSED) { event ->
+ if (event.code == KeyCode.G) {
+ Alert(Alert.AlertType.CONFIRMATION).apply {
+ title = "event test"
+ headerText = null
+ contentText = "event test"
+ }.show()
+ }
+ }
+
+ stage?.scene = scene
+ stage?.show()
+ }
+}
+
+fun main(args: Array) {
+ Application.launch(MainApplication::class.java, *args)
+}
\ No newline at end of file
diff --git a/lesson3/src/main/resources/mskbot.png b/lesson3/src/main/resources/mskbot.png
new file mode 100644
index 0000000..e9aa2ce
Binary files /dev/null and b/lesson3/src/main/resources/mskbot.png differ
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 763f9ac..9451388 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -1,3 +1,4 @@
rootProject.name = "jfx-learn"
include("lesson1")
-include("lesson2")
\ No newline at end of file
+include("lesson2")
+include("lesson3")
\ No newline at end of file