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
- Kikk på kursnotater om grafiske brukergrensesnitt, særlig de første par avsnittene.
Endre farge med tastetrykk
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 å skriveapp.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 skriverapp.color = 'yellow'
i app_started-funksjonen oppretter du en variabel som hetercolor
iapp
og setter den til å være'yellow'
.
Når funksjonen er implementert, skal programmet se ut som det gjorde fra starten av:
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 vilevent.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:
Teksteditor
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.
- Sjekk om det var
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 strengenapp.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:
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
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:
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 variabelapp.debug_mode
og setter den til å begynne med tilFalse
. - 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 vido_step
. - I
timer_fired
legger vi til en sjekk omapp.debug_mode
erFalse
. Hvis den er det, kaller vido_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)