Pre5

Denne laben er fullstendig frivillig og vil ikke bli rettet, men spør gjerne en gruppeleder om hjelp hvis du sitter fast! Meningen med disse oppgavene er å bli litt kjent med brukergrensesnitt (interaktiv grafikk) før lab5.

Forberedelser

Oppgaver

Valgfri

Hvordan fullføre laben

For å bestå laben, må alle de obligatoriske oppgavene være bestått. Laben leveres i CodeGrade; du finner som vanlig knappen dit på mitt.uib.


Valgfri

Endre farge med tastetrykk
Valgfri
Nivå E

I denne oppgaven skal vi få en boks på skjermen til å endre farge når vi trykker på tastaturet. Vi skal også gjøre slik at spesifikke tastetrykk endrer til spesifikke farger. Begynn med å kopiere denne koden inn i din egen fil colorchange_keypress.py:

from uib_inf100_graphics.event_app import run_app

def app_started(app):
    ...

def key_pressed(app, event):
    ...

def redraw_all(app, canvas):
    # tegn firkanten
    canvas.create_rectangle(
        25, 25, app.width - 25, app.height - 25,
        fill='yellow',
    )

run_app(width=400, height=150)

Kjør programmet allerede nå for å se hvordan det ser ut. Foreløpig viser koden bare et gult rektangel. Men når vi er ferdige vil vi kunne endre fargen med å klikke på tastaturet.

Del A: Fargevariabel

Siden vi ønsker å endre fargen på firkanten ved tastetrykk, kan det ikke være bestemt i redraw_all at den skal være «yellow», slik det nå er i koden. Vi må derfor lage en variabel som holder på fargen, og som vi kan endre på. Fargen kan begynne som 'yellow'. Deretter må vi gjøre slik at firkanten tegnes med fargen som angitt av variabelen.

  • Opprett en variabel for fargen i app_started ved å skrive app.color = 'yellow'.
  • Endre på redraw_all slik at den bruker fargevariabelen vi nettopp laget når du tegner rektangelet.

Tenk på app som en beholder for alle variablene som til sammen beskriver tilstanden for programmet ditt. Når du skriver app.color = 'yellow' i app_started-funksjonen oppretter du en variabel som heter color i app og setter den til å være 'yellow'.

Når funksjonen er implementert, skal programmet se ut som det gjorde fra starten av:

Illustrasjon del A fullført

Vi må først opprette en variabel for å holde på fargen i app_started, slik som dette:

def app_started(app):
    app.color = 'yellow'

Deretter endrer vi på redraw_all slik at den bruker fargevariabelen til app i stedet for å bruke en bestemt farge for å tegne rektangelet:

def redraw_all(app, canvas):
    # tegn firkanten
    canvas.create_rectangle(
        25, 25, app.width - 25, app.height - 25,
        fill=app.color,
    )

Del B: Tastetrykk

Nå skal vi gjøre slik at vi kan endre fargen på firkanten ved å trykke på tastene. Vi skal bruke funksjonen key_pressed til dette. Denne funksjonen kalles hver gang vi trykker på en tast. Til å begynne med skal vi endre fargen til svart om en hvilken som helst tast blir trykket inn.

Når du har gjort dette riktig, vil du kunne kjøre programmet og gjøre rektangelet svart ved å trykke på en hvilken som helst tast.

For å endre fargen til svart, må vi endre på fargevariabelen når det skjer et tastetrykk. Vi kan gjøre dette slik med key_pressed:

def key_pressed(app, event):
    app.color = 'black'

Del C: Flere farger

Nå skal vi gjøre det slik at noen taster kan endre fargen på rektangelet til spesielle farger. I key_pressed trenger vi da at:

  • Når vi trykker på r skal fargen bli rød
  • Når vi trykker på g skal fargen bli grønn
  • Når vi trykker på b skal fargen bli blå
  • Når vi trykker på y skal fargen bli gul
  • Når vi trykker på alle andre taster skal fargen bli svart.

Du kan gjerne legge til flere farger om du vil.

PS: Hvilken tast som ble trykket er lagret i event.key. For eksempel vil event.key være strengen 'r' dersom brukeren trykket på r-tasten.

Slik bruker vi key_pressed til å endre fargevariabelen til app:

def key_pressed(app, event):
    if event.key == 'r':
        app.color = 'red'
    elif event.key == 'g':
        app.color = 'green'
    elif event.key == 'b':
        app.color = 'blue'
    elif event.key == 'y':
        app.color = 'yellow'
    else:
        app.color = 'black'

Når du er ferdig skal du kunne endre fargene ved å trykke på tastaturet:

Illustrasjon av ferdig program
Teksteditor
Valgfri
Nivå E

I denne oppgaven skal vi sette opp en veldig enkel tekst-editor. Vi skal kunne trykke på tastaturet og se tegnene komme opp i rekkefølge, slik som skjer når man skriver noe inn i et tekstfelt. Vi skal også kunne slette tegn ved å trykke på backspace, og legge inn mellomrom. Bruk denne koden som utgangspunkt:

from uib_inf100_graphics.event_app import run_app

def app_started(app):
    ...

def key_pressed(app, event):
    ...

def redraw_all(app, canvas):
    # tegn teksten
    canvas.create_text(
        20, 20,
        anchor='nw',
        text='Hello world!',
        font='Arial 14',
    )

run_app(width=400, height=400)

Kjør programmet og se at teksten «Hello world!» vises i skjermvinduet.

Del A: Tekstvariabel

I stedet for at vi alltid tegner akkurat «Hello World!», trenger vi en variabel som holder på teksten vi skal tegne. Vi skal bruke denne variabelen i redraw_all for å tegne teksten.

  • I app_started: opprett og initier en variabel i app for teksten som skal tegnes.
  • I redraw_all: benytt overnevnte variabel når du angir hvilken tekst som skal tegnes.

I app_started lager vi en variabel for strengen som skal vises. Vi initierer den her til å være den tomme strengen, men det kan i prinsippet være en hvilken som helst streng:

def app_started(app):
    app.text = ''

Deretter endrer vi på redraw_all slik at den bruker variabelen vi opprettet i app i stedet for å bruke en bestemt tekst for å tegne teksten:

def redraw_all(app, canvas):
    canvas.create_text(
        20, 20,
        anchor='nw',
        text=app.text,
        font='Arial 14',
    )

Nå vil du få opp en tom skjerm når du kjører programmet. Hvis du initierte app.text til noe annet i app_started, skal det være den teksten som vises når programmet kjører.

Del B: Skrive inn symboler

Nå skal vi gjøre slik at vi kan skrive inn symboler ved å trykke på tastaturet. Vi skal bruke funksjonen key_pressed til dette. Til å begynne med gjør vi slik at tegnet som ble trykket legges til på slutten av teksten. Når du er ferdig burde tegnene komme opp en etter en ettersom du trykker på tastaturet.

  • I key_pressed: legg til tegnet som ble trykket (event.key) på slutten av teksten.

def key_pressed(app, event):
    app.text += event.key

Kjør programmet, og skriv inn noen bokstaver. Prøv å trykk på mellomrom, linjeskift og backspace i programmet når du er ferdig. Hva skjer?

Del C: Mellomrom, linjeskift og backspace

Nå skal vi fikse oppførselen til mellomrom, linjeskift og backspace. Når ‘Space’ tastes, skal det legges til et mellomrom i teksten. Når linjeskift tastes, legg til et linjeskift i teksten. Når ‘Backspace’ tastes, skal det siste tegnet i teksten slettes (med mindre teksten er den tomme strengen). Når du er ferdig burde mellomrom, linjeskift og backspace oppføre seg som forventet, og programmet skal ikke krasje om du trykker på backspace når det ikke er noe tekst.

  • Linjeskift-knappen har ulike navn på Windows og Mac – respektivt 'Enter' og 'Return'. For å lage et program som virker på begge plattformer, må du håndetere begge.
  • Backspace er også ulik på Windows og Mac – respektivt 'Backspace' og 'BackSpace'. For å lage et program som virker på begge plattformer, må du håndetere begge.

  • Benytt en if-setning for å sjekke om 'Space' ble trykket: hvis det skjedde, legg til et mellomrom (' ') i teksten.
  • Fortsett med flere elif-ledd på if-setningen:
    • Sjekk om det var 'Enter' eller 'Return' som trykket. Hvis det skjedde, legg til et linjeskift i teksten.
    • Sjekk om det var 'Backspace' eller 'BackSpace' som ble trykket. Hvis det skjedde, slett det siste tegnet i teksten.

For å slette det siste tegnet i teksten kan du bruke app.text = app.text[:-1]. Dette er en måte å skrive ut en del av en streng på som bruker beskjæring. app.text[:-1] betyr «alle tegn i strengen app.text bortsett fra det siste».

  • Avslutt if-setningen med et else -ledd: hvis ingen av de andre if-setningene var sanne, må det være et vanlig tegn som ble trykket. Legg til dette tegnet i teksten.

def key_pressed(app, event):
    if event.key == 'Space':
        app.text += ' '
    elif event.key in ['Enter', 'Return']:
        app.text += '\n'
    elif event.key.lower() == 'backspace':
        if len(app.text) > 0:
            app.text = app.text[:-1]
    else:
        app.text += event.key

Nå skal du kunne skrive inn tekst i programmet ditt (nesten) som vanlig. Eksempel:

Illustrasjon av ferdig program

Legg gjerne til mer funksjonalitet om du vil! For eksempel kan du slette all teksten om man trykker Escape, eller ignorere knapper som ikke er bokstaver eller tall (f. eks. piltaster).

Firkant som flytter seg
Valgfri
Nivå E

I denne oppgaven skal vi endre oppførselen til en bevegende firkant med piltastene. Vi skal også gjøre slik at vi kan skru på en debug-modus hvor vi kan flytte firkanten steg for steg. Ta utgangspunkt i denne koden:

from uib_inf100_graphics.event_app import run_app

def app_started(app):
    app.square_left = app.width//2
    app.square_top = app.height//2
    app.square_size = 25
    app.dx = -4
    app.timer_delay = 25 # millisekunder

def key_pressed(app, event):
    ...

def timer_fired(app):
    # Denne funksjonen kalles periodisk av selve uib_inf100_graphics
    # -rammeverket. Hvor ofte bestemmes av verdien i app.timer_delay.
    do_step(app)

def do_step(app):
    # Flytt horisontalt
    app.square_left += app.dx

    # Sjekk om firkanten har gått utenfor lerretet, og hvis ja, snu
    # retning; men flytt også firkanten til kanten (i stedet for å gå
    # forbi). Merk: det finnes andre, mer sofistikerte måter å håndtere
    # at rektangelet går forbi kanten...
    if app.square_left < 0:
        # snu retningen!
        app.square_left = 0
        app.dx = -app.dx
    elif app.square_left > app.width - app.square_size:
        app.square_left = app.width - app.square_size
        app.dx = -app.dx

def redraw_all(app, canvas):
    # tegn firkanten
    canvas.create_rectangle(
        app.square_left,
        app.square_top,
        app.square_left + app.square_size,
        app.square_top + app.square_size,
        fill="yellow",
    )


run_app(width=400, height=150)

Til å begynne med flytter firkanten seg automatisk fra side til side, og skifter bare retning når den treffer kanten. Legg merke til at firkantens retning bestemmes av fortegnet på app.dx. Når app.dx er positiv går firkanten mot høyre, og når den er negativ går den mot venstre.

Del A: Endre firkantens retning

For å få firkanten til å gå den retningen vi vil, må vi legge til noe i key_pressed som endrer variabelen app.dx. Vi må gjøre slik at firkanten går mot høyre når vi trykker på høyre piltast, og mot venstre når vi trykker på venstre piltast.

Her er tre alternativer til løsning. Hvilken synest du er best?:

def key_pressed(app, event):
    if event.key == "Left":
        app.dx = -4
    elif event.key == "Right":
        app.dx = 4
def key_pressed(app, event):
    if event.key == "Left" or event.key == "Right":
        app.dx = -app.dx
def key_pressed(app, event):
    if event.key in ("Left", "Right"):
        app.dx *= -1

Når du har gjort dette riktig, vil du kunne styre firkantens retning ved å trykke på piltastene:

Illustrasjon av ferdig del A

Del B: Debug-mode

Det som får firkanten til å flytte seg jevnlig, er at timer_fired kalles jevnlig av rammeverket i bakgrunnen, og da kalles do_step av timer_fired. Dette skjer med et intervall lik app.timer_delay. Når vi er i debug-mode, vil vi at firkanten skal flytte seg kun når vi trykker på ‘Space’.

  • I app_started setter vi opp en variabel app.debug_mode og setter den til å begynne med til False.
  • I key_pressed legger vi til en sjekk om ’d’ ble tastet. Da skrur vi debug-mode på eller av.
  • I key_pressed skal vi også sjekke om space ble tastet under debug-mode. Hvis det skjedde, kaller vi do_step.
  • I timer_fired legger vi til en sjekk om app.debug_mode er False. Hvis den er det, kaller vi do_step. Hvis ikke, gjør vi ingenting.

Du er ferdig når du kan skru debug-mode på og av, og du kan flytte firkanten steg for steg når du er i debug-mode.

Legg til dette i app_started:

    app.debug_mode = False

Legg til dette i key_pressed:

    elif event.key == "d":
        app.debug_mode = not app.debug_mode
    elif app.debug_mode and event.key == "Space":
        do_step(app)

Endre timer_fired slik:

def timer_fired(app):
    if not app.debug_mode:
        do_step(app)