Code Sketch
kojo
Category: Programming
import javax.swing._
import javax.swing.border._
import java.awt._
import java.awt.event._
import java.awt.geom._
// ============================================================
// EASY KOJO SCALA QUESTION PAPER
// 30 MINUTES / 20 QUESTIONS / EASY LEVEL
// ============================================================
val frame = new JFrame("Easy Kojo Scala - 30 Minute Easy Level Question Paper")
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE)
frame.setSize(1240, 820)
frame.setMinimumSize(new Dimension(1040, 700))
frame.setLocationRelativeTo(null)
val BG = new Color(20, 26, 38)
val PANEL = new Color(30, 39, 55)
val PANEL2 = new Color(39, 50, 69)
val TEXT = new Color(242, 245, 250)
val MUTED = new Color(180, 192, 208)
val ACCENT = new Color(88, 166, 255)
val GOOD = new Color(78, 190, 120)
val BAD = new Color(235, 95, 95)
val GOLD = new Color(245, 190, 70)
val mainPanel = new JPanel(new BorderLayout(10, 10))
mainPanel.setBackground(BG)
mainPanel.setBorder(new EmptyBorder(10, 10, 10, 10))
// ============================================================
// QUESTION BANK
// ============================================================
val questionText = Array[String](
"Complete the Kojo command: forward(______)",
"Complete the turn command so the turtle makes a right angle: right(______)",
"A square has how many sides?",
"Complete the code to draw a square using repeat: ______(4) { forward(60); right(90) }",
"The shown square has equal sides. What is the value of each angle in a square?",
"Complete the triangle code: forward(80); right(______); forward(80)",
"How many sides does the shown triangle have?",
"Which command draws a circle with radius 50?",
"Complete: val side = ______",
"Which command prints a message in Scala?",
"Complete the condition: if (score ______ 10) { println(\"Great\") }",
"Which operator means NOT EQUAL in Scala?",
"Complete the pen command that lifts the pen: ______()",
"Complete the pen command that puts the pen down: ______()",
"Which command clears the Kojo drawing?",
"Complete the position command: ______(100, 50)",
"For a loop from 1 to 5, complete: for (i <- 1 ______ 5) { println(i) }",
"Complete the function name: def ______(): Unit = { println(\"Hi\") }",
"The shown circle has how many straight sides?",
"Complete the update: var score = 0; score ______ 1"
)
val questionType = Array[Int](
0, 0, 1, 0, 1,
0, 2, 1, 0, 1,
0, 1, 0, 0, 1,
0, 0, 0, 2, 0
)
val answerKey = Array[String](
"100|100.0",
"90|90.0",
"4",
"repeat",
"90|90.0",
"120|120.0",
"3",
"circle(50)",
"50|50.0",
"println|println(\"Hello\")",
">",
"!=",
"penUp|penup",
"penDown|pendown",
"cleari|cleari()",
"setPosition(100,50)|setPosition(100, 50)",
"to",
"greet",
"0|zero",
"+="
)
val codeTemplate = Array[String](
"forward(______)\n",
"right(______)\n",
"Answer the number only.\n",
"______(4) {\n forward(60)\n right(90)\n}\n",
"Square angle = ______ degrees\n",
"forward(80)\nright(______)\nforward(80)\n",
"Look at the triangle diagram and answer the number.\n",
"______(50)\n",
"val side = ______\n",
"______(\"Hello\")\n",
"if (score ______ 10) {\n println(\"Great\")\n}\n",
"x ______ y\n",
"______()\nforward(80)\n",
"______()\nforward(80)\n",
"______()\n",
"______(100, 50)\n",
"for (i <- 1 ______ 5) {\n println(i)\n}\n",
"def ______(): Unit = {\n println(\"Hi\")\n}\n",
"Look at the circle diagram and answer the number.\n",
"var score = 0\nscore ______ 1\n"
)
val optionBank = Array[Array[String]](
Array[String](),
Array[String](),
Array[String]("3", "4", "5", "6"),
Array[String](),
Array[String]("45", "60", "90", "120"),
Array[String](),
Array[String](),
Array[String]("circle(50)", "square(50)", "drawCircle(50)", "ring(50)"),
Array[String](),
Array[String]("print", "println", "show", "echo"),
Array[String](),
Array[String]("!=", "==", "=>", "=<"),
Array[String](),
Array[String](),
Array[String]("cleari", "clearAll", "eraseAll", "clear"),
Array[String](),
Array[String](),
Array[String](),
Array[String](),
Array[String]()
)
val diagramType = Array[Int](
0, 0, 0, 0, 1,
0, 2, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 3, 0
)
// ============================================================
// STATE
// ============================================================
var currentQuestion = 0
var submitted = false
var paperFinished = false
var resultVisible = false
var secondsLeft = 30 * 60
val userAnswers = Array.fill[String](questionText.length)("")
val visited = Array.fill[Boolean](questionText.length)(false)
// ============================================================
// HEADER
// ============================================================
val titleLabel = new JLabel(
"EASY KOJO SCALA QUESTION PAPER",
SwingConstants.CENTER
)
titleLabel.setForeground(TEXT)
titleLabel.setFont(new Font("SansSerif", Font.BOLD, 28))
val subtitleLabel = new JLabel(
"Easy Level | 20 Questions | Fill in the Blanks | Simple Code | Shapes | Basic Logic",
SwingConstants.CENTER
)
subtitleLabel.setForeground(MUTED)
subtitleLabel.setFont(new Font("SansSerif", Font.PLAIN, 14))
val headerCenter = new JPanel(new GridLayout(2, 1, 2, 2))
headerCenter.setBackground(BG)
headerCenter.add(titleLabel)
headerCenter.add(subtitleLabel)
val timerLabel = new JLabel("TIME 30:00", SwingConstants.CENTER)
timerLabel.setForeground(GOLD)
timerLabel.setFont(new Font("Monospaced", Font.BOLD, 25))
timerLabel.setBorder(BorderFactory.createLineBorder(GOLD, 2))
val header = new JPanel(new BorderLayout(12, 4))
header.setBackground(BG)
header.add(headerCenter, BorderLayout.CENTER)
header.add(timerLabel, BorderLayout.EAST)
mainPanel.add(header, BorderLayout.NORTH)
// ============================================================
// INFO STRIP
// ============================================================
val infoLabel = new JLabel("Question 1 of 20 | Answer every question. The paper stops automatically at 30:00.")
infoLabel.setForeground(TEXT)
infoLabel.setFont(new Font("SansSerif", Font.BOLD, 15))
infoLabel.setBorder(BorderFactory.createEmptyBorder(8, 10, 8, 10))
infoLabel.setBackground(PANEL2)
infoLabel.setOpaque(true)
val progressLabel = new JLabel("Answered: 0 / 20", SwingConstants.RIGHT)
progressLabel.setForeground(GOOD)
progressLabel.setFont(new Font("SansSerif", Font.BOLD, 14))
val infoStrip = new JPanel(new BorderLayout())
infoStrip.setBackground(PANEL2)
infoStrip.add(infoLabel, BorderLayout.CENTER)
infoStrip.add(progressLabel, BorderLayout.EAST)
// ============================================================
// QUESTION AREA
// ============================================================
val questionTitle = new JLabel("QUESTION 1", SwingConstants.CENTER)
questionTitle.setForeground(ACCENT)
questionTitle.setFont(new Font("SansSerif", Font.BOLD, 24))
val questionTextArea = new JTextArea()
questionTextArea.setEditable(false)
questionTextArea.setLineWrap(true)
questionTextArea.setWrapStyleWord(true)
questionTextArea.setFont(new Font("SansSerif", Font.BOLD, 18))
questionTextArea.setForeground(TEXT)
questionTextArea.setBackground(PANEL)
questionTextArea.setBorder(new EmptyBorder(12, 12, 12, 12))
val codeArea = new JTextArea()
codeArea.setEditable(false)
codeArea.setFont(new Font("Monospaced", Font.PLAIN, 16))
codeArea.setForeground(new Color(190, 235, 255))
codeArea.setBackground(new Color(16, 22, 32))
codeArea.setBorder(BorderFactory.createTitledBorder(
BorderFactory.createLineBorder(new Color(70, 110, 150), 1),
"CODE / QUESTION WORK AREA"
))
val answerField = new JTextField()
answerField.setFont(new Font("SansSerif", Font.PLAIN, 19))
answerField.setBackground(new Color(248, 250, 252))
answerField.setForeground(new Color(20, 26, 38))
answerField.setToolTipText("Type your answer here")
val answerLabel = new JLabel("Your Answer:")
answerLabel.setForeground(TEXT)
answerLabel.setFont(new Font("SansSerif", Font.BOLD, 16))
val optionBox = new JComboBox[String]()
optionBox.setFont(new Font("SansSerif", Font.PLAIN, 18))
optionBox.setBackground(new Color(248, 250, 252))
optionBox.setForeground(new Color(20, 26, 38))
optionBox.setSelectedIndex(-1)
val workPanel = new JPanel(new BorderLayout(8, 8))
workPanel.setBackground(PANEL)
workPanel.setBorder(new EmptyBorder(10, 10, 10, 10))
val answerPanel = new JPanel(new BorderLayout(8, 8))
answerPanel.setBackground(PANEL)
answerPanel.add(answerLabel, BorderLayout.WEST)
answerPanel.add(answerField, BorderLayout.CENTER)
answerPanel.add(optionBox, BorderLayout.SOUTH)
workPanel.add(new JScrollPane(codeArea), BorderLayout.CENTER)
workPanel.add(answerPanel, BorderLayout.SOUTH)
val leftTop = new JPanel(new BorderLayout(8, 8))
leftTop.setBackground(PANEL)
leftTop.add(questionTitle, BorderLayout.NORTH)
leftTop.add(new JScrollPane(questionTextArea), BorderLayout.CENTER)
val leftPanel = new JPanel(new BorderLayout(8, 8))
leftPanel.setBackground(BG)
leftPanel.add(leftTop, BorderLayout.NORTH)
leftPanel.add(workPanel, BorderLayout.CENTER)
// ============================================================
// DIAGRAM PANEL
// ============================================================
val diagramPanel = new JPanel() {
override def paintComponent(g0: Graphics): Unit = {
super.paintComponent(g0)
val g = g0.asInstanceOf[Graphics2D]
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)
g.setColor(PANEL)
g.fillRect(0, 0, getWidth, getHeight)
g.setColor(TEXT)
g.setFont(new Font("SansSerif", Font.BOLD, 21))
g.drawString("SHAPE / DIAGRAM", 26, 35)
val kind = diagramType(currentQuestion)
val cx = getWidth / 2
val cy = getHeight / 2 + 15
if (kind == 1) {
g.setColor(new Color(88, 166, 255))
g.fillRoundRect(cx - 110, cy - 110, 220, 220, 14, 14)
g.setColor(TEXT)
g.setStroke(new BasicStroke(3.0f))
g.drawRoundRect(cx - 110, cy - 110, 220, 220, 14, 14)
g.setFont(new Font("SansSerif", Font.BOLD, 18))
g.drawString("SQUARE", cx - 48, cy + 145)
g.drawString("4 equal sides", cx - 65, cy + 175)
} else if (kind == 2) {
val tri = new Polygon()
tri.addPoint(cx, cy - 125)
tri.addPoint(cx - 130, cy + 105)
tri.addPoint(cx + 130, cy + 105)
g.setColor(new Color(255, 148, 82))
g.fillPolygon(tri)
g.setColor(TEXT)
g.setStroke(new BasicStroke(3.0f))
g.drawPolygon(tri)
g.setFont(new Font("SansSerif", Font.BOLD, 18))
g.drawString("TRIANGLE", cx - 57, cy + 145)
g.drawString("3 sides", cx - 35, cy + 175)
} else if (kind == 3 || kind == 4) {
g.setColor(new Color(110, 210, 150))
g.fillOval(cx - 115, cy - 115, 230, 230)
g.setColor(TEXT)
g.setStroke(new BasicStroke(3.0f))
g.drawOval(cx - 115, cy - 115, 230, 230)
g.setFont(new Font("SansSerif", Font.BOLD, 18))
g.drawString("CIRCLE", cx - 38, cy + 145)
g.drawString("0 straight sides", cx - 70, cy + 175)
} else {
g.setColor(MUTED)
g.setFont(new Font("SansSerif", Font.PLAIN, 18))
g.drawString("Diagram appears for shape questions.", 45, cy - 10)
g.drawString("Read the question and choose/fill the answer.", 45, cy + 25)
}
}
}
diagramPanel.setPreferredSize(new Dimension(360, 520))
diagramPanel.setBorder(BorderFactory.createLineBorder(new Color(65, 80, 105), 2))
val progressBar = new JProgressBar(0, questionText.length)
progressBar.setValue(0)
progressBar.setStringPainted(true)
progressBar.setForeground(ACCENT)
progressBar.setBackground(PANEL2)
val rightPanel = new JPanel(new BorderLayout(8, 8))
rightPanel.setBackground(BG)
rightPanel.add(diagramPanel, BorderLayout.CENTER)
rightPanel.add(progressBar, BorderLayout.SOUTH)
val split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftPanel, rightPanel)
split.setResizeWeight(0.73)
split.setBorder(null)
split.setDividerSize(7)
val centerPanel = new JPanel(new BorderLayout(8, 8))
centerPanel.setBackground(BG)
centerPanel.add(infoStrip, BorderLayout.NORTH)
centerPanel.add(split, BorderLayout.CENTER)
mainPanel.add(centerPanel, BorderLayout.CENTER)
// ============================================================
// BOTTOM CONTROLS
// ============================================================
val previousButton = new JButton("< Previous")
val nextButton = new JButton("Next >")
val finishButton = new JButton("FINISH PAPER")
val resultButton = new JButton("SEE YOUR RESULT")
val resetButton = new JButton("NEW PAPER")
val questionBox = new JComboBox[String]()
var qi = 1
while (qi <= questionText.length) {
questionBox.addItem("Question " + qi)
qi += 1
}
questionBox.setSelectedIndex(0)
questionBox.setFont(new Font("SansSerif", Font.BOLD, 14))
val bottomPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 8, 8))
bottomPanel.setBackground(BG)
bottomPanel.add(previousButton)
bottomPanel.add(questionBox)
bottomPanel.add(nextButton)
bottomPanel.add(finishButton)
bottomPanel.add(resultButton)
bottomPanel.add(resetButton)
mainPanel.add(bottomPanel, BorderLayout.SOUTH)
// ============================================================
// RESULT VIEW
// ============================================================
val resultArea = new JTextArea()
resultArea.setEditable(false)
resultArea.setLineWrap(true)
resultArea.setWrapStyleWord(true)
resultArea.setFont(new Font("Monospaced", Font.PLAIN, 16))
resultArea.setForeground(TEXT)
resultArea.setBackground(PANEL)
resultArea.setBorder(new EmptyBorder(16, 16, 16, 16))
val resultPanel = new JPanel(new BorderLayout(10, 10))
resultPanel.setBackground(BG)
resultPanel.setBorder(new EmptyBorder(20, 20, 20, 20))
val resultTitle = new JLabel("YOUR RESULT", SwingConstants.CENTER)
resultTitle.setForeground(GOLD)
resultTitle.setFont(new Font("SansSerif", Font.BOLD, 30))
resultPanel.add(resultTitle, BorderLayout.NORTH)
resultPanel.add(new JScrollPane(resultArea), BorderLayout.CENTER)
// ============================================================
// HELPERS
// ============================================================
def cleanAnswer(s: String): String = {
s.toLowerCase
.trim
.replace("`", "")
.replace(" ", "")
.replace("\t", "")
.replace("\r", "")
.replace("\n", "")
}
def isCorrect(index: Int): Boolean = {
val got = cleanAnswer(userAnswers(index))
val accepted = answerKey(index).split("\\|")
var i = 0
var ok = false
while (i < accepted.length) {
if (got == cleanAnswer(accepted(i))) {
ok = true
}
i += 1
}
ok
}
def answeredCount(): Int = {
var count = 0
var i = 0
while (i < userAnswers.length) {
if (userAnswers(i).trim.nonEmpty) count += 1
i += 1
}
count
}
def formatTime(sec: Int): String = {
val minutes = sec / 60
val seconds = sec % 60
val mm = if (minutes < 10) "0" + minutes else minutes.toString
val ss = if (seconds < 10) "0" + seconds else seconds.toString
mm + ":" + ss
}
def updateTimerLabel(): Unit = {
timerLabel.setText("TIME " + formatTime(secondsLeft))
if (secondsLeft <= 60) {
timerLabel.setForeground(BAD)
} else {
timerLabel.setForeground(GOLD)
}
}
def saveCurrentAnswer(): Unit = {
if (!paperFinished) {
if (optionBox.isVisible) {
val selected = optionBox.getSelectedItem
if (selected != null) {
userAnswers(currentQuestion) = selected.toString
}
} else {
userAnswers(currentQuestion) = answerField.getText
}
visited(currentQuestion) = true
}
}
def updateProgress(): Unit = {
val count = answeredCount()
progressLabel.setText("Answered: " + count + " / " + questionText.length)
progressBar.setValue(count)
progressBar.setString(count + " answered")
}
def showQuestion(index: Int): Unit = {
if (index < 0 || index >= questionText.length) return
saveCurrentAnswer()
currentQuestion = index
questionTitle.setText("QUESTION " + (currentQuestion + 1))
questionTextArea.setText(questionText(currentQuestion))
codeArea.setText(codeTemplate(currentQuestion))
infoLabel.setText("Question " + (currentQuestion + 1) + " of " + questionText.length + " | EASY LEVEL | Read the code and diagram carefully.")
if (optionBank(currentQuestion).length > 0) {
optionBox.removeAllItems()
var j = 0
while (j < optionBank(currentQuestion).length) {
optionBox.addItem(optionBank(currentQuestion)(j))
j += 1
}
optionBox.setVisible(true)
answerField.setVisible(false)
answerLabel.setText("Choose:")
val old = userAnswers(currentQuestion)
if (old.nonEmpty) {
var k = 0
while (k < optionBank(currentQuestion).length) {
if (optionBank(currentQuestion)(k) == old) optionBox.setSelectedIndex(k)
k += 1
}
} else {
optionBox.setSelectedIndex(-1)
}
} else {
optionBox.setVisible(false)
answerField.setVisible(true)
answerLabel.setText("Your Answer:")
answerField.setText(userAnswers(currentQuestion))
SwingUtilities.invokeLater(new Runnable {
def run(): Unit = {
if (!paperFinished && !resultVisible) answerField.requestFocusInWindow()
}
})
}
diagramPanel.repaint()
updateProgress()
workPanel.revalidate()
workPanel.repaint()
}
def buildResultText(): String = {
var correct = 0
var wrong = 0
var unanswered = 0
var i = 0
val sb = new StringBuilder()
while (i < questionText.length) {
if (userAnswers(i).trim.isEmpty) {
unanswered += 1
} else if (isCorrect(i)) {
correct += 1
} else {
wrong += 1
}
i += 1
}
val total = questionText.length
val percent = (correct.toDouble * 100.0) / total.toDouble
sb.append("==============================================\n")
sb.append(" EASY KOJO SCALA RESULT\n")
sb.append("==============================================\n\n")
sb.append("Total Questions : " + total + "\n")
sb.append("Correct : " + correct + "\n")
sb.append("Wrong : " + wrong + "\n")
sb.append("Unanswered : " + unanswered + "\n")
sb.append("Score : " + correct + " / " + total + "\n")
sb.append("Percentage : " + (Math.round(percent * 100.0) / 100.0) + "%\n")
sb.append("Time Left : " + formatTime(secondsLeft) + "\n")
sb.append("\n----------------------------------------------\n")
sb.append("WRONG / UNANSWERED REVIEW\n")
sb.append("----------------------------------------------\n")
i = 0
while (i < questionText.length) {
if (!isCorrect(i)) {
sb.append("\nQuestion " + (i + 1) + ": " + questionText(i) + "\n")
sb.append("Your Answer : " + (if (userAnswers(i).trim.isEmpty) "Not answered" else userAnswers(i)) + "\n")
sb.append("Correct Ans : " + answerKey(i).replace("|", " / ") + "\n")
}
i += 1
}
sb.append("\n----------------------------------------------\n")
sb.append("NOTE: This is a beginner practice paper based on simple Kojo/Scala concepts.\n")
sb.append("Keep practicing commands, shapes, variables, conditions, loops and functions.\n")
sb.append("==============================================\n")
sb.toString
}
def showResult(): Unit = {
if (!paperFinished) return
resultVisible = true
resultArea.setText(buildResultText())
centerPanel.removeAll()
centerPanel.add(resultPanel, BorderLayout.CENTER)
centerPanel.revalidate()
centerPanel.repaint()
infoLabel.setText("RESULT READY - You can start a new paper from the NEW PAPER button.")
previousButton.setEnabled(false)
nextButton.setEnabled(false)
questionBox.setEnabled(false)
finishButton.setEnabled(false)
resultButton.setEnabled(false)
answerField.setEnabled(false)
optionBox.setEnabled(false)
}
def finishPaper(): Unit = {
if (paperFinished) return
saveCurrentAnswer()
paperFinished = true
submitted = true
secondsLeft = Math.max(0, secondsLeft)
updateTimerLabel()
answerField.setEnabled(false)
optionBox.setEnabled(false)
previousButton.setEnabled(false)
nextButton.setEnabled(false)
questionBox.setEnabled(false)
finishButton.setEnabled(false)
resultButton.setEnabled(true)
infoLabel.setText("PAPER STOPPED. Press SEE YOUR RESULT to open the full result report.")
}
def resetPaper(): Unit = {
var i = 0
while (i < userAnswers.length) {
userAnswers(i) = ""
visited(i) = false
i += 1
}
currentQuestion = 0
submitted = false
paperFinished = false
resultVisible = false
secondsLeft = 30 * 60
answerField.setEnabled(true)
optionBox.setEnabled(true)
previousButton.setEnabled(true)
nextButton.setEnabled(true)
questionBox.setEnabled(true)
finishButton.setEnabled(true)
resultButton.setEnabled(false)
centerPanel.removeAll()
centerPanel.add(infoStrip, BorderLayout.NORTH)
centerPanel.add(split, BorderLayout.CENTER)
centerPanel.revalidate()
centerPanel.repaint()
showQuestion(0)
updateTimerLabel()
updateProgress()
}
// ============================================================
// LISTENERS
// ============================================================
previousButton.addActionListener(new ActionListener {
override def actionPerformed(e: ActionEvent): Unit = {
if (!paperFinished && currentQuestion > 0) {
showQuestion(currentQuestion - 1)
}
}
})
nextButton.addActionListener(new ActionListener {
override def actionPerformed(e: ActionEvent): Unit = {
if (!paperFinished) {
saveCurrentAnswer()
if (currentQuestion < questionText.length - 1) {
showQuestion(currentQuestion + 1)
}
}
}
})
questionBox.addActionListener(new ActionListener {
override def actionPerformed(e: ActionEvent): Unit = {
if (!paperFinished) {
val selected = questionBox.getSelectedIndex
if (selected >= 0 && selected < questionText.length && selected != currentQuestion) {
showQuestion(selected)
}
}
}
})
finishButton.addActionListener(new ActionListener {
override def actionPerformed(e: ActionEvent): Unit = {
val confirm = JOptionPane.showConfirmDialog(
frame,
"Finish the paper now? You can then see your result.",
"Finish Paper",
JOptionPane.YES_NO_OPTION
)
if (confirm == JOptionPane.YES_OPTION) {
finishPaper()
}
}
})
resultButton.addActionListener(new ActionListener {
override def actionPerformed(e: ActionEvent): Unit = {
showResult()
}
})
resetButton.addActionListener(new ActionListener {
override def actionPerformed(e: ActionEvent): Unit = {
resetPaper()
}
})
answerField.addKeyListener(new KeyAdapter {
override def keyReleased(e: KeyEvent): Unit = {
if (!paperFinished) {
userAnswers(currentQuestion) = answerField.getText
visited(currentQuestion) = true
updateProgress()
}
}
})
optionBox.addActionListener(new ActionListener {
override def actionPerformed(e: ActionEvent): Unit = {
if (!paperFinished) {
val selected = optionBox.getSelectedItem
if (selected != null) {
userAnswers(currentQuestion) = selected.toString
visited(currentQuestion) = true
updateProgress()
}
}
}
})
// ============================================================
// KEYBOARD SHORTCUTS
// ============================================================
mainPanel.setFocusable(true)
mainPanel.addKeyListener(new KeyAdapter {
override def keyPressed(e: KeyEvent): Unit = {
if (!paperFinished) {
if (e.getKeyCode == KeyEvent.VK_RIGHT && currentQuestion < questionText.length - 1) {
saveCurrentAnswer()
showQuestion(currentQuestion + 1)
} else if (e.getKeyCode == KeyEvent.VK_LEFT && currentQuestion > 0) {
saveCurrentAnswer()
showQuestion(currentQuestion - 1)
}
}
}
})
// ============================================================
// TIMER - EXACTLY 30 MINUTES
// ============================================================
val paperTimer = new javax.swing.Timer(1000, new ActionListener {
override def actionPerformed(e: ActionEvent): Unit = {
if (!paperFinished) {
secondsLeft -= 1
if (secondsLeft <= 0) {
secondsLeft = 0
updateTimerLabel()
e.getSource.asInstanceOf[javax.swing.Timer].stop()
JOptionPane.showMessageDialog(
frame,
"30 minutes are over. The paper is now closed.\nPress SEE YOUR RESULT.",
"TIME UP",
JOptionPane.INFORMATION_MESSAGE
)
finishPaper()
} else {
updateTimerLabel()
}
}
}
})
// ============================================================
// INITIAL STATE / STARTUP
// ============================================================
resultButton.setEnabled(false)
showQuestion(0)
updateTimerLabel()
updateProgress()
frame.setContentPane(mainPanel)
frame.setVisible(true)
frame.toFront()
frame.requestFocus()
mainPanel.requestFocusInWindow()
paperTimer.start()