CPSC 329 Software Development Fall 2026

CPSC 329 Lab 9: JavaFX Threads

This lab provides practice with using threads in a JavaFX program: running slow work in the background without freezing the window, dealing with results that are out of date by the time they arrive, updating the GUI from a thread that runs for the whole program, and animation.

Objectives

Successful completion of this lab means that you:

Collaboration and AI

Labs are for learning and practice — you may help and be helped by others when it comes to figuring out what to do, but in the end you need to understand and be able to do the things for yourself.

This lab can be done individually or in pairs. If you work together, use pair programming rather than splitting things up and working in parallel.

You may not use AI to figure out what to do or to do the task for you.

Due Date, Deliverables, and Handin

due Fri 11/6 at the start of class

To hand in your work:


Preliminaries

JavaFX Threads Reference

This lab handout itself and the slides and examples from class (11/2; posted on the schedule page) should be your primary reference for these exercises.

The slides contain some references for additional information and examples for Timeline.

Provided Code and Files

You have been provided with complete maze solver application. This application has some additional features beyond the simpler application used in lab 6, and the focus of this lab is the GUI (and specifically threads-related aspects of the GUI) rather than the code organization.

The files, organized by package:

The maze files are in the mazes folder.

Setup

Create an Eclipse project and share it to a local Git repository:


The Maze Solver

The maze is drawn with walls in light gray and open rooms in black. The start is the blue circle and the goal is the green circle. After solving, discovered rooms are yellow, explored rooms are orange, and the path from start to goal is a red line. Click a grid cell in the maze display to toggle a wall and drag the start or goal to move it. File → Load Maze loads a different maze. Reset clears the displayed solution.

Solving a maze of this size is actually very fast so the solver has been given some extra work to do: SolveTask.simulateWork() waits for a few milliseconds for each room explored. It stands in for an expensive computation that might be part of another application.

Work through the parts below in order. Places where you need to add code are marked with TODO comments in the provided code, labeled with the specific steps (e.g. 1a, 1b).

0. The Frozen Window

The provided Solve button works but...

1. Solving in the Background

In this part you'll move the solving into a Task so that the JavaFX application thread is free to keep the window responsive.

2. Stale Results

Now that the window stays responsive during a solve, the user can edit the maze while the task is working on its copy. By the time the result arrives, it may be the solution to a maze that no longer exists. The slides identify three strategies for this: disable the inputs, label the result, or cancel (and optionally restart) the task. Solve, Reset, and Animate are already disabled during a solve but disabling the whole maze would be annoying, so here an edit will cancel the solve. The user can press Solve again when they're done editing.

This is different from the Cancel button. There, the user decides to stop the task; here, the program stops the task because its result would be wrong.

The usual case is now handled, but there's a subtle gap. A task has finished when call returns — on the task's thread. The task then asks the JavaFX application thread to change its state to SUCCEEDED, which runs the setOnSucceeded handler. If the user's edit is handled after call returns but before that handler runs, then calling cancel() on the task has no effect (the task is already done). The setOnSucceeded handler still runs anyway, showing the stale result.

That gap is very short, so the Debug menu has an option to make the problem visible: it makes invalidateResult wait three seconds before doing anything, giving the task time to finish.

3. A Thread That Isn't a Task

A Task is for a piece of work with a result. Some threads instead run for the whole program, waiting for something to happen and then telling the GUI about it — for example, a client may have a thread that waits for messages from the server. (This will come up in project P3.) This program has a similar thread, though it waits for the user to type commands on the console rather than reading over the network.

4. Watching the Algorithm

Lab 6's maze solver showed the algorithm at work, room by room. In this part you'll add that as an animation with a Timeline.

A Timeline runs a handler at set times on the JavaFX application thread. It is made of KeyFrames, each with a time and a handler. For example:

Timeline timeline = new Timeline(new KeyFrame(Duration.millis(20),e -> ...));
timeline.setCycleCount(Animation.INDEFINITE); // repeat until stopped
timeline.play();

In this example, the handler runs 20 ms after play(), and with an indefinite cycle count, every 20 ms after that until stop(). pause() pauses the timeline and play() continues it. The rate property speeds up or slows down the timeline (2 is twice as fast).

If You Have Time

This part is optional. If you have time, add one or more of the following: