Ohjelmoinnin peruskurssi Y1 CS-A1111 8.11.2017 CS-A1111 Ohjelmoinnin peruskurssi Y1 8.11.2017 1 / 30
Mahdollisuus antaa luentopalautetta Luennon aikana voit kirjoittaa kommentteja ja kysymyksiä sivulle presemo.aalto.fi/opey1luento9 Goblinissa vasemmassa reunassa olevassa valikossa on valinta Luentopalaute. Tätä kautta on mahdollisuus antaa nimettömänä palautetta luennosta. Ennen ensi keskiviikon viimeistä luentoa voit erityisesti kertoa Goblinin luentopalautteen kautta, jos haluat viimeisellä luennolla kerrattavan (lyhyesti) jonkin asian. Myös harjoitustehtävistä voi antaa palautetta palautuksen yhteydessä, mutta tämä palaute ei ole nimetöntä. CS-A1111 Ohjelmoinnin peruskurssi Y1 8.11.2017 2 / 30
Oppimistavoitteet: tämän luennon jälkeen Osaat kirjoittaa ohjelman, jossa on graafinen käyttöliittymä. Tiedät, mitä pitää tehdä, jos haluat käyttää ohjelmassasi (esimerkiksi sen tulostuksissa) kirjaimia Ä, Ö ja Å. CS-A1111 Ohjelmoinnin peruskurssi Y1 8.11.2017 3 / 30
Graafiset käyttöliittymät Useimmissa nykyisissä ohjelmissa on graafinen käyttöliittymä, jossa käyttäjä ohjaa ohjelman toimintaa erilaisten komponenttien, kuten valikoiden, tekstikenttien, painikkeiden jne avulla. Tällä luennolla käydään läpi joitakin perusasioita graafisen käyttöliittymän kirjoittamisesta. Lisää perustietoa suomeksi on saatavissa esimerkiksi TTY:n Tkinter-oppaasta http://www.cs.tut.fi/~aps/tkinter.pdf tai LTY:n Tkinter-oppaasta http://www2.it.lut.fi/project/masto/ material/python-tkinteropas_lty2007.pdf (jälkimmäinen käyttää vanhempaa Python-versiota). Pythonin omassa dokumentaatiossa on tietoa käytetystä tkinter-moduulista https://docs.python.org/3/library/tkinter.html CS-A1111 Ohjelmoinnin peruskurssi Y1 8.11.2017 4 / 30
Yleistä graafisen käyttöliittymän kirjoittamisesta Graafisen käyttöliittymän kirjoittamiseen tarvitaan sopiva moduuli. Vaihtoehtoisia moduuleja on tarjolla useita. Tässä käytetään moduulia tkinter, jonka on yleensä asennettu Python-ohjelmointiympäristön mukana. Joihinkin Linux-ympäristöihin moduuli pitää kuitenkin asentaa itse. Graafisen käyttöliittymän määrittelevän tiedoston alkuun kirjoitetaan import tkinter Yleensä graafisen käyttöliittymän määritettelevä koodi kirjoitetaan luokan sisään. Käyttöliittymän ikkunaa luodessa tehtävät toimenpiteet kirjoitetaan metodin init sisään. Ikkuna luodaan ja ohjelma käynnistetään luomalla olio käyttöliittymän määrittelevästä luokasta. CS-A1111 Ohjelmoinnin peruskurssi Y1 8.11.2017 5 / 30
Esimerkki 1: tyhjä ikkuna import tkinter class Ikkuna1: def init (self): self. paaikkuna = tkinter.tk() self. paaikkuna.title("esimerkki 1") tkinter.mainloop() esimerkki_ikkuna = Ikkuna1() CS-A1111 Ohjelmoinnin peruskurssi Y1 8.11.2017 6 / 30
Vaihtoehto esimerkille 1 Säästytään tkinter-moduulin nimen kirjoittamiselta kirjoittamalla import-käsky toisella tavalla from tkinter import * class Ikkuna2: def init (self): self. paaikkuna = Tk() self. paaikkuna.title("esimerkki 1") mainloop() esimerkki_ikkuna = Ikkuna2() CS-A1111 Ohjelmoinnin peruskurssi Y1 8.11.2017 7 / 30
Komponentteja ikkunaan Moduulissa tkinter on eri luokkia erilaisten komponenttien (engl. widget) luomista varten, esimerkiksi painikkeita varten luokka Button ja tekstin esittämistä varten luokka Label. Kun halutaan lisätä ikkunaan joku komponentti, luodaan vastaavan luokan olio. Oliota luodessa kerrotaan, mihin komponentti tulee (esim. pääikkuna). Lisäksi komponentteja luodessa voidaan antaa muita tietoja, kuten komponenttiin tuleva teksti. Komponentin luominen ei vielä lisää komponenttia ikkunaan, vaan tämä pitää tehdä erikseen metodilla pack. Seuraavan kalvon esimerkkiohjelmassa luodaan ikkuna, jossa on yksi teksti. CS-A1111 Ohjelmoinnin peruskurssi Y1 8.11.2017 8 / 30
Komponentteja ikkunaan, koodi from tkinter import * class Teksti_ikkuna: def init (self): self. paaikkuna = Tk() self. paaikkuna.title("esimerkki 2") self. teksti = Label(self. paaikkuna, \ text = " Tekstia ikkunassa! ") self. teksti.pack() mainloop() oma_ikkuna = Teksti_ikkuna() CS-A1111 Ohjelmoinnin peruskurssi Y1 8.11.2017 9 / 30
Painike ikkunaan Ikkunaan voidaan luoda painikkeita luokan Button avulla. Painikkeen luomisen lisäksi pitää kertoa, mitä ohjelman halutaan tekevän, kun painiketta on painettu. Ikkunan määrittelevään luokkaan kirjoitetaan oma tapahtumankäsittelijämetodi, joka kertoo, mitä ohjelman halutaan tekevän painiketta painettaessa. Painiketta luodessa metodin nimi annetaan luokan Button init -metodille command-nimisenä parametrina. Metodin nimi annetaan ilman sulkuja. Kun painiketta on painettu, Python-tulkki kutsuu automaattisesti sille määriteltyä tapahtumankäsittelijämetodia. CS-A1111 Ohjelmoinnin peruskurssi Y1 8.11.2017 10 / 30
Dialogin käyttäminen Painike-esimerkkiohjelmassa halutaan, että painikkeen painaminen saa aikaan sen, että avataan uusi dialogi-ikkuna. Moduulissa messagebox on valmiita funktioita, joiden avulla voi luoda dialogi-ikkunoita, joissa on haluttu otsikko ja teksti. Esimerkkiohjelmassa on käytetty moduulin metodia showinfo, joka luo tiedoteikkunan. CS-A1111 Ohjelmoinnin peruskurssi Y1 8.11.2017 11 / 30
Painike-esimerkki, koodi from tkinter import * import tkinter.messagebox class Painikeikkuna: def init (self): self. paaikkuna = Tk() self. paaikkuna.title("esimerkki 3") self. nappi = Button(self. paaikkuna, \ text = "Paina minua!", \ command = self.anna_ilmoitus) self. nappi.pack() mainloop() CS-A1111 Ohjelmoinnin peruskurssi Y1 8.11.2017 12 / 30
Painike-esimerkki, koodi jatkuu def anna_ilmoitus(self): tkinter.messagebox.showinfo("vastaus", \ "Hienoa, osasit toimia oikein") oma_ikkuna = Painikeikkuna() CS-A1111 Ohjelmoinnin peruskurssi Y1 8.11.2017 13 / 30
Syötteen lukeminen käyttäjältä Seuraavassa esimerkissä kirjoitetaan ohjelma, joka muuntaa käyttäjän fahrenheiteina antaman lämpötilan celsius-asteiksi. Tarvitsemme komponentin, jonka avulla käyttäjä voi antaa haluamansa lämpötilan. Tähän voi käyttää tekstikenttää, joka luodaan luokan Entry avulla. Kenttään kirjoitettu teksti voidaan lukea metodin get avulla. Metodi get palauttaa tekstin merkkijonona. Se pitää muuntaa desimaaliluvuksi laskemista varten. Käyttäjä ilmoittaa painiketta painamalla siitä, että hän on jo antanut luvun. Muunnoksen tekevä ohjelman osa on siis kirjoitettu painikkeen tapahtumankäsittelijämetodin sisään. Esimerkkiohjelmassa muunnoksen tulos ilmoitetaan Label-komponentissa, jossa olevaa tekstiä muutetaan metodin configure avulla. CS-A1111 Ohjelmoinnin peruskurssi Y1 8.11.2017 14 / 30
Lämpötilamuunnos, koodi from tkinter import * class Muunnin1: def init (self): self. paaikkuna = Tk() self. paaikkuna.title("lampotilamuunnin") self. teksti = Label(self. paaikkuna, \ text = "Fahrenheit-lampotila:") self. ruutu = Entry(self. paaikkuna, \ width = 10) self. nappi = Button(self. paaikkuna, \ text = "Muunna", \ command = self.muunna_asteet) self. vastaus = Label(self. paaikkuna, \ text = "Celsius-lampotila:") CS-A1111 Ohjelmoinnin peruskurssi Y1 8.11.2017 15 / 30
Lämpötilamuunnos, koodi jatkuu self. teksti.pack() self. ruutu.pack() self. vastaus.pack() self. nappi.pack() mainloop() def muunna_asteet(self): syote = self. ruutu.get() fahrenheit = float(syote) celsius = 5.0 / 9.0 * (fahrenheit - 32.0) vastausteksti = "Celsius-lampotila: {:.2f} C".\ format(celsius) self. vastaus.configure(text = vastausteksti) oma_ikkuna = Muunnin1() CS-A1111 Ohjelmoinnin peruskurssi Y1 8.11.2017 16 / 30
Virheenkäsittely lämpötilamuunnokseen Muutetaan lämpötilamuunnoksen tekevää ohjelmaa niin, että se käsittelee mahdolliset virheelliset syötteet. Virheestä ilmoitetaan virhedialogi-ikkunalla. Sellainen voidaan tehdä moduulin messagebox funktion showerror avulla. CS-A1111 Ohjelmoinnin peruskurssi Y1 8.11.2017 17 / 30
Virheenkäsittely lämpötilamuunnokseen, koodi from tkinter import * import tkinter.messagebox class Muunnin2: def init (self): self. paaikkuna = Tk() self. paaikkuna.title("lampotilamuunnin") self. teksti = Label(self. paaikkuna, \ text = "Fahrenheit-lampotila:") self. ruutu = Entry(self. paaikkuna, \ width = 10) self. nappi = Button(self. paaikkuna, \ text = "Muunna", \ command = self.muunna_asteet) self. vastaus = Label(self. paaikkuna, \ text = "Celsius-lampotila:") CS-A1111 Ohjelmoinnin peruskurssi Y1 8.11.2017 18 / 30
Virheenkäsittely lämpötilamuunnokseen, koodi jatkuu self. teksti.pack() self. ruutu.pack() self. vastaus.pack() self. nappi.pack() mainloop() CS-A1111 Ohjelmoinnin peruskurssi Y1 8.11.2017 19 / 30
Virheenkäsittely lämpötilamuunnokseen, koodi jatkuu def muunna_asteet(self): syote = self. ruutu.get() try: fahrenheit = float(syote) celsius = 5.0 / 9.0 * (fahrenheit - 32.0) vastausteksti = "Celsius-lampotila: {:.2f} C".\ format(celsius) self. vastaus.configure(text = vastausteksti) except ValueError: virheteksti = "Anna lampotila lukuna!" tkinter.messagebox.showerror("virhe", \ virheteksti) oma_ikkuna = Muunnin2() CS-A1111 Ohjelmoinnin peruskurssi Y1 8.11.2017 20 / 30
Piirtäminen Luokan Canvas avulla voidaan luoda piirtoalusta, jolle voidaan piirtää erilaisia kuvioita, viivoja, tekstejä jne. Näin voidaan saada ohjelma tulostamaan erilaisia kaavioita tai kuvaajia. Piirtoalustan koordinaatteja lasketaan pikseleiden avulla. Vasemman yläkulman koordinaatit ovat (0, 0) Joitakin luokan Canvas metodeita. Mahdollisia parametreja on paljon erilaisia, mutta ensimmäiset parametrit kertovat ne koordinaatit, mihin komponentti piirretään: create_line piirtää suoran viivan create_polygon piirtää murtoviivan create_rectangle piirtää suorakulmion create_oval piirtää ympyrän tai ellipsin create_text piirtää tekstin CS-A1111 Ohjelmoinnin peruskurssi Y1 8.11.2017 21 / 30
Esimerkki piirtävästä ohjelmasta from tkinter import * class Piirtoikkuna: def init (self): self. paaikkuna = Tk() self. paaikkuna.title("piirtoesimerkki") self. alusta = Canvas(self. paaikkuna, \ width = 200, \ height = 300, \ background = "lightblue") self. alusta.pack() self. alusta.create_line(0, 0, 100, 100, \ fill = "red") self. alusta.create_rectangle(50, 50, 150, 150,\ fill = "blue") CS-A1111 Ohjelmoinnin peruskurssi Y1 8.11.2017 22 / 30
Esimerkki piirtävästä ohjelmasta jatkuu self. alusta.create_oval(100, 100, 200, 200, \ fill = "yellow") self. alusta.create_line(70, 30, 95, 180, \ fill = "green") self. alusta.create_text(100, 250, \ text = "Hurraa!", \ fill = "brown") mainloop() oma_ikkuna = Piirtoikkuna() CS-A1111 Ohjelmoinnin peruskurssi Y1 8.11.2017 23 / 30
Valmiiden kuvatiedostojen lisääminen ikkunaan Luokan PhotoImage avulla voidaan.gif-,.pgm- ja.ppm-tyyppisistä (uusissa tkinter-versioissa myös.png) kuvatiedostoista luoda kuvaolioita, joita voidaan liittää esimerkiksi Canvas-tyyppiselle piirtoalustalle ja erilaisiin komponentteihin, kuten painikkeisiin. Jos halutaan käyttää muuntyyppisiä kuvatiedostoja (esim..jpg), ei PhotoImage-luokka yksin riitä, mutta apuna voidaan käyttää Pillow-moduulin tarjoamia luokkia. Seuraavilla kalvoilla on kaksi esimerkkiä, joista ensimmäisessä kuvatiedoston sisältämä kuva on liitetty piirtoalustalle ja toisessa kuva on liitetty painikkeeseen. CS-A1111 Ohjelmoinnin peruskurssi Y1 8.11.2017 24 / 30
Kuvaesimerkki 1 from tkinter import * class Kuvaikkuna1: def init (self): self. paaikkuna = Tk() self. paaikkuna.title("kuvaesimerkki") self. paaikkuna.geometry("400x400") self. teksti = Label(self. paaikkuna, \ text = " Hauskaa talvea! ") self. teksti.pack() self. alusta = Canvas(self. paaikkuna, \ width = 350, height = 350) CS-A1111 Ohjelmoinnin peruskurssi Y1 8.11.2017 25 / 30
Kuvaesimerkki 1, jatkoa self. kuva = PhotoImage(file = "aurinko2.gif") self. alusta.create_image(150, 150,\ image = self. kuva) self. alusta.pack() mainloop() oma_ikkuna = Kuvaikkuna1() CS-A1111 Ohjelmoinnin peruskurssi Y1 8.11.2017 26 / 30
Kuvaesimerkki 2 from tkinter import * import tkinter.messagebox class Kuvaikkuna2: def init (self): self. paaikkuna = Tk() self. paaikkuna.title("kuvaesimerkki2") self. paaikkuna.geometry("100x100") self. kuva = PhotoImage(file = "pyoryla.gif") self. nappi = Button(self. paaikkuna, \ image = self. kuva, \ command = self.anna_ilmoitus) self. nappi.pack() mainloop() CS-A1111 Ohjelmoinnin peruskurssi Y1 8.11.2017 27 / 30
Kuvaesimerkki 2 jatkuu def anna_ilmoitus(self): tkinter.messagebox.showinfo("vastaus", \ "Olitko utelias?") oma_ikkuna = Kuvaikkuna2() CS-A1111 Ohjelmoinnin peruskurssi Y1 8.11.2017 28 / 30
Skandinaaviset aakkoset ja muut erikoismerkit Tekstitiedostoja myös Python-ohjelmia kirjoitettaessa tietokone tallentaa tiedoston niin, että kutakin tiedoston merkkiä vastaa tietokoneen muistissa jokin luku. Skandinaaviset aakkoset aiheuttavat erityisongelmia, koska eri tallennustavoissa samaa merkkiä (esimerkiksi ä) vastaa eri luku. Sitä, mikä luku vastaa mitäkin merkkiä, kutsutaan koodaukseksi. Python 3:ssa on oletuksena se, että esimerkiksi merkkijonojen sisältävät merkit on muutettu luvuiksi käyttämällä utf-8-koodausta. Jos ohjelmaa kirjoitettaessa on käytetty jotain muuta koodausta, ja ohjelma sisältää (esimerkiksi tulostettavissa merkkijonoissa) skandinaavisia aakkosia tai muita erityismerkkejä, on ohjelmatiedoston alkuun kirjoitettava kommentti, joka kertoo käytetyn koodauksen. CS-A1111 Ohjelmoinnin peruskurssi Y1 8.11.2017 29 / 30
Skandinaaviset aakkoset ja muut erikoismerkit, jatkoa Alla on joitakin yleisiä koodaustapoja vastaavia alkukommentteja. # -*- coding: utf-8 -*- # -*- coding: cp850 -*- # -*- coding: cp1252 -*- # -*- coding: iso-latin-1 -*- # -*- coding: iso-latin-15 -*- CS-A1111 Ohjelmoinnin peruskurssi Y1 8.11.2017 30 / 30