Skip to content

Commit 9e77182

Browse files
Merge pull request #23 from spbu-coding-2022/feature/TreeGUI
Переработка GUI
2 parents b5dd73e + b5e7695 commit 9e77182

File tree

16 files changed

+276
-172
lines changed

16 files changed

+276
-172
lines changed

App/src/main/kotlin/app/App.kt

Lines changed: 154 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,22 @@ import exceptions.NodeNotFoundException
77
import guiClasses.components.Frame
88
import guiClasses.components.KeyTextField
99
import guiClasses.components.MenuClass
10-
import guiClasses.components.nodePanels.AVLPanel
11-
import guiClasses.components.nodePanels.BTPanel
12-
import guiClasses.components.nodePanels.RBTPanel
10+
import guiClasses.components.TreePanel
11+
import guiControl.painters.AVLPainter
12+
import guiControl.painters.BTPainter
13+
import guiControl.painters.RBTPainter
1314
import trees.AVLTree
1415
import trees.BinaryTree
1516
import trees.RBTree
17+
import java.awt.event.ComponentAdapter
18+
import java.awt.event.ComponentEvent
1619
import java.io.File
1720
import javax.swing.GroupLayout
1821
import javax.swing.JButton
1922
import javax.swing.JFrame
2023
import javax.swing.JOptionPane
2124

25+
2226
/**
2327
* Объект, хранящий отдельно каждое из деревьев
2428
* (позволяет параллельно работать сразу со всеми)
@@ -39,9 +43,20 @@ enum class TreeTypes {
3943
None
4044
}
4145

46+
/**
47+
* Константы с сообщениями ошибок, именами файлов бд
48+
*/
4249
object Constants {
4350
const val BinaryBaseName = "Binary Tree Data.db"
4451
const val RBTBaseName = "Red-Black Tree Data.yml"
52+
53+
const val NotFoundErrorMessage = "Tree node with such key not found"
54+
const val NotChosenErrorMessage = "You must select a tree to perform this action"
55+
const val AlreadyExistsErrorMessage = "Tree node with the same key already exists"
56+
const val InputErrorMessage = "Entered value is not a number or is too large"
57+
const val DataReadError = "Unable to read data from file"
58+
const val TreeAlreadyClearErrorMessage = "There are no more nodes in tree"
59+
4560
}
4661

4762
/**
@@ -50,10 +65,19 @@ object Constants {
5065
private var currentTree: TreeTypes = TreeTypes.None
5166

5267
private lateinit var treeFrame: JFrame
68+
private lateinit var treePanel: TreePanel
69+
5370
private lateinit var menuFrame: JFrame
5471
fun main() {
72+
treeFrameInit()
5573
menuFrameInit()
74+
loadDatabase()
75+
}
5676

77+
/**
78+
* Вытаскивает деревья из баз данных
79+
*/
80+
private fun loadDatabase() {
5781
if (File(Constants.RBTBaseName).exists()) {
5882
try {
5983
val base = RBTBase(Constants.RBTBaseName,
@@ -68,7 +92,7 @@ fun main() {
6892

6993
Trees.RBTree = base.loadTree()
7094
} catch (ex: Exception) {
71-
showError("Не удалось прочитать данных из файла ${Constants.RBTBaseName}", menuFrame)
95+
showMessage(Constants.DataReadError)
7296
}
7397
}
7498
if (File(Constants.BinaryBaseName).exists()) {
@@ -85,37 +109,90 @@ fun main() {
85109

86110
Trees.binTree = base.loadTree()
87111
} catch (ex: Exception) {
88-
showError("Не удалось прочитать данных из файла ${Constants.BinaryBaseName}", menuFrame)
112+
showMessage(Constants.DataReadError)
89113
}
90114
}
91115
}
92116

93-
private fun treeInit(newTree: TreeTypes) {
94-
if (::treeFrame.isInitialized)
95-
treeFrame.dispose()
117+
private fun treeFrameInit() {
96118
treeFrame = Frame("Treeple", 1000, 700, 360, 50)
97-
when (newTree) {
98-
TreeTypes.RB -> treeFrame.add(RBTPanel(Trees.RBTree))
99-
TreeTypes.AVL -> treeFrame.add(AVLPanel(Trees.AVLTree))
100-
TreeTypes.BINARY -> treeFrame.add(BTPanel(Trees.binTree))
101-
else -> return
119+
treePanel = TreePanel()
120+
treeFrame.add(treePanel)
121+
122+
treeFrame.addComponentListener(object : ComponentAdapter() {
123+
override fun componentResized(componentEvent: ComponentEvent) {
124+
treeRepaint()
125+
}
126+
})
127+
128+
Trees.binTree.run {
129+
add(100)
130+
add(120)
131+
add(-10)
132+
}
133+
134+
Trees.RBTree.run {
135+
add(100)
136+
add(120)
137+
add(-10)
138+
}
139+
140+
Trees.AVLTree.run {
141+
add(100)
142+
add(120)
143+
add(-10)
102144
}
103-
println(newTree)
104-
currentTree = newTree
105145

106146
}
107147

148+
/**
149+
* Выводит сообщение об ошибке на экран
150+
*/
151+
private fun showMessage(text: String, frame: JFrame = menuFrame, messageType: Int = JOptionPane.ERROR_MESSAGE) {
152+
JOptionPane.showMessageDialog(frame, text, "An error has occurred", messageType)
153+
}
154+
155+
private fun treeRepaint() {
156+
when (currentTree) {
157+
TreeTypes.BINARY -> {
158+
if (Trees.binTree.root == null) {
159+
treePanel.clearTree()
160+
return
161+
}
162+
val painter = BTPainter(Trees.binTree, width = treeFrame.width)
163+
treePanel.changeTree(painter.lines, painter.nodes)
164+
}
165+
166+
TreeTypes.AVL -> {
167+
if (Trees.AVLTree.root == null) {
168+
treePanel.clearTree()
169+
return
170+
}
171+
val painter = AVLPainter(Trees.AVLTree, width = treeFrame.width)
172+
treePanel.changeTree(painter.lines, painter.nodes)
173+
}
108174

175+
TreeTypes.RB -> {
176+
if (Trees.RBTree.root == null) {
177+
treePanel.clearTree()
178+
return
179+
}
180+
val painter = RBTPainter(Trees.RBTree, width = treeFrame.width)
181+
treePanel.changeTree(painter.lines, painter.nodes)
182+
}
109183

110-
private fun showError(text: String, frame: JFrame) {
111-
JOptionPane.showMessageDialog(frame, text, "Произошла ошибка", JOptionPane.ERROR_MESSAGE)
184+
else -> {}
185+
}
112186
}
113187

188+
/**
189+
* Заполняет menuFrame компонентами
190+
*/
114191
private fun menuFrameInit() {
115192
menuFrame = Frame("Treeple Menu", 300, 400, 50, 50)
116193

117194
val addButton = JButton("Add")
118-
val addTextField = KeyTextField()
195+
val addTextField = KeyTextField(addButton)
119196

120197
addButton.addActionListener {
121198
if (addTextField.text.toIntOrNull() != null) {
@@ -126,18 +203,21 @@ private fun menuFrameInit() {
126203
TreeTypes.BINARY -> Trees.binTree.add(key)
127204
TreeTypes.AVL -> Trees.AVLTree.add(key)
128205

129-
else -> showError("Сначала выберите дерево", menuFrame)
206+
else -> showMessage(Constants.NotChosenErrorMessage)
130207
}
131208

132209
} catch (ex: NodeAlreadyExistsException) {
133-
showError("Узел с таким значением уже существует", menuFrame)
210+
showMessage(Constants.AlreadyExistsErrorMessage)
134211
}
135212
} else
136-
showError("Добавлять можно только узлы с числовыми значениями", menuFrame)
213+
showMessage(Constants.InputErrorMessage)
214+
215+
addTextField.text = ""
216+
treeRepaint()
137217
}
138218

139219
val removeButton = JButton("Remove")
140-
val removeTextField = KeyTextField()
220+
val removeTextField = KeyTextField(removeButton)
141221

142222
removeButton.addActionListener {
143223
if (removeTextField.text.toIntOrNull() != null) {
@@ -148,21 +228,48 @@ private fun menuFrameInit() {
148228
TreeTypes.BINARY -> Trees.binTree.remove(key)
149229
TreeTypes.AVL -> Trees.AVLTree.remove(key)
150230

151-
else -> showError("Сначала выберите дерево", menuFrame)
231+
else -> showMessage(Constants.NotChosenErrorMessage)
152232
}
153233

154234
} catch (ex: NodeNotFoundException) {
155-
showError("Узла с таким значением не существует", menuFrame)
235+
showMessage(Constants.NotFoundErrorMessage)
156236
}
157237
} else
158-
showError("Добавлять можно только узлы с числовыми значениями", menuFrame)
238+
showMessage(Constants.InputErrorMessage)
239+
240+
removeTextField.text = ""
241+
treeRepaint()
159242
}
160243

161244
val saveButton = JButton("Save")
162-
val refreshButton = JButton("Refresh")
245+
val clearButton = JButton("Clear")
163246

164-
refreshButton.addActionListener {
165-
treeInit(currentTree)
247+
clearButton.addActionListener {
248+
when (currentTree) {
249+
TreeTypes.RB -> {
250+
if (Trees.RBTree.root == null)
251+
showMessage(Constants.TreeAlreadyClearErrorMessage)
252+
else
253+
Trees.RBTree = RBTree()
254+
}
255+
256+
TreeTypes.BINARY -> {
257+
if (Trees.binTree.root == null)
258+
showMessage(Constants.TreeAlreadyClearErrorMessage)
259+
else
260+
Trees.binTree = BinaryTree()
261+
}
262+
263+
TreeTypes.AVL -> {
264+
if (Trees.AVLTree.root == null)
265+
showMessage(Constants.TreeAlreadyClearErrorMessage)
266+
else
267+
Trees.AVLTree = AVLTree()
268+
}
269+
270+
else -> showMessage(Constants.NotChosenErrorMessage)
271+
}
272+
treeRepaint()
166273
}
167274

168275
saveButton.addActionListener {
@@ -195,14 +302,27 @@ private fun menuFrameInit() {
195302
}
196303

197304
TreeTypes.AVL -> {
198-
showError("Сохранение AVL дерева не реализовано", menuFrame)
305+
showMessage("AVL tree saving is not implemented ;(")
199306
}
200307

201-
else -> showError("Сначала выберите дерево", menuFrame)
308+
else -> showMessage(Constants.NotChosenErrorMessage)
202309
}
203310
}
204311

205-
menuFrame.jMenuBar = MenuClass(::treeInit)
312+
menuFrame.jMenuBar = MenuClass(
313+
onBinSelected = {
314+
currentTree = TreeTypes.BINARY
315+
treeRepaint()
316+
},
317+
onAVLSelected = {
318+
currentTree = TreeTypes.AVL
319+
treeRepaint()
320+
},
321+
onRBTSelected = {
322+
currentTree = TreeTypes.RB
323+
treeRepaint()
324+
}
325+
)
206326

207327
// contentPane - контейнер для компонентов
208328
val layout = GroupLayout(menuFrame.contentPane)
@@ -228,7 +348,7 @@ private fun menuFrameInit() {
228348
)
229349
)
230350
.addComponent(saveButton)
231-
.addComponent(refreshButton)
351+
.addComponent(clearButton)
232352
)
233353

234354
layout.setVerticalGroup(
@@ -249,9 +369,9 @@ private fun menuFrameInit() {
249369
.addGroup(
250370
layout.createSequentialGroup()
251371
.addComponent(saveButton)
252-
.addComponent(refreshButton)
372+
.addComponent(clearButton)
253373
)
254374

255375
)
256376

257-
}
377+
}

App/src/main/kotlin/guiClasses/components/KeyTextField.kt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
package guiClasses.components
22

3+
import javax.swing.JButton
34
import javax.swing.JTextField
45

5-
class KeyTextField() : JTextField() {
6+
class KeyTextField(
7+
private val button: JButton
8+
) : JTextField() {
69

710
private val textField = JTextField("Key")
811
init {
912
textField.also {
1013
addActionListener {
11-
text = "" }
14+
button.doClick()
15+
}
1216
}
1317

1418
add(textField)

App/src/main/kotlin/guiClasses/components/MenuClass.kt

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
package guiClasses.components
22

3-
import app.TreeTypes
43
import java.awt.Color
54
import javax.swing.JMenu
65
import javax.swing.JMenuBar
76
import javax.swing.JMenuItem
87

98
class MenuClass(
10-
private val onTreeSelected: (type: TreeTypes) -> Unit
9+
private val onBinSelected: () -> Unit,
10+
private val onAVLSelected: () -> Unit,
11+
private val onRBTSelected: () -> Unit
12+
1113
) : JMenuBar() {
1214

1315
/**
@@ -25,7 +27,7 @@ class MenuClass(
2527
menuItems.filter { it != item }.forEach { it.background = Color.WHITE }
2628
}
2729

28-
private val menu = JMenu("Выбор Дерева")
30+
private val menu = JMenu("Tree select")
2931
private val menuItems = arrayOf(
3032
JMenuItem("Binary Tree"),
3133
JMenuItem("AVL-Tree"),
@@ -39,19 +41,19 @@ class MenuClass(
3941
// Слушатель событий для элемента меню "Binary Tree"
4042
menuItems[0].addActionListener {
4143
updateMenuItemsChoosing(menuItems[0])
42-
onTreeSelected(TreeTypes.BINARY)
44+
onBinSelected()
4345
}
4446

4547
// Слушатель событий для элемента меню "AVL-Tree"
4648
menuItems[1].addActionListener {
4749
updateMenuItemsChoosing(menuItems[1])
48-
onTreeSelected(TreeTypes.AVL)
50+
onAVLSelected()
4951
}
5052

5153
// Слушатель событий для элемента меню "Red-black Tree"
5254
menuItems[2].addActionListener {
5355
updateMenuItemsChoosing(menuItems[2])
54-
onTreeSelected(TreeTypes.RB)
56+
onRBTSelected()
5557
}
5658

5759
add(menu)

0 commit comments

Comments
 (0)