Luet oppimateriaalin englanninkielistä versiota. Mainitsit kuitenkin taustakyselyssä osaavasi suomea. Siksi suosittelemme, että käytät suomenkielistä versiota, joka on testatumpi ja hieman laajempi ja muutenkin mukava.

Suomenkielinen materiaali kyllä esittelee englanninkielisetkin termit.

Kieli vaihtuu A+:n sivujen yläreunan painikkeesta. Tai tästä: Vaihda suomeksi.

# Chapter 3.1: Interactive Graphics

Questions Answered: How do I bring my graphical application to life? How do I make it react to the user’s mouse clicks and key presses?

Topics: GUI events of different kinds. Event handling in a GUI.

What Will I Do? Very concrete things. The chapter consists largely of example programs and programming assignments.

Rough Estimate of Workload:? An hour or more. There are a lot of optional assignments on offer.

Points Available: A65.

Related Modules: IntroApps, FlappyBug.

## Introduction

In this chapter, we’ll get the ladybug moving and do other nice things. But let’s start with a very simple example.

### A counter class

Some of the programs in this chapter make use of a simple counter. Such a counter can keep track of any quantity that increases by one at a time, such as the number of a user’s mouse clicks in an application.

The REPL session below creates a counter that starts at zero and increases by one every time its effectful method `advance` is invoked:

```val firstCounter = new Counter(0)firstCounter: Counter = value 0
firstCounter.valueres0: Int = 0
```

The initial value doesn’t need to be zero:

```val secondCounter = new Counter(100)secondCounter: Counter = value 100
```

Given what we know from earlier chapters, class `Counter` is easy to implement:

```class Counter(var value: Int) {

this.value = this.value + 1
}

override def toString = "value " + this.value

}
```

### A new role: the stepper

The “path” of a stepper is predetermined.

The variable `value` in class `Counter` had a role that’s a bit different from any of the other variables we’ve used so far (cf. the roles of variables from Chapter 2.6). Starting from an initial number, it always increases by one. With the same initial value, the sequence is invariably the same; e.g., 0, 1, 2, 3, etc.

A stepper (askeltaja) is a variable whose value advances along a preordained sequence of values. Assuming we know the initial state, we also know what the sequence is. A typical stepper follows a sequence of increasing or descreasing integers, but other kinds of steppers exist, too.

Steppers are very common. Our counter class featured an archetypal use case for a stepper: we wanted to track an increasing quantity. Later in O1, you’ll see another frequent use: keeping track of an advancing ordinal number.

Just like the value of a gatherer (Chapter 2.6), a stepper’s new value depends on its previous value. However, a stepper’s value doesn’t depend on external factors (such as inputs) but always follows its preset path.

## My Program Notices When I Click

As an experiment, let’s write a program that counts the user’s mouse clicks and makes visible changes to the GUI display as the clicks accumulate.

A single `Counter` object will do as our domain model. Let’s make our GUI draw a circle that grows in size with each click.

We can get started by writing an app object as taught in Chapter 2.7:

```object ClickApp extends App {
val clickCounter = new Counter(5)
val background = rectangle(500, 500, Black)

val gui = new View(clickCounter) {
def makePic = background.place(circle(clickCounter.value, White), new Pos(100, 100))
}

gui.start()
}
```
Our domain model is a `Counter` object whose value starts at, say, five.
`makePic` constructs an image by placing a white circle against a dark background. The circle’s diameter equals the counter’s current value (initially five).

To make our GUI react to mouse clicks, we need to define an event handler (tapahtumankäsittelijä) on it. An event handler is a piece of code that is invoked whenever a new event (tapahtuma) is observed; events include mouse clicks and movements, key presses, and so forth. We can write an event-hander method on our `View` instance:

```object ClickApp extends App {
val clickCounter = new Counter(5)
val background = rectangle(500, 500, Black)

val gui = new View(clickCounter) {
def makePic = background.place(circle(clickCounter.value, White), new Pos(100, 100))

override def onClick(locationOfClick: Pos) = {
println("Click detected at " + locationOfClick + "; " + clickCounter)
}
}

gui.start()
}
```
Our event handler is a method called `onClick`. Any instance of `View` is capable of detecting events in the GUI; it calls this method whenever a click event occurs. We’ll take a closer look at the method’s code momentarily.

You can find this program in package `o1.counter` in the IntroApps module. Run the program, click about with the mouse, and observe what happens. Keep an eye on both the graphical window and the text console.

Now that you’ve tried the program, let’s inspect the event-handler:

```override def onClick(locationOfClick: Pos) = {
println("Click detected at " + locationOfClick + "; " + clickCounter)
}
```
To react to mouse clicks, we must give the method exactly this name. The `Pos` parameter is also important. Now the GUI library recognizes our method as the one to call when an event occurs and passes the event’s coordinates as a parameter.
The method’s body defines what we want this application to do when a click happens. Here, we command our counter to record the click and also report the event in the text console.
Many event handlers receive additional information about the event as a parameter. In this case, the parameter informs the event handler of the coordinates where the mouse was clicked. This application does nothing with this information apart from printing it out.
We’re free to name the event handler’s parameter variable as we please, just like we’re free to name any other local variables.
We must prefix the method with `override` just like you’ve done with `toString` methods (Chapter 2.5). This is because the `View` class already defines a number of default event handlers, `onClick` being one of them. The default handlers’ behavior is to simply ignore all events, because there is no generic way to react to an event; the desired reaction depends entirely on the application. So what we do here is override the default implementation with our own application-specific method.

We didn’t need to explicitly call `onClick` anywhere. From our perspective, the method is invoked automatically whenever the user clicks. This automaticity is provided to us by the `View` class: each `View` object knows how to function as its own event listener (tapahtumankuuntelija), observing events that apply to it and calling event handlers such as `onClick`.

## My Program Notices When I Press a Key

### An event handler for the keyboard

We can react to a key press just like we could to a mouse click. We just need a slightly different event handler:

```override def onKeyDown(pressedKey: Key) = {
println("Pressed down: " + pressedKey)
}
```
This event handler must be named `onKeyDown`. It receives a value of type `Key` as a parameter. Different `Key` objects correspond to the different keys on a keyboard.
This example handler just prints out a report of which key was pressed.

## Assignment: FlappyBug (Part 5 of 17: The Bug Moves)

Take out the version of `FlappyBugApp` that you wrote earlier (Chapter 2.7). As things stand, the app object creates a `View` that knows how to produce a picture of the game world but nothing else.

1. On that `View` object, add the `onKeyDown` event handler from the previous section. Run the program and note the reports it produces in the text console on every key press.
• Make sure you have followed the previous FlappyBug assignment’s advice on naming the variable that refers to the `View` object: “Normally, you could name such a variable freely, but please use the name `gui` here to ensure that the automatic assessment works properly.”
1. Remove the print command from the event handler. Instead call the `activateBug` method of the `Game` object. Now pressing any key on the keyboard should activate the bug that’s linked to the `Game`.
2. Run the modified program. Witness:
• The bug moves!
• The bug flies off-screen after just a few key presses.
• The bug doesn’t fall. The obstacle doesn’t move. Time stands still in the game world. You haven’t yet called the `timePasses` method of the `Game` object. (We’ll get to that momentarily.)

A+ presents the exercise submission form here.

## My Program is Ticking

An event doesn’t necessarily have to reflect an action by the user. The passing of a moment is an event of sorts, too.

### A ticking app

The package `o1.counter` in IntroApps contains a program that resembles `ClickApp` but counts clock ticks rather than mouse clicks. Run `TickingApp` and see below for an explanation of how it works.

```object TickingApp extends App {
val tickCounter = new Counter(0)
val background = rectangle(500, 500, Black)

val gui = new View(tickCounter) {
def makePic = {
val square = circle(tickCounter.value, White)
background.place(square, new Pos(250, 250))
}

override def onTick() = {
}
}

gui.start()
}
```
This program doesn’t have an `onClick` handler; it has `onTick` instead. This method takes no parameters.

The `View` object uses a timer that fires a clock tick roughly 24 times per second. Every time this happens, the view object calls its own `onTick` handler, which makes our counter advance.

### Assignment: ticking and rotating

Edit the program’s `makePic` method so that:

• The shape that “approaches” the user isn’t a circle but a square whose edge length equals the counter’s current value.
• The square not only grows in size but also rotates one degree clockwise on each clock tick. Use the `clockwise` method introduced in Chapter 2.3 to rotate the square, and pass in the counter’s value as a parameter.

Test the edited program. Then try changing the clock speed: give the `View` object the number 50 as a second constructor parameter. Now `onTick` gets called about fifty times per second, causing the shape to gyrate and grow faster.

A+ presents the exercise submission form here.

More things to try

Try different clock speeds. A larger number speeds up the ticking, a smaller number slows down the program. A value between zero and one means the application’s clock ticks at a rate slower than one tick per second.

Try a different picture in place of the square. For instance, Scaling a rotating `face.png` to an increasingly large size makes for a rather disturbing animation. To adjust an image’s size, you can use either the `scaleBy` method from Chapter 2.3 or `scaleTo`, which expects the desired width and height as parameters (in pixels).

Who calls `makePic` and when?

I guess `View` updates itself, since the pictures move in the window even though I haven’t called `makePic`...
Does a `View` call `makePic` whenever any of the `onSomeEvent` methods has been called, like `onClick` or `onTick`?

A `View` object is responsible for updating the visible graphics whenever one of its event-handler methods is called.

After each event, the `View` calls its own `makePic` method (which you always need to define) and displays the image that `makePic` returns. `makePic` gets called in this fashion on clock ticks and on user-generated GUI events once you’ve `start`ed the view.

Any `onTick` method that you define gets called multiple times per second (unless otherwise specified). It triggers a `makePic` call each time.

(Even though you don’t need to call a `View`’s event-handling methods and `makePic` directly, they are methods just like any other. The tester code in A+ doesn’t actually `start` your GUIs and display them onscreen; it calls `makePic`, `onTick` and the rest directly.)

## Assignment: FlappyBug (Part 6 of 17: Time Passes)

Implement an `onTick` method on `FlappyBugApp`’s `View` object. The method should simply call the `timePasses` method of the app’s game object. (Since this is the `onTick` method, the `View` object will automatically call it on every tick of the clock.)

Try it.

Submit it.

A+ presents the exercise submission form here.

## Assignment: FlappyBug (Part 7 of 17: At the World’s Edge)

FlappyBug is starting to look like a game, but there’s much to be done still. In this assignment, you’ll improve the app as follows:

• Prevent the bug from rising higher than the top edge of the visible game world. The bug’s center must not have a negative y coordinate.
• Prevent the bug from burrowing into the ground. The bug’s center must not have a y coordinate in excess of 350.

We recommend the following approach, which is both convenient and elegant. There are other ways to solve the assignment, too; in programming, there always are.

### Phase 1: an auxiliary method

Add an effectful method `move` in class `Bug`:

• It takes a `Double` parameter that indicates how much should be added to the bug’s y coordinate.
• It places the bug at new coordinates, which it computes from the old ones by adding to the y coordinate as indicated. A positive parameter value sends the bug downwards, a negative value upwards.

### Phase 2: refactoring

Reimplement the methods `flap` and `fall` so that each of the two calls `move`, passing in the appropriate number. These methods should continue to do exactly the same as before even though their implementation is different. Each method is very simple to implement by calling `move`.

In fancy terms, what you do here is refactor (refaktoroida) your program. Refactoring is the modification of a program so that its quality improves but its functionality stays the same. A common reason to refactor code is to make it easier to extend or modify.

After refactoring code that works, it’s wise to check that it still works; this is called regression testing (regressiotestaus). For the present, we’ll accept a trial run as sufficient testing. Run your program; it should work as before.

### Phase 3: get to know `clampY`

Every `Pos` object has a `clampY` method. It receives two numbers as parameters, which define a lower and upper bound for the y coordinate:

```val testPos = new Pos(10, 50)testPos: Pos = (10.0,50.0)
testPos.clampY(5, 30)res4: Pos = (10.0,30.0)
testPos.clampY(100, 200)res5: Pos = (10.0,100.0)
testPos.clampY(0, 100)res6: Pos = (10.0,50.0)
```
`clampY` returns a new position whose x coordinate is the same as that of the original `Pos` but whose y coordinate has been squeezed into the given bounds. In our example, the bounds are 5 and 30, so the original’s excessive y coordinate gets replaced by 30.
The same principle applies if the original coordinate is smaller than the lower bound.
If the coordinate is already within bounds, the result equals the original `Pos`.

`clampX`

There is, unsurprisingly, also a `clampX` method, but you won’t need it now.

```testPos.clampX(100, 200)res7: Pos = (100.0,50.0)
```

### Phase 4: the actual solution

With the groundwork done, the actual solution is but a few characters long.

Our twin goals are to prevent the y coordinate from growing too large and to prevent it from growing too small. You can address both goals at once by clamping the bug’s y coordinate to the desired interval.

Make that small change in the `move` method.

What about `flap` and `fall`? If you did as suggested in Phase 2 above, those methods now also abide by the rules, since their implementation is based on `move`, whose code now governs all the bug’s movements.

An optional hint

Make sure to assign the right value to the variable that stores the bug’s location: the new location should be affected by both the bug’s movement and the clamping.

As you specify that sequence of operations, keep in mind that `Pos` objects are immutable (Chapter 2.5). Be sure to apply the latter operation to the result of the former.

A+ presents the exercise submission form here.

## Assignment: FlappyBug (Part 8 of 17: The Thrill of Speed)

Just hopping up and down is not fit for a bug.

To introduce a sense of forward motion into our game, we could make our bug move sideways along the x axis. But how about a different approach? Let’s instead make the background slide from right to left. The `Pic` class has a method that’ll serve us nicely:

### Groundwork: `shiftLeft`

```val testPic = circle(200, Red)testPic: Pic = circle-shape
val shifted = testPic.shiftLeft(25)shifted: Pic = circle-shape (transformed)
show(shifted)```

The illustration on the right shows the new image returned by `shiftLeft`, in which the original image’s contents have been moved leftwards by the given amount. The left-hand bit that would have otherwise vanished now appears on the right.

You can probably guess what’s coming: we’ll take the familiar picture of sky, ground, and tree, and shift it leftward as the clock ticks, yielding new versions of the background.

### A shifting background

Make three changes to `FlappyBugApp`.

1. Add an instance variable to the `View` object. Call it `background`. Initialize it with the value of `scenery`:

```var background = scenery
```

This is a `var`. You’ll use this variable to keep track of which image is currently used as the game’s background. When the game starts, the background is the familiar image with the tree right in the middle.

Reminder: to make `background` an instance variable on the `View` object, put the variable inside the `View` object’s definition. But don’t put it within `makePic` or the other method definitions — that would make it a local variable that doesn’t exist while the method isn’t running.

2. In `onTick`, add the following command that updates the background:

```this.background = this.background.shiftLeft(2)
```

What this does is shift the background a couple of pixels left every time the clock ticks.

If you wish, you can also define a constant (Chapter 2.6) and use it instead of the magic number two.

3. The above commands do create new versions of the background image and adjust the `background` variable just as intended. Nevertheless, if you run your program now, you’ll find its outward behavior unaltered. This is because `makePic` still uses the original `scenery` to construct the image that it shows to the user. Substitute `background` for `scenery`, and voilà!

A+ presents the exercise submission form here.

## Assignment: FlappyBug (Part 9 of 17: The Bug Accelerates)

### The plan

Our bug falls at a steady, slow, unnatural pace. Let’s make it accelerate towards the ground between flaps. Here’s the basic idea:

• The bug will have a velocity: how many pixels it moves vertically on each clock tick. A positive velocity stands for downward movement; a negative velocity moves the bug upwards.
• When the bug flaps its wings, its gets an upward velocity. That is, it doesn’t immediately change location on a wing flap; instead, its velocity changes (see below for details).
• On each tick, we add two to the bug’s speed, pulling it ever more downwards.

### Detailed instructions: a variable for velocity

In class `Bug`, add an instance variable that keeps track of the bug’s current vertical velocity: how many pixels per tick does the bug fall or rise per tick?

Set the variable to an initial value of 0.0. Give it the name `yVelocity`.

### Detailed instructions: the `flap` method

Edit the `flap` method so that it no longer moves the bug fifteen pixels upwards or indeed anywhere else.

In the existing version of the program, `flap`’s parameter indicates how much the bug moves right away. Modify the method so that the parameter instead gives the bug an upward velocity. For instance, if you pass 15 as a parameter to `flap`, the bug gets a negative velocity of -15. Assign that value to `yVelocity`.

In the modified program, the `flap` method must not move the bug at all! The method only adjusts the bug’s velocity.

Also note that `flap` completely ignores what the bug’s earlier velocity was. It simply replaces the old velocity rather than adjusting it by the given amount.

(The `activateBug` method in class `Game` should still call the bug’s `flap` method and pass in the number fifteen, as before. The difference is what `flap` does with its parameter.)

### Detailed instructions: the `fall` method

Adjust the `fall` method so that it:

• first increases the value of `yVelocity`: the new value should be two more than the old;
• then moves the bug (up or down) by `yVelocity`’s new value. If you wrote a `move` method for this class in the earlier assignment, simply calling that method will do the trick.

A side note about `move`

It turns out that the helper method `move` is no longer quite as useful in this version of FlappyBug as it was in the earlier one. Such things happen as programs evolve. Even so, it’s okay to leave `move` in and call it from `fall`.

A+ presents the exercise submission form here.

## My Program Notices the Mouse (and Other Stuff)

The optional activities below will teach you, among other things, how to make your application respond to mouse movements. That isn’t necessary for O1, but you’ll probably want to try your hand at some of these assignments anyway.

Optional assignment: something’s stuck to my mouse

photo: Dwight Kuhn

In this toy example, we’ll use a simple class to model an object that we’ll call a burr:

```class Burr {
var location = new Pos(0, 0)    // most-recent holder
}
```

A burr object’s only attribute is its location, which is mutable:

```val testBurr = new BurrtestBurr: Burr = o1.burr.Burr@34ece05e
testBurr.locationres8: Pos = (0.0,0.0)
testBurr.location = new Pos(10, 50)testBurr.locationres9: Pos = (10.0,50.0)
```

Within the IntroApps module you can find the above class as well as a file named `BurrApp1.scala`. Build on the starter code in the file to produce the following application:

• The domain model is a single burr object.

• The GUI is a `View` that draws a green circle (`burrPic`) on a white background (`background`) at the burr’s location.

• The view’s `makePic` method must return an image where the burr pic is correctly positioned against the background.
• Please make sure to use the name `gui` for the variable that refers to the `View` instance. (This helps us with the automatic assessment.)
• The view has the following event handler:

• It’s called `onMouseMove` and receives as its only parameter a `Pos` object that indicates the mouse cursor’s current position (just like `onClick` above).
• It assigns the mouse location to the burr’s location attribute. The burr will thus follow the mouse.
• If you want, you can also include a command in the body of `onMouseMove` that prints out the parameter. This makes it easier to observe how often this event handler is called as you move the mouse within the GUI window.

To clarify: the `onMouseMove` method does no image manipulation at all. It’s `makePic`’s job to form each new image, using the latest coordinates that `onMouseMove` has assigned to the burr.

A+ presents the exercise submission form here.

Follow-on assignment: crosshairs

Instead of the green circle, let’s draw two lines that meet at the mouse cursor.

Lines are easy to draw with the `line` function from package `o1`. This function works much like `circle`, `rectangle`, and the rest. Here’s an example:

```val myLine = line(new Pos(0, 0), new Pos(150, 100), Red)myLine: Pic = line-shape
val backdrop = circle(200, LightBlue)backdrop: Pic = circle-shape
val myPic = backdrop.place(myLine, new Pos(20, 20))myPic: Pic = combined pic
```

The outcome should look like this. The lines move with the mouse cursor.

Open `BurrApp2.scala` and copy the previous assignment’s solution there. Then edit `makePic` to draw not `burrPic` but two black (`Black`) lines:

• One of the lines should start at the top edge exactly above the mouse cursor and reach all the way straight down to the bottom of the view.
• The other line should begin at the edge to the left of the cursor and reach all the way to the right-hand edge.

Instructions and hints:

• You can use `place` to position the lines. As you do so, note that the method places the starting point of the line — not its middle — at the given coordinates.
• There’s no need to make any changes to `onMouseMove`.

A+ presents the exercise submission form here.

Follow-on assignment: arithmetic on `Pos` objects

In `BurrApp3.scala`, write an application that resembles the previous two but doesn’t draw a burr or crosshairs. Instead, it draws a single black line from the view’s center towards the mouse cursor — but only until the halfway point between the center and the cursor. That is, the line “points towards” the cursor but doesn’t reach it.

This assignment calls for a bit of arithmetic on coordinates. We recommend that you use the methods `add`, `multiply`, and/or `divide` from class `Pos`. You can first experiment with them in the REPL:

• Try calling `add` so that you pass a reference to another `Pos` object as parameter: `pos1.add(pos2)`.
• Try multiplying or dividing both coordinates by a number: `pos1.multiply(number)` or `pos1.divide(number)`.

A+ presents the exercise submission form here.

Follow-on assignment: A slow burr

In `BurrApp4.scala`, write an application where a green circle follows the mouse cursor much as in `BurrApp1`. However, instead of instantly appearing where the mouse currently is, the burr will now gradually glide towards the cursor.

Again, take the code of `BurrApp1` as your starting point. Make these changes:

• Give the `View` object an additional instance variable that keeps track of the mouse cursor’s most recent observed `Pos`. You can initially set it to (0,0). Call the variable `latestCursorPos`, for example.
• Edit `onMouseMove` so that it does nothing more than assign its parameter value (i.e., the cursor’s current position) to the `latestCursorPos` variable. In other words: This app doesn’t actually move the burr whenever the mouse moves. At that point of time, it simply records the latest movement of the mouse.
• Add an `onTick` method that moves the burr. The burr’s new location is the point that is ten percent of the way from its old location towards the latest cursor position.
• For instance, if the burr is now at (10,20) and `latestCursorPos` is (100,100), the burr moves to (19,28).
• Here, too, you can use the `Pos` methods mentioned in the previous assignment.

A+ presents the exercise submission form here.

Optional assignment: a painting app

Take a look at the following pseudocode class that represents “art projects”. An art project, here, is an image that evolves incrementally as little dabs of color are added to it. The pseudocode already contains quite a bit of actual Scala, too.

```class ArtProject(canvas: Pic) {
var image = canvas              // gatherer
var brush = circle(10, Black)   // most-recent holder

def paint(where: Pos) = {
Form a new picture by taking the current image and positioning the brush pic
onto it at the given coordinates. This new picture becomes the new image.
}
}
```
The variable `image` is a gatherer (Chapter 2.6): it initially holds just the original canvas, but small images (“brush strokes”) are gradually `place`d on it. The image stored in the variable is a combination of the canvas and all the brush strokes that have accumulated so far. (At least, this is what the variable should do, but we haven’t yet implemented the method that actually adds the brush strokes.)
The “brush” is a picture. A new copy of the brush is positioned onto the current image whenever the `paint` method is invoked. The default brush is small, round, and black.
The algorithm for adding paint to the canvas has been given as pseudocode here. You’ll need to implement it yourself in the `o1.art` package, which you’ll find in the IntroApps module.

You’ll also find the app object `PaintingApp`. It creates a `View` of an `ArtProject` object that serves as the domain model. The given code is a good start but it lacks an event handler.

To summarize, here is what you need to do:

1. Implement the `paint` method of class `ArtProject`.
2. Add an `onMouseMove` handler to `PaintingApp`. It should simply call the `paint` method of the art project that is displayed in the `View`, so that a brush stroke appears at the mouse cursor.

A+ presents the exercise submission form here.

Follow-on assignment: changing colors

Modify the painting app so that the user can change the drawing color with a mouse click.

First edit class `ArtProject` so that it keeps track of the currently active color and cycles to the next color on request. More specifically:

1. Add these two instance variables at the top:

```var colorIndex = 0
val palette = Buffer(Black, Red, Green, Blue)
```

The `palette` variable holds a reference to a buffer that stores all the colors available to the app’s user.

At any given time, a single color from the palette is active; the variable `colorIndex` stores the index of the active color. In this assignment, we’ll use `colorIndex` as a stepper that advances through the palette in order and wraps back to the beginning: 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, etc.

2. Add an effect-free method named `drawingColor` that takes no parameters and returns the currently active color. That is, the method returns the `Color` indicated by `colorIndex` (initially black).

3. Implement an effectful method `changeColor`:

• It advances `colorIndex` to the next integer. (Use the modulo operator to wrap the number back to zero.)
• It changes the value of `brush` to a differently colored circle of the same size. (Call `drawingColor` to get the new color.)
• It takes no parameters (but as an effectful method, requires an empty parameter list; Chapter 2.6).

Finally, add an `onClick` event handler to the GUI. This method should (ignore its `Pos` parameter and) simply call `changeColor` on the art project. See `ClickingApp` at the beginning of this chapter for guidance.

A+ presents the exercise submission form here.

Follow-on assignment: GUI events in more detail

Modify the program from the previous assignment. In the new version, the user still clicks to change the drawing color. However, the new color isn’t the next one in the palette. Instead, the color is determined by the number of successive clicks: a single click selects the first color in the palette, a double-click the second one, a triple-click the third one, and so forth.

First, edit class `ArtProject`: add an `Int` parameter to `changeColor` and modify the method’s body so that it doesn’t cycle to the next color but instead sets `colorIndex` from the parameter.

Then replace the `onClick` method in `PaintingApp` with this one:

```override def onClick(clickEvent: MouseClicked) = {
artwork.changeColor(clickEvent.clicks)
}
```

Our earlier `onClick` methods received just the click’s location as a parameter. In many cases, that’s all the information about the event that we need. But sometimes we do want to take a more detailed look at a GUI event, say, to examine the number of successive clicks:

In such cases, we can define an event handler that receives a reference to an object that represents the entire event, as the `MouseClicked` object does here.
A `MouseClicked` object provides access to various attributes of the event. Here, all we need is `clicks`, which is the number of successive clicks as an `Int`.

Test your program. Try clicking a lot of times in quick succession. Did you take this possibility into account when you rewrote `changeColor`? If not, do something about it now; if yes, you may wish to try and see what would have happened if you had failed to consider high click counts.

A+ presents the exercise submission form here.

If you wish, you can continue exploring event handlers and event objects on your own. For example, the documentation of class `View` lists a number of event-handler methods (whose names start with `on`).

## Summary of Key Points

• When a user interacts with a graphical user interface, a GUI event is fired. A GUI event can be a key press or a mouse movement, for instance. The ticks of an application’s internal clock can be events, too.
• An event handler is a subprogram that receives information about events that have occurred and determines what the program does when that happens.
• An event handler may receive parameters such as the precise location of an event.
• You can define event handlers on instances of the `View` class that we use in O1.
• Writing graphical programs is fun.
• Links to the glossary: model, user interface; graphical user interface (GUI); GUI event, event handler, event listener; refactoring; stepper.

Create stuff!

You can use the tools just introduced to do a lot more than what was required or suggested. Go forth and create! Edit one of the example programs or invent something entirely of your own creation.

## Feedback

Please note that this section must be completed individually. Even if you worked on this chapter with a pair, each of you should submit the form separately.

## Credits

Thousands of students have given feedback that has contributed to this ebook’s design. Thank you!

The ebook’s chapters, programming assignments, and weekly bulletins have been written in Finnish and translated into English by Juha Sorva.

The appendices (glossary, Scala reference, FAQ, etc.) are by Juha Sorva unless otherwise specified on the page.

The automatic assessment of the assignments has been developed by: (in alphabetical order) Riku Autio, Nikolas Drosdek, Joonatan Honkamaa, Jaakko Kantojärvi, Niklas Kröger, Teemu Lehtinen, Strasdosky Otewa, Timi Seppälä, Teemu Sirkiä, and Aleksi Vartiainen.

The illustrations at the top of each chapter, and the similar drawings elsewhere in the ebook, are the work of Christina Lassheikki.

The animations that detail the execution Scala programs have been designed by Juha Sorva and Teemu Sirkiä. Teemu Sirkiä and Riku Autio did the technical implementation, relying on Teemu’s Jsvee and Kelmu toolkits.

The other diagrams and interactive presentations in the ebook are by Juha Sorva.

The O1Library software has been developed by Aleksi Lukkarinen and Juha Sorva. Several of its key components are built upon Aleksi’s SMCL library.

The pedagogy of using O1Library for simple graphical programming (such as `Pic`) is inspired by the textbooks How to Design Programs by Flatt, Felleisen, Findler, and Krishnamurthi and Picturing Programs by Stephen Bloch.

The course platform A+ was originally created at Aalto’s LeTech research group as a student project. The open-source project is now shepherded by the Computer Science department’s edu-tech team and hosted by the department’s IT services. Markku Riekkinen is the current lead developer; dozens of Aalto students and others have also contributed.

The A+ Courses plugin, which supports A+ and O1 in IntelliJ IDEA, is another open-source project. It was created by Nikolai Denissov, Olli Kiljunen, Nikolas Drosdek, Styliani Tsovou, Jaakko Närhi, and Paweł Stróżański with input from Juha Sorva, Otto Seppälä, Arto Hellas, and others.

For O1’s current teaching staff, please see Chapter 1.1.