0% found this document useful (0 votes)
2 views52 pages

Unit 9 - Event Driven Programming

Unit 9 focuses on event-driven programming in JavaFX, detailing how to describe events, event sources, and handler classes. It explains the process of registering handlers with event sources to respond to user actions like mouse clicks and keystrokes. The unit also covers various coding styles, including the use of inner classes, anonymous inner classes, and lambda expressions for handling events.

Uploaded by

Cookies Hang
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2 views52 pages

Unit 9 - Event Driven Programming

Unit 9 focuses on event-driven programming in JavaFX, detailing how to describe events, event sources, and handler classes. It explains the process of registering handlers with event sources to respond to user actions like mouse clicks and keystrokes. The unit also covers various coding styles, including the use of inner classes, anonymous inner classes, and lambda expressions for handling events.

Uploaded by

Cookies Hang
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Unit 9: Event-Driven Programming

Unit Goals

• To describe events, event sources, and event classes


• To define handler classes, register handler objects with the
source object, and write the code to handle events
• To explore various coding styles for creating and registering
handler classes
• To handle MouseEvents
• To handle KeyEvents

2
Event-Driven Programming

Recall: JavaFX Basics

• So far we’ve learned about the basic GUI classes (e.g.,


shapes, UI controls) and how to arrange them in window

• A big missing piece: interaction

• To have a GUI interact with a user, we have to use event-


driven programming to write the code to respond to the
user actions (e.g., button click, mouse movement and
keystroke).

3
Event-Driven Programming

Big Picture

When GUI elements want to implement event-driven programming,


they will offer ways to “handle” an event via a class that implements
an interface.

Typical sequence:
1) Create GUI
2) “Register” a class to handle event(s), sometime referred to as a
“listener”
3) Implement handling code in the listener

4
Event-Driven Programming

• Event-driven programming allow a program to respond to


user-generated events such as clicking a button, inputting
text in the text field, or moving a mouse.

• To respond to an event, we need to establish the


connection between the event source object, and the
object that capable of handling the event (event handler or
event listener)

5
Event Handling Model

• The are many types of event defined in JavaFX. For examples:


ActionEvent, MouseEvent, KeyEvent, etc.
• To handle a specific type of event, XEvent, two things are needed:
1. The event handler (listener) object must implement the
corresponding event-handler interface EventHandler<XEvent>.
The handler interface contains the handle(XEvent e) method
for processing the event.
2. The handler object must be registered with the event source object
using the method [Link](listener)

2
1
6
Event Handling Example: ActionEvent
• For example, when a button is clicked, an ActionEvent is fired, the event
listener must
1. implement the EventHandler<ActionEvent> interface:
class CustomListener implements EventHandler<ActionEvent> {
public void handle(ActionEvent e) {
[Link]("OK button clicked");
} }

2. use setOnAction(listener) to register the event listener with


the button:
CustomeListener handler1 = new CustomeListener();
Button btOK = new Button("OK");
[Link](handler1);

7
ActionEvent Example 1/5

public class HandleEvent extends Application {


@Override //override the start method in the Application
class
public void start(Stage primaryStage) {

OKHandlerClass handler1 = new OKHandlerClass();
[Link](handler1);

1. Declare and

create the
[Link]();
ActionEvent
}
}
handler object

class OKHandlerClass implements EventHandler<ActionEvent>


{
@Override
public void handle(ActionEvent e) {
[Link]("OK button clicked");
}
} 8
ActionEvent Example 2/5

public class HandleEvent extends Application {


public void start(Stage primaryStage) {

OKHandlerClass handler1 = new OKHandlerClass();
[Link](handler1);

… 2. Register the
[Link](); handler with the
} button object
}

class OKHandlerClass implements


EventHandler<ActionEvent> {
@Override
public void handle(ActionEvent e) {
[Link]("OK button clicked");
}
}
9
ActionEvent Example 3/5

public class HandleEvent extends Application {


public void start(Stage primaryStage) { 3. Start from the
… application and
OKHandlerClass handler1 = new OKHandlerClass();
display the button
[Link](handler1); in a window


[Link]();
}
}

class OKHandlerClass implements


EventHandler<ActionEvent> {
@Override
public void handle(ActionEvent e) {
[Link]("OK button clicked");
}
}
10
ActionEvent Example 4/5

public class HandleEvent extends Application {


public void start(Stage primaryStage) { 4. Click OK

OKHandlerClass handler1 = new OKHandlerClass();
[Link](handler1);


[Link]();
}
}

class OKHandlerClass implements


EventHandler<ActionEvent> {
@Override
public void handle(ActionEvent e) {
[Link]("OK button clicked");
}
}
11
ActionEvent Example 5/5

public class HandleEvent extends Application {


public void start(Stage primaryStage) {5. Click OK. The
… JVM invokes the
listener’s handle()
OKHandlerClass handler1 = new OKHandlerClass();
[Link](handler1); method


[Link]();
}
}

class OKHandlerClass implements


EventHandler<ActionEvent> {
@Override
public void handle(ActionEvent e) {
[Link]("OK button clicked");
}
}
12
[Link] 1/2
// other imports
import [Link].*;

public class HandleEvent extends Application {


@Override // Override the start method in the Application class
public void start(Stage primaryStage) {
// Create a pane and set its properties
HBox pane = new HBox(10);
[Link](new Insets(15));
[Link]([Link]);
Button btOK = new Button("OK");
Button btCancel = new Button("Cancel");
OKHandlerClass handler1 = new OKHandlerClass();
[Link](handler1);
CancelHandlerClass handler2 = new CancelHandlerClass();
[Link](handler2);
[Link]().addAll(btOK, btCancel);

// Create a scene and place it in the stage


Scene scene = new Scene(pane);
[Link]("HandleEvent"); // Set the stage title
[Link](scene); // Place the scene in the stage
[Link](); // Display the stage
}

13
[Link] 2/2
public static void main(String[] args) {
launch(args);
}

class OKHandlerClass implements EventHandler<ActionEvent> {


@Override
public void handle(ActionEvent e) {
[Link]("OK button clicked");
}
Inner Class
} Handlers
class CancelHandlerClass implements EventHandler<ActionEvent> {
@Override
public void handle(ActionEvent e) {
[Link]("Cancel button clicked");
}
}

14
Inner Class
• A handler class is designed specifically to create a handler
object for a GUI component (e.g., a button).
• It will not be shared by other applications. So, it is
appropriate to define the handler class inside the main
class as an inner class.
• An inner class, or nested class, is a class defined within the
scope of another class.
• An inner class can directly reference the data and methods
defined in the outer class in which it nests. So, in some
cases, you can use an inner class to make a program
simpler.

15
Events

• An event can be defined as a type of signal to the


program that something has happened.
• An event is an object created from an event source.
• The event is generated by external user actions such as
mouse movements, mouse clicks, and keystrokes.
• The program can choose to respond to or ignore an
event.

16
Event Classes
• An event object contains whatever properties are pertinent to the event.
• You can identify the source object of an event using the getSource().

17
Selected User Actions and Associated Event Handlers

18
[Link] 1/2
public class ControlCircle extends Application {
private Circle circle = new Circle(50);

@Override // Override the start method in the Application class


public void start(Stage primaryStage) {
// Hold two buttons in an HBox
HBox hBox = new HBox();
[Link](10);
[Link]([Link]);
Button btEnlarge = new Button("Enlarge");
Button btShrink = new Button("Shrink");
[Link]().add(btEnlarge);
[Link]().add(btShrink);

// Create and register the handler


[Link](new EnlargeHandler());

BorderPane borderPane = new BorderPane();


[Link](circle);
[Link](hBox);
[Link](hBox, [Link]);

19
[Link] 2/2

// Create a scene and place it in the stage


Scene scene = new Scene(borderPane, 250, 200);
[Link]("ControlCircle"); // Set the stage title
[Link](scene); // Place the scene in the stage
[Link](); // Display the stage
}

public static void main(String[] args) {


launch(args);
}

class EnlargeHandler implements EventHandler<ActionEvent> {


@Override // Override the handle method
public void handle(ActionEvent e) {
[Link]([Link]() + 2);
}
}
}

20
Handling Multiple Events using getSource()
public class ControlCircle2 extends Application {
private Button btEnlarge = new Button("Enlarge");
private Button btShrink = new Button("Shrink");
private Circle circle = new Circle(50);

@Override // Override the start method in the Application class


public void start(Stage primaryStage) {
// Hold two buttons in an HBox
HBox hBox = new HBox();
[Link](10);
[Link]([Link]);
[Link]().add(btEnlarge);
[Link]().add(btShrink);

// Create and register the handler


ButtonHandler handler = new ButtonHandler();
[Link](handler);
[Link](handler);

BorderPane borderPane = new BorderPane();


[Link](circle);
[Link](hBox);
[Link](hBox, [Link]);

21
Handling Multiple Events using getSource()
// Create a scene and place it in the stage
Scene scene = new Scene(borderPane, 250, 200);
[Link]("ControlCircle"); // Set the stage title
[Link](scene); // Place the scene in the stage
[Link](); // Display the stage
}

public static void main(String[] args) {


launch(args);
}

class ButtonHandler implements EventHandler<ActionEvent> {


@Override // Override the handle method
public void handle(ActionEvent e) {
if([Link]() == btEnlarge)
[Link]([Link]() + 2);
else if ([Link]() == btShrink)
[Link]([Link]() > 2 ?
[Link]() - 2 : [Link]());
// shortcut if-else

}
}
} The Conditional expression’s Syntax:
Boolean-expression ? expression1 : expression2;
22
Anonymous Inner Class Handlers
• Inner-class handlers can be shortened using anonymous inner
classes.
• An anonymous inner class is an inner class without a name. It
combines defining an inner class and creating an instance of the
class into one step.
– An anonymous inner class must always extend a superclass or
implement an interface.

23
Lambda Expression
• Lambda expressions is a new feature in Java 8. It can be used to
greatly simplify coding for event handling.
• Lambda expressions can be viewed as an anonymous method with
a concise syntax. The statements in the lambda expression is all for
that method.
• So, for the compiler to understand lambda expressions, the interface
must contain exactly one abstract method. Such an interface is
known a Single Abstract Method (SAM) interface.

[Link]( [Link](e -> {


new EventHandler<ActionEvent>() { // Code for processing event e
@Override });
public void handle(ActionEvent e) {
// Code for processing event e
}
}
});

(a) Anonymous inner class event handler (b) Lambda expression event handler

24
[Link]
public class LambdaHandlerDemo extends Application {
@Override // Override the start method in the Application class
public void start(Stage primaryStage) {
// Hold two buttons in an HBox
HBox hBox = new HBox();
[Link](10);
[Link]([Link]);
Button btNew = new Button("New");
Button btOpen = new Button("Open");
Button btSave = new Button("Save");
Button btPrint = new Button("Print");
[Link]().addAll(btNew, btOpen, btSave, btPrint);

// Create and register the handler


[Link]((ActionEvent e) -> {
[Link]("Process New");
});

[Link]((e) -> {
[Link]("Process Open");
});

[Link](e -> { // often use


[Link]("Process Save");
});

[Link](e -> [Link]("Process Print"));


25
[Link]

// Create a scene and place it in the stage


Scene scene = new Scene(hBox, 300, 50);
[Link]("LambdaHandlerDemo"); // Set title
[Link](scene); // Place the scene in the stage
[Link](); // Display the stage
}

/**
* The main method is only needed for the IDE with limited
* JavaFX support. Not needed for running from the command line.
*/
public static void main(String[] args) {
launch(args);
}
}

26
JavaFX UI Controls
• JavaFX provides many UI controls for developing a comprehensive
user interface. We have seen several UI controls such as Button,
Label, and TextField. Here we will introduce some more frequently
used UI controls.

27
Label
• A Label is a display area for a short text, a node, or both. It is often
used to label other controls (usually text fields).
• Constructors:
Label() // creates an empty label
Label(String text) // creates a label with the specified text
Label(String text, Node graphic) // creates a label with text and graphic

• Examples:
Label lb = new Label("First Name: ");
ImageView us = new ImageView("[Link]");
Label lb1 = new Label("US 50 States", us);
[Link]("-fx-border-color: green; -fx-border-width: 2");
[Link]([Link]); // bottom of text
[Link]([Link]);

Note: ImageView is used for displaying an image.


The image file "[Link]" must be in the same directory as the class file
28
Button
• A Button is a control that triggers an ActionEvent when clicked.
• JavaFX provides regular buttons, check box buttons, and radio
buttons.
• Constructors:
Button() // creates an empty button
Button(String text) // creates a button with the specified text
Button(String text, Node graphic) // creates a button with text and graphic

• Examples:
Button btLeft = new Button("Left", new ImageView("[Link]"));
Button btCenter = new Button("Center");
[Link](30);
Button btRight = new Button("Right", new ImageView("[Link]"));

29
CheckBox
• A CheckBox is used for the user to make a selection.
• When a check box is clicked (checked or unchecked), it fires an
ActionEvent. To see if a check box is selected, use the
isSelected() method.
• Constructors:
CheckBox() // creates an empty check box
CheckBox(String text) // creates a check box with the specified text

• Examples:
CheckBox chkBold = new CheckBox("Bold");
CheckBox chkItalic = new CheckBox("Italic");
[Link](true);
[Link](true);

[Link](true); // disable the check box

30
RadioButton
• RadioButtons, also known as option buttons, enable the user to
choose a single item from a group of choices.
• To group radio buttons, you need to create an instance of
ToggleGroup and use setToggleGoup() method to set a radio
button’s toggleGroup property to join the group.
• When a radio button is changed (selected or deselected), it fires an
ActionEvent. To see if a radio button is selected, use the
isSelected() method.
• Examples:
RadioButton rbRed = new RadioButton("Red");
RadioButton rbGreen = new RadioButton("Green");
RadioButton rbBlue = new RadioButton("Blue");

ToggleGroup group = new ToggleGroup();


[Link](group);
[Link](group);
[Link](group);
31
TextField
• A TextField can be used to enter or display a string.
• When you move the cursor in the text field and press the Enter key,
it fires an ActionEvent.
• Use getText() method to retrieve the string entered by the user,
and then use [Link]() or [Link]()
to convert to numerical value if needed.
• Constructors:
TextField() // creates an empty text field
TextField(String text) // creates a text field with the specified
text

• Examples:
TextField tf = new TextField(“Testing");
[Link](false); // false = noneditable
[Link]([Link]("Times", 20));
double val = [Link]([Link]());

32
UI Controls Demo

Top (BorderPane)
TextField Center
Text

Left (Vbox)
RadioButton Right (Vbox)
CheckBox

Bottom (HBox)
Button

33
[Link] 1/5
public class UIControlsDemo extends Application {
@Override // Override the start method in the Application class
public void start(Stage primaryStage) {

BorderPane pane = new BorderPane(); // border pane to hold all

// center: text
Text text = new Text(50, 50, "JavaFX Programming");
[Link]([Link]("Times New Roman", [Link],
[Link], 20) );
Pane paneForText = new Pane();
[Link]().add(text);
[Link](paneForText);

// bottom: buttons
HBox paneForButtons = new HBox(20);
Button btLeft = new Button("Left", new ImageView("images/[Link]"));
Button btRight = new Button("Right", new ImageView("images/[Link]"));
[Link]().addAll(btLeft, btRight);
[Link]([Link]);
[Link]("-fx-border-color: green");
[Link](paneForButtons);

[Link](e -> [Link]([Link]() - 10)); // event handlers


[Link](e -> [Link]([Link]() + 10));

34
[Link] 2/5
// top: text field
BorderPane paneForTextField = new BorderPane();
[Link](new Insets(5));
[Link]("-fx-border-color: green");
[Link](new Label("Enter a new message: "));

TextField tf = new TextField();


[Link](tf);
[Link](paneForTextField);

[Link](e -> [Link]([Link]())); // event handler

// left: radio buttons


VBox paneForRadioButtons = new VBox(20);
[Link](new Insets(5, 5, 5, 5));
[Link]("-fx-border-color: green");
RadioButton rbRed = new RadioButton("Red");
RadioButton rbGreen = new RadioButton("Green");
RadioButton rbBlue = new RadioButton("Blue");
[Link]().addAll(rbRed, rbGreen, rbBlue);
[Link](true);
[Link]([Link]);
[Link](paneForRadioButtons);

35
[Link] 3/5

ToggleGroup group = new ToggleGroup(); // create button group


[Link](group);
[Link](group);
[Link](group);

[Link](e -> { // event handlers


if([Link]())
[Link]([Link]);
});

[Link](e -> {
if([Link]())
[Link]([Link]);
});

[Link](e -> {
if([Link]())
[Link]([Link]);
});

36
[Link] 4/5
// right: check boxes
VBox paneForCheckBoxes = new VBox(20);
[Link](new Insets(5, 5, 5, 5));
[Link]("-fx-border-color: green");
CheckBox chkBold = new CheckBox("Bold");
CheckBox chkItalic = new CheckBox("Italic");
[Link]().addAll(chkBold, chkItalic);
[Link](paneForCheckBoxes);

EventHandler<ActionEvent> handler = e -> { // even handler


if ([Link]() && [Link]()) {
[Link]([Link]("Times New Roman", [Link],
[Link], 20)); // Bold & Italic checked
}
else if ([Link]()) {
[Link]([Link]("Times New Roman", [Link],
[Link], 20)); // Bold checked
}
else if ([Link]()) {
[Link]([Link]("Times New Roman", [Link],
[Link], 20)); // Italic check checked
}
else {
[Link]([Link]("Times New Roman", [Link],
[Link], 20)); // Both check boxes unchecked
}
};
[Link](handler);
37
[Link](handler);
[Link] 5/5
// Create a scene and place it in the stage
Scene scene = new Scene(pane, 600, 400);
[Link]("UIControlDemo"); // Set the stage title
[Link](scene); // Place the scene in the stage
[Link](); // Display the stage
}

public static void main(String[] args) {


launch(args);
}
}

38
TextArea
• A TextArea enables the user to enter multiple lines of text.
• Often it is useful to create a ScrollPane object to hold an instance of
TextArea and let ScrollPane handle scrolling for TextArea.
• Constructors:
TextArea() // creates an empty text area
TestArea(String text) // creates a text area with the specified text

• Examples:
TextArea taNote = new TextArea("This is a text area");
[Link](20); // default=40
[Link](5); // default=10
[Link](true);
// Create a scroll pane to hold text area
ScrollPane scrollPane = new ScrollPane(taNote);

[Link](“set new text string”);


[Link](“append new text string”);
39
ComboBox
• A ComboBox<T>, also known as drop-down list, contains a list of
items from which the user can choose.
• ComboBox is defined as a generic class. The generic type T
specifies the element type for the elements stored in a combo box.
• Use [Link]().addAll() method to add multiple items into
the list.
• Whenever an item is selected, an ActionEvent is fired.
• Examples:
ComboBox<String> cbo = new ComboBox<String>();
[Link]().addAll("Item 1", "Item 2", "Item 3", "Item 4");
[Link]("-fx-color: red");
[Link]("Item 2"); // set selected item

String selected = [Link](); // return selected item

40
ComboBox
• The items in the combo box are stored in an ObservableList.
• For convenience, JavaFX provides the static method
[Link](arrayOfElements) for creating an
ObservableList from an array of elements, to simplify the creation of
combo box.
• Examples:
String [] itemArray = {"Item 1", "Item 2", "Item 3", "Item 4“};

ObservableList<String> items = [Link](itemArray);


ComboBox<String> cbo = new ComboBox<String>(items);

[Link]().addAll(items); // same as above

41
Show Flags Demo

ComboBox

TextArea
Label

42
[Link] 1/3
public class ShowFlags extends Application {

// Declare an array of Strings for flag titles


private String[] flagTitles = {"Canada", "France", "United Kingdom",
"United States of America"};

// Declare an ImageView array for the flags


private ImageView[] flagImage = {new ImageView("images/[Link]"),
new ImageView("images/[Link]"), new ImageView("images/[Link]"),
new ImageView("images/[Link]")};

// Declare an array of strings for flag descriptions


private String[] flagDescription = {"Description for Canada ...",
"Description for France ...", "Description for United Kingdom ...",
"Description for United States of America ..."};

@Override // Override the start method in the Application class


public void start(Stage primaryStage) {

BorderPane pane = new BorderPane();

// Add label + combo box on top


HBox paneForComboBox = new HBox(10); // use HBox to hold them
[Link](new Insets(5));
[Link](Pos.CENTER_RIGHT);
[Link]().add(new Label("Select a country: "));

43
[Link] 2/3
ComboBox<String> cbo =
new ComboBox<String>([Link](flagTitles));
[Link](flagTitles[0]);
[Link]().add(cbo);
[Link](paneForComboBox);

// Add text area at the center


TextArea txtArea = new TextArea();
[Link](true);
[Link](false);
[Link](new Font("Serif", 14));
[Link](flagDescription[0]);
ScrollPane scrollPane = new ScrollPane(txtArea);
[Link](scrollPane);

// Add Label with image at top


Label imageLabel = new Label();
[Link]([Link]);
[Link](200, 100);
[Link](new Font("SansSerif", 16));
[Link](flagTitles[0]);
[Link](flagImage[0]);
[Link](imageLabel);

44
[Link] 3/3
// Handle event to display the selected country
[Link](e -> {
int i = [Link]().indexOf([Link]());
[Link](flagTitles[i]);
[Link](flagImage[i]);
[Link](flagDescription[i]);
});

// Create a scene and place it in the stage


Scene scene = new Scene(pane, 450, 170);
[Link]("Show Flag"); // Set the stage title
[Link](scene); // Place the scene in the stage
[Link](); // Display the stage
}

public static void main(String[] args) {


launch(args);
}

45
Mouse Events
• A MouseEvent is fired whenever a mouse button is pressed,
released, clicked, moved, or dragged on a node or a scene.
• The MouseEvent object captures the event, such as the number of
clicks associated with it, the location (the x- and y-coordinates) of
the mouse, or which mouse button was pressed.

46
Mouse Events
• You can use the getButton() method to detect which button is
pressed:
[Link]() == [Link]; // left
[Link]() == [Link]; // middle
[Link]() == [Link]; // right
[Link]() == [Link]; // none

• Mouse event registration methods:


Mouse pressed -> setOnMousePressed(EventHandler<MouseEvent>)
Mouse released -> setOnMouseReleased(EventHandler<MouseEvent>)
Mouse clicked -> setOnMouseClicked(EventHandler<MouseEvent>)
Mouse entered -> setOnMouseEntered(EventHandler<MouseEvent>)
Mouse exited -> setOnMouseExited(EventHandler<MouseEvent>)
Mouse moved -> setOnMouseMoved(EventHandler<MouseEvent>)
Mouse dragged -> setOnMouseDragged(EventHandler<MouseEvent>)

47
[Link]
public class MouseEventDemo extends Application {
@Override // Override the start method in the Application class
public void start(Stage primaryStage) {
// Create a pane and set its properties
Pane pane = new Pane();
Text text = new Text(20, 20, "Programming is fun");
[Link]().addAll(text);

[Link](e -> {
[Link]([Link]());
[Link]([Link]());
});

// Create a scene and place it in the stage


Scene scene = new Scene(pane, 300, 200);
[Link]("MouseEventDemo"); // Set the stage title
[Link](scene); // Place the scene in the stage
[Link](); // Display the stage
}

public static void main(String[] args) {


launch(args);
}
}

48
Key Events
• A KeyEvent is fired whenever a key is pressed, released, or typed
on a node or a scene.
• Key events enable the use of the keys to control and perform
actions or get input from the keyboard.

key-typed event

for key-pressed/released

49
Key Events
• Every key event has an associated code that is returned by the
getCode() method.

50
[Link]
public class KeyEventDemo extends Application {
public void start(Stage primaryStage) {
// Create a pane and set its properties
Pane pane = new Pane();
Text text = new Text(50, 50, "A");
[Link]().add(text);
[Link](e -> {
switch ([Link]()) {
case DOWN: [Link]([Link]() + 10); break;
case UP: [Link]([Link]() - 10); break;
case LEFT: [Link]([Link]() - 10); break;
case RIGHT: [Link]([Link]() + 10); break;
default: {
String s = [Link]();
if (![Link]("") && [Link]([Link](0)))
[Link]([Link]());
}
}
});

// Create a scene and place the pane in the stage


Scene scene = new Scene(pane, 300, 200);
[Link]("KeyEventDemo"); // Set the stage title
[Link](scene); // Place the scene in the stage
[Link](); // Display the stage
[Link](); // text is focused to receive key input
}
51
Reminders
1. There will be no lecture class in Week 8. Lectures will
resume as usual in Week 9.

2. There will be no practical class in Week 8. However,


practical group P24 will have a replacement class on
31 March 2025 via Microsoft Teams. This is due to the
cancellation of the practical class in Week 12 (28 April
2025).

3. The Midterm Test will be held in Week 10.


• Date: 18 April 2025 (Friday)
• Time: 8:00 am – 10:00 am
• Venues: LDK3 and LDK1 (Please follow your lecture class group)
52

You might also like