Ohjelmoinnin peruskurssien laaja oppimäärä



Samankaltaiset tiedostot
Luento 5. T Ohjelmoinnin jatkokurssi T1 & T Ohjelmoinnin jatkokurssi L1. Luennoitsija: Otto Seppälä

JAVA-OHJELMOINTI 3 op A274615

Luento 6. T Ohjelmoinnin jatkokurssi T1 & T Ohjelmoinnin jatkokurssi L1. Luennoitsija: Otto Seppälä

Olio-ohjelmointi Käyttöliittymä

Ohjelmoinnin peruskurssien laaja oppimäärä

Osio 4: Graafinen käyttöliittymä

GRAAFISEN KÄYTTÖLIITTYMÄN OHJELMOINTI JAVA SWING

Ohjelmoinnin perusteet Y Python

Java ja grafiikka. Ville Sundberg

Graafisen käyttöliittymän ohjelmointi

Eclipse & WindowBuilder

Graafinen käyttöliittymä, osa 2

Graafinen käyttöliittymä, osa 1

Osio 4: Graafinen käyttöliittymä

Osio 4: Graafinen käyttöliittymä

Osio 4: Graafinen käyttöliittymä

Sovelmat. Janne Käki

Java layoutit. Juha Järvensivu 2007

Ohjelmoinnin jatkokurssi, kurssikoe

JAVA-PERUSTEET. JAVA-OHJELMOINTI 3op A JAVAN PERUSTEET LYHYT KERTAUS JAVAN OMINAISUUKSISTA JAVAN OMINAISUUKSIA. Java vs. C++?

Ohjelmoinnin peruskurssien laaja oppimäärä

Tapahtumapohjainen ohjelmointi

Tapahtumapohjainen ohjelmointi. Juha Järvensivu 2007

Osio 4: Graafinen käyttöliittymä

Ohjelmoinnin peruskurssien laaja oppimäärä

Tapahtumapohjainen ohjelmointi. Juha Järvensivu 2008

Osio 4: Graafinen käyttöliittymä

Oliosuunnitteluesimerkki: Yrityksen palkanlaskentajärjestelmä

Ohjelmassa henkilön etunimi ja sukunimi luetaan kahteen muuttujaan seuraavasti:

Ohjelmointi 2 / 2010 Välikoe / 26.3

Rajapinta (interface)

7. Näytölle tulostaminen 7.1

JAVA-OHJELMOINTI 3 op A274615

Tietorakenteet, laskuharjoitus 7,

Opintojakso TT00AA11 Ohjelmoinnin jatko (Java): 3 op Taulukot & Periytyminen

Harjoitus Olkoon olemassa luokat Lintu ja Pelikaani seuraavasti:

Olio-ohjelmointi Suunnittelumallit Adapter ja Composite. 1. Adapter

Metodien tekeminen Javalla

Ohjelmoinnin peruskurssien laaja oppimäärä

1. Omat operaatiot 1.1

8. Näppäimistöltä lukeminen 8.1

5. HelloWorld-ohjelma 5.1

Flash ActionScript osa 4

Ohjelmoinnin perusteet Y Python

Graafinen käyttöliittymä, osa 3

Harjoitus 3: Flash-komponenttiarkkitehtuuri ( )

Sisällys. 12. Näppäimistöltä lukeminen. Yleistä. Yleistä

5 Näppäimistö. 5.1 Näppäimistön eventit

9. Periytyminen Javassa 9.1

Ohjelmointitaito (ict1td002, 12 op) Kevät Java-ohjelmoinnin alkeita. Tietokoneohjelma. Raine Kauppinen

Olio-ohjelmointi Javalla

Vesisika. metsiemme työmyyrä.

Ikkunointijärjestelmät

Sisällys. 1. Omat operaatiot. Yleistä operaatioista. Yleistä operaatioista

CODEONLINE. Monni Oo- ja Java-harjoituksia. Version 1.0

812341A Olio-ohjelmointi, IX Olioiden välisistä yhteyksistä

8. Näppäimistöltä lukeminen 8.1

Ohjelmoinnin perusteet Y Python

kertaa samat järjestykseen lukkarissa.

Sisällys. JAVA-OHJELMOINTI Osa 7: Abstrakti luokka ja rajapinta. Abstraktin luokan idea. Abstrakti luokka ja metodi. Esimerkki

Rajapinnasta ei voida muodostaa olioita. Voidaan käyttää tunnuksen tyyppinä. Rajapinta on kuitenkin abstraktia luokkaa selvästi abstraktimpi tyyppi.

Lohkot. if (ehto1) { if (ehto2) { lause 1;... lause n; } } else { lause 1;... lause m; } 16.3

Ohjelmoinnin peruskurssien laaja oppimäärä

JAVA on ohjelmointikieli, mikä on kieliopiltaan hyvin samankaltainen, jopa identtinen mm. C++

Javan GUI Scratchaajalle

Opintojakso TT00AA11 Ohjelmoinnin jatko (Java): 3 op Rajapinnat ja sisäluokat

Ohjelmoinnin peruskurssi Y1

JUnit ja EasyMock (TilaustenKäsittely)

812341A Olio-ohjelmointi Peruskäsitteet jatkoa

Jypelin käyttöohjeet» Ruutukentän luominen

Javan GUI Scratchaajalle

1 Tehtävän kuvaus ja analysointi

Suunnittelumalleja, MVC. Juha Järvensivu 2008

ITKP102 Ohjelmointi 1 (6 op)

Lohkot. if (ehto1) { if (ehto2) { lause 1;... lause n; } } else { lause 1;... lause m; } 15.3

Pedacode Pikaopas. Java-kehitysympäristön pystyttäminen

Ohjelmoinnin perusteet Y Python

Opintojakso TT00AA11 Ohjelmoinnin jatko (Java): 3 op

4. Luokan testaus ja käyttö olion kautta 4.1

Metodit. Metodien määrittely. Metodin parametrit ja paluuarvo. Metodien suorittaminen eli kutsuminen. Metodien kuormittaminen

Laskuharjoitus 9, tehtävä 6

Java kahdessa tunnissa. Jyry Suvilehto

Ohjelmoinnin perusteet, syksy 2006

Tämän lisäksi listataan ranskalaisin viivoin järjestelmän tarjoama toiminnallisuus:

Luokka Murtoluku uudelleen. Kirjoitetaan luokka Murtoluku uudelleen niin, että murtolukujen sieventäminen on mahdollista.

2. Lisää Java-ohjelmoinnin alkeita. Muuttuja ja viittausmuuttuja (1/4) Muuttuja ja viittausmuuttuja (2/4)

Taulukot. Jukka Harju, Jukka Juslin

12. Näppäimistöltä lukeminen 12.1

Pakkauksen kokoaminen

Operaattoreiden ylikuormitus. Operaattoreiden kuormitus. Operaattoreiden kuormitus. Operaattoreista. Kuormituksesta

Sisällys. 11. Rajapinnat. Johdanto. Johdanto

BlueJ ohjelman pitäisi löytyä Development valikon alta mikroluokkien koneista. Muissa koneissa BlueJ voi löytyä esim. omana ikonina työpöydältä

Tällä harjoituskerralla on tarkoituksena harjoitella käyttötapaus-, luokka- ja tapahtumasekvenssikaavioiden luontia.

Pakkauksen kokoaminen

OpenOffice.org Impress 3.1.0

ohjeita kirjautumiseen ja käyttöön

Harjoitustyö (TKO_2023)

Tehtävä 1. Tehtävä 2. Arvosteluperusteet Koherentti selitys Koherentti esimerkki

Dialogit. Juha Järvensivu 2008

Sisältö. 22. Taulukot. Yleistä. Yleistä

Transkriptio:

Ohjelmoinnin peruskurssien laaja oppimäärä Luento 18: Graaset käyttöliittymät Riku Saikkonen (merkityt ei-laajan kurssin kalvot: Otto Seppälä) 3. 3. 2011

Sisältö 1 Graasten käyttöliittymien oliomalli 2 Graikan piirtäminen itse 3 Komponentteja ja säiliöitä 4 Komponenttien asettelu 5 Tapahtumankäsittelijät 6 Composite- ja Observer-suunnittelumallit 7 Lisälukemista

Yleiskatsaus Graafinen käyttöliittymä sisältää nappeja, menuja, checkboxeja, paneeleja jne... Jotta voi rakentaa toimivan graafisen käyttöliittymän, tarvistee tietää : kuinka graafisia komponentteja luodaan kuinka ne saadaan näkyviin ruudulle kuinka ne saadaan ruudulla sinne minne halutaan kuinka ne saadaan tekemään jotain

Miten luodaan graafinen komponentti? Graafisia komponentteja luodaan kuten mitä tahansa muita javan olioita. JButton painike; painike = new JButton( Paina tästä! ); JFrame ikkuna; ikkuna = new JFrame( Ikkunan otsikko ); JPanel paneeli; paneeli = new JPanel(); //Paneeliin voi laittaa muita komponentteja

Miten komponentin saa mukaan käyttöliittymään? Osa käyttöliittymän osista on tarkoitettu toisten graafisten komponenttien säilytykseen ns. Container (säiliö) Näistä lisää myöhemmin luennolla Komponentin saa käyttöliittymän osaksi lisäämällä sen johonkin ikkunaan tai ikkunan sisältämään säiliöön komponenttien lisäämisestä säiliöihin myöhemmin luennolla Se tulee ruudulle kun ikkuna, jonka sisällä se on, laitetaan näkyviin Ikkunan laittamisesta näkyviin myöhemmin luennolla

Miten komponentin saa haluaansa paikkaan ruudulla? Komponenttien sijoittelu tehdään ns. Layout managerilla Layout manager yrittää parhaansa mukaan sijoitella komponentit jonkin säiliön sisällä ohjelmoijan toiveiden mukaisesti. Eri managerit asettelevat komponentit eri tavoin. Jokaisella säiliöllä on siis Layout manager, joka päättää miten sen sisältämät komponentit laitetaan esille tästä lisää myöhemmin luennolla

Missä graaset käyttöliittymät ovat tällaisia? melkein kaikki graaset käyttöliittymäkirjastot käyttävät samankaltaista oliomallia jopa kielissä, jotka eivät tue olioita (esim. C ja GTK) siellä olioita simuloidaan kuten kevään Scheme-tehtävissä malli on myös perusrakenteeltaan useimmiten hyvin samanlainen komponentteja, säiliöitä, sijoitteluasetuksia, painalluksiin ym. tapahtumiin reagoimista, jne. komponentitkin ovat enimmäkseen samoja, joskin eri näköisiä vaihtoehtoisia malleja (harvinaisia): matalamman tason malli: kirjasto tarjoaa vain piirtoalustan, ei komponentteja (esim. SDL, OpenGL) lomakemalli: esim. WWW-sivu tarjoaa lomakkeen ja saa sen täytettynä selaimelta (Web-sovelluksille tämä ei yleensä riitä) muitakin (esim. funktionaalisia) GUI-malleja on esitetty, mutta lähinnä tutkimusmielessä

Sisältö 1 Graasten käyttöliittymien oliomalli 2 Graikan piirtäminen itse 3 Komponentteja ja säiliöitä 4 Komponenttien asettelu 5 Tapahtumankäsittelijät 6 Composite- ja Observer-suunnittelumallit 7 Lisälukemista

AWT-kirjasto Java API:ssa on kaksi graafisten käyttöliittymien kasaamiseen tarkoitettua kirjastoa AWT Swing AWT Abstract Windowing Toolkit on Java APIn kahdesta GUIkirjastosta vanhempi Tällä kurssilla käytetty kirjasto on Swing Tulemme tarvitsemaan (ei komponentti)-luokkia myös AWT:stä Monet Swing-kirjaston luokista käyttävät AWT-luokkia tai periytyvät suoraan niistä.

Grafiikkaa Swingillä Oman grafiikan piirtäminen Swing-käyttöliittymässä on varsin helppoa. 1) Periytä uusi luokka JPanel-luokasta 2)Korvaa paintcomponent(graphics g)-metodi Graphics-luokan API-dokumentaatiosta selviää mitä kaikkea sillä voi tehdä piirtää ympyröitä, suorakulmioita, viivoja, tekstiä jne... Swing komponenttien paintcomponent-metodin parametri on yleensä Graphics2D-tyyppinen tyyppipakotuksen jälkeen voit piirtää myös bezier-käyriä, jne... Seuraavassa yksinkertainen esimerkki... 21:32

import java.awt.color; import java.awt.dimension; import java.awt.graphics; import javax.swing.jpanel; public class Ympyra extends JPanel { // piirretään Graphics-olion kautta ruudulle // punainen ympyrä ja tekstiä public void paintcomponent ( Graphics g ) { g.setcolor( Color.RED ); g.drawstring( "Maailman hienoin ympyrä!", 10, 10 ); g.drawoval(20,30,100,100); } // pyydetään vähän enemmän tilaa ettei pack // paina komponenttia kasaan. public Dimension getpreferredsize() { return new Dimension(200,200); } paintcomponent-metodia kutsutaan automaattisesti kun käyttöliittymän alue piirretään. Tyypillisesti et siis kirjoita tämän metodin kutsua minnekään itse. } 21:32

import javax.swing.jframe; public class PaaIkkuna extends JFrame { public static void main( String[] args ) { PaaIkkuna ikkuna = new PaaIkkuna(); ikkuna.setvisible(true); ikkuna.pack(); } public PaaIkkuna() { super("maailman hienoin ikkuna"); //Ikkunan sulkeminen lopettaa koko ohjelman this.setdefaultcloseoperation(jframe.exit_on_close); } Ympyra ympyra = new Ympyra(); this.getcontentpane().add(ympyra); } 21:32

Entä Scalassa? Scalassa käytetään samaa Swing-kirjastoa kuin Javassa kuitenkin hieman eri tavalla: Java-rajapinnan päälle on tehty Scala-maisempi rajapinta pakettiin scala.swing perusrakenne on sama, mutta muutama yksityiskohta on tehty eri lailla (esim. layout managerit ja tapahtumat) moni asia toimii samoin kuin Javassa (ja melkein kaikkea voi tehdä Java-tavalla, Scala-tapa vain voisi olla siistimpi) esimerkiksi piirtämiseen Scalassa ei ole varsinaisesti mitään omaa: käytetään samoja Graphics- tai Graphics2D-luokan metodeja valitettavasti dokumentaatio on (vielä?) hajallaan Java- ja Scala-kirjastojen dokumenteissa ja Scalan Swing-kirjasto on muuttunut Scalan mukana mutta tällä kurssilla ei tarvitse mennä yksityiskohtiin

Mitä paintcomponentin pitää tehdä? GUI-kirjastoissa piirtämistä ei yleensä voi tehdä vain kutsumalla piirroskomentoja sieltä täältä muualta ohjelmasta sillä ohjelman pitää milloin tahansa osata piirtää ikkunansa uudelleen käytännössä paintcomponent-metodia kutsutaan esim. kun käyttäjä tuo ikkunan näkyviin toisen ikkunan alta käyttöliittymäkirjasto ei siis (yleensä) talleta piirrettyä kuvaa mihinkään itse joissain käyttöliittymäkirjastoissa voidaan myös pyytää piirtämään uudelleen vain osa komponentista yleensä paintcomponent tehdään piirtämään ikkuna jossain muualla ohjelmassa tallessa olevien ohjeiden mukaan poikkeus: jos kuva vaihtuu tiheään (esim. reaaliaikainen peli, jonka kuva päivittyy monta kertaa sekunnissa), ei välttämättä ole hyötyä piirtää vanhaa kuvaa uudelleen

Sisältö 1 Graasten käyttöliittymien oliomalli 2 Graikan piirtäminen itse 3 Komponentteja ja säiliöitä 4 Komponenttien asettelu 5 Tapahtumankäsittelijät 6 Composite- ja Observer-suunnittelumallit 7 Lisälukemista

Komponenttityypit Esimerkki: www-selaimen ikkuna sisältää tyypillisesti valikkorivin, jonkinlaisen painikkeiden rivin, tilan jossa wwwsivut näytetään, sekä jonkinlaisen statusrivin ruudun alalaidassa Valikkorivi sisältää joukon valikoita Jokainen valikko taas sisältää joukon valikkoalkioita Painikerivi sisältää painikkeita sekä tekstikentän johon sivun osoitteen voi kirjoittaa Graafiset komponentit voivat sisältää toisia graafisia komponentteja. Vastaavasti näiden sisään voidaan asettaa toisia komponentteja Pohdi, millaisiin suorakaiteen muotoisiin alueisiin käyttämäsi ohjelman käyttöliittymä jakautuu

JPanel Mikäli olisimme rakentamassa mainitun kaltaista selainta, voisi painike/osoiteriviä kuvata luokan JPanel oliolla. JPanel on komponentti, jonka tehtävä on toimia kuin laatikko, johon voidaan lisätä joukko muita komponentteja. Säiliöt Käyttöliittymät rakennetaan tyypillisesti tällaisista laatikoista, joilla tila saadaan jaettua sopivankokoisiin ja muotoisiin suorakaiteisiin. JPanelin lisäksi monet muutkin komponentit voivat sisältää muita komponentteja: JFrame, JWindow, JScrollpane, jne.. Tällaisia komponentteja, joiden tehtävä on tavallaan säilöä muita komponentteja ja jäsentää niiden sijoittelua kutsutaan yhteisesti nimellä container, säiliö

Top-level Containers Top-level container on säiliö, jota ei voi (eikä tarvitse) sisällyttää muihin säiliöihin. Jotta muita komponentteja voitaisiin näyttää ruudulla, niiden täytyy sisältyä komponenttien hierarkiaan, jonka huipulla on jokin Swingin Top-level Container. JFrame Ohjelman ikkuna JApplet www-sivuille sijoitettava sovelma JDialog Apuikkuna, jolla voidaan esittää eri kysymyksiä jne. Vaikkapa ladattavan tiedoston valinta, jne. Jokainen Swing:in ylimmän tason säiliö sisältää alueen nimeltä contentpane johon lisättävät komponentit lisätään. Tähän alueeseen haetaan viittaus metodilla getcontentpane() jonka jälkeen sen kanssa voi toimia pitkälti kuin se olisi JPanel

JButton Ehkä helpoimmin hahmotettava Swing:in komponenteista on painonappi, JButton Napissa voi esittää joko tekstiä, kuvan tai molemmat. Halutessa teksti voi olla myös HTML-muotoista, jolloin sitä voi muotoilla vapaammin. Yleisesti tarvittavia metodeja luokassa on vähän. Alla annetulla listalla pärjää pitkälle. konstruktorit addactionlistener kuuntelijoiden lisäämiseen setenabled asettaa sen, toimiiko nappi vai onko se inaktiivinen, harmaa settext(string teksti) vaihtaa nappulan tekstin

Tekstikomponentteja JLabel komponentti, johon ei tyypillisesti liity mitään toiminnallisuutta. Sen avulla voi halutussa tilassa esittää jotakin tekstiä. JTextField yksirivinen tekstikenttä, jonka sisältöä voi tarvittaessa muuttaa. Tekstin muuttumista voi seurata ActionListenerillä, joka reagoi enter:in painallukseen Vastaavasti tekstin muuttumista sitä muutettaessa voi seurata liittämällä tekstikentän sisältämään tekstidokumenttiin DocumentListener:in Tekstin voi toki lukea milloin vain, esim kun muualla käyttöliittymässä painetaan jotain nappia. JPasswordField kuten edellä, mutta arvattavin muutoksin

Entä Scalassa? Swing-komponenteista ja säiliöistä on myös Scala-versiot paketin scala.swing luokat ja oliot yleensä sama nimi kuin Javassa mutta ilman J-kirjainta alussa Java-rajapintaakin voi käyttää (tai molempia sekaisin) Scala-rajapintakin luo taustalle samat Java-Swingin oliot Pieni graanen Scala-ohjelma HelloGUI.scala import scala.swing._ import scala.swing.event._ object HelloGUI extends SimpleSwingApplication { def top = new MainFrame { title = "Hello" val label = new Label { text = "Hello, world!" } val quit = new Button { text = "Quit" } contents = new GridBagPanel { var c = new Constraints add(label, c); add(quit, c) border = Swing.EmptyBorder(15, 15, 15, 15) } listento(quit) reactions += { case ButtonClicked(`quit`) => exit(0) } } }

Sisältö 1 Graasten käyttöliittymien oliomalli 2 Graikan piirtäminen itse 3 Komponentteja ja säiliöitä 4 Komponenttien asettelu 5 Tapahtumankäsittelijät 6 Composite- ja Observer-suunnittelumallit 7 Lisälukemista

Komponenttien asettelu Sijoittelu Kuten jo mainittiinkin, on käyttöliittymäkirjastossa ns. säiliöitä (container), jotka voivat sisältää toisia komponentteja. Komponentin voi lisätä säiliöön antamalla sen parametrina säiliön metodille add(komponentti) Vastaavasti komponentin voi poistaa metodilla remove(komponentti) Säiliö pitää listaa sisältämistään komponenteista, esim. jotta se voisi tarvittaessa välittää tapahtumia se voisi pyytää sisältämiään komponentteja piirtämään itsensä Huom: Composite-suunnittelumalli se voisi laskea komponenteille tarvittaessa uuden sijoittelun ruudulla

Komponenttien asettelu Milloin viimeksi näit ohjelman jonka ikkunan kokoa ei saanut muuttaa? (poislukien pelit...) Javalla rakennettujen käyttöliittymien yksi perusidea on, että komponenteille ei määrätä kiinteitä paikkoja ruudulla, vaan niiden paikat ja sijainnit muuttuvan dynaamisesti, kun säiliö, johon ne on lisätty muuttaa muotoaan. Jokaiseen Javan säiliötyyppiin on liitetty ns. Layout Manager, joka laskee säiliön sisältämille komponenteille nämä paikat

Komponenttien asettelu AWT API:n mukana tulee joukko erilaisia Layout Managereja, joista seuraavassa muutama yleisimmin käytetty FlowLayout Asettelee komponentit riveittäin (kuten tekstin sanat), kunnes riville ei mahdu enempää, jolloin vaihdetaan riviä. GridLayout Asettelee komponentit taulukkoon siten että jokaisen komponentin leveys ja korkeus ovat samat. Venyttää komponentit niin että ne täyttävät koko ruudun. BoxLayout Asettelee komponentit joko vaakaan tai pystyyn, niin että asettelusuunnassa komponentit ovat halutun kokoisia (preferredsize) ja toisessa suunnassa saman kokoisia. Näillä kolmella pääsee jo pitkälle...

Komponenttien asettelu...jatkuu GridBagLayout Monimutkaisempi layout manager, jolla voi tehdä melkein mitä vain (mm. imitoida kaikkia yllämainittuja managereja) Tällä voi asettaa osan komponenteista vakiokokoisiksi, osan kokoaan muuttaviksi jne.

Komponenttien asettelu Älä yritä tehdä kaikkea kerralla. Käytännössä käyttöliittymän rakentamisessa käytetään apuna säiliöitä, kuten JPanel, joilla alue ensin jaetaan osiin. luonnollisesti paneelienkin koot määrää jokin layout manager Jokaisen paneelin sisällön voi jakaa halutessaan alipaneeleihin jne. ja määritellä näille kaikille tilanteeseen sopivat layout managerit. pack() On usein kätevää kutsua ylimmän tason säiliölle juuri ennen sen asettamista näkyviin metodia pack(). pack() asettelee säiliön ja muuttaa ikkunan sen kokoiseksi että kaikki komponentit näkyvät, mikäli mahdollista.

Muuta asettelusta joskus asettelussa ei tueta ikkunoiden koon muuttamista vaan komponentit sijoitetaan pikselikoordinaatistoon jolloin erilaisia säiliöluokkia ja layout manageria tms. ei tarvita mutta tämän aiheuttama jäykkyys näkyy ohjelmoijallekin: esimerkiksi tekstien kääntäminen toiselle kielelle voi vaatia ikkunan skaalaamista monissa GUI-kirjastoissa on myös erillinen graanen työkalu käyttöliittymien tekemiseen useimmiten tukevat myös skaalattavien ikkunoiden tekemistä (eri säiliöluokkia yms.) tuottavat joko koodia tai datatiedoston, jonka voi ladata koodista

Sisältö 1 Graasten käyttöliittymien oliomalli 2 Graikan piirtäminen itse 3 Komponentteja ja säiliöitä 4 Komponenttien asettelu 5 Tapahtumankäsittelijät 6 Composite- ja Observer-suunnittelumallit 7 Lisälukemista

Miten GUI-ohjelmaa suoritetaan? useimmiten graasissa ohjelmissa ohjelman suoritusmalli on erilainen kuin tavallisissa ohjelman kannalta katsottuna (yksinkertaistaen): main-metodia tms. ei ole (tai siinä ei näy kaikkea) ohjelmasta ei näy suoritusjärjestystä, jossa asiat tapahtuvat vaan ohjelma toimii reagoimalla tapahtumiin (event) esim. käyttöliittymän napin painaminen käynnistää tätä tapahtumaa käsittelevän koodin ei siis niin päin, että koodin keskellä olisi read-kutsu tms., joka jäisi odottamaan ja palauttaisi käyttäjältä saadun syötteen useimmat yksittäiset tapahtumankäsittelijät ovat melko yksinkertaisia ja muuttavat ohjelman tilaa (esim. globaaleja muuttujia) tapahtuman mukaisesti

Mitä oikeasti tapahtuu? miten edellä kuvattu tapahtumapohjainen suoritusmalli toteutetaan? GUI-ohjelmassa on main, joka luo käyttöliittymäkomponentit ja jää lopulta silmukkaan (ns. event loop) odottamaan tapahtumia tämä silmukka on normaalisti GUI-kirjaston sisällä eli ei suoraan näy itse ohjelmassa silmukka lähettää kunkin tapahtuman sen käsittelijälle tapahtumankäsittelijä on funktio tai metodi, jonka ohjelmoija on esim. käyttöliittymäkomponenttia luodessaan antanut tee nappi, jonka painalluksista kutsutaan tätä funktiota tällainen funktio on nimeltään takaisinkutsu (callback function) sitä ei (yleensä) kutsuta suoraan ohjelmasta käsin tapoja ajatella: suoritus on asynkronista (ei siis tahdissa käsky kerrallaan) tai reaktiivista (reagoidaan tapahtumiin eikä jäädä kesken koodin odottamaan vastausta)

Peräkkäin vai yhtäaikaa? yleensä tapahtumankäsittelijöitä kutsutaan peräkkäin ei siis yhtäaikaa eli rinnakkain tyypillisesti käyttöliittymä ei reagoi, kun suoritus on tapahtumankäsittelijäfunktion sisällä joten funktion on syytä olla nopea entä jos GUI-ohjelmassa haluaa tehdä jotain pitkäkestoista? kirjastoissa on erikseen tapa määritellä taustalaskentaa (kutsu tätä aina kun tapahtumia ei ole saatavilla) sekä ajastettuja tapahtumia (kutsu tätä sekunnin välein) mutta näitäkin kutsutaan muun tapahtumakäsittelyn joukossa, joten yksittäisen funktion suoritus ei saa kestää kauaa (muuten käyttöliittymä jää jumiin siksi aikaa) pitkäkestoinen laskenta pitää siis paloitella lyhyisiin osiin toinen tapa on käyttää rinnakkaisuutta (josta myöhemmällä luennolla)

Tapahtumat - events Event Kun hiirellä tai näppäimistöllä tehdään yleensä ottaen mitä tahansa käyttöliittymässä, syntyy tapahtumia Komponentit tiedottavat niihin kohdistuneista käyttöliittymätapauksista luomalla tapahtunutta kuvaavan tapahtumaolion Tapahtumaolio sisältää kaiken olennaisen tiedon tapahtuneesta asiasta Näitä tietoja tapahtumia seuraava taho, tapahtumankuuntelija, voi käyttää miten haluaa Vrt. kirjeenvaihto Tapahtumaolio (Event) on kuin kirje jolla lähettäjä kertoo kaikille ystävilleen mitä lähettäjälle on tapahtunut EventListener (selitetään kohta) on kirjeen vastaanottaja

Tapahtumat - events Tapahtumatyyppejä on monia erilaisia Eri tyyppisille asioille on kaikille omat AWTEventluokan aliluokkansa ActionEvent kuvaa jotakin komponenttiin liittyvää korkean tason tapahtumaa, kuten napin painaminen jne. Tällöin komponenttia kuuntelevat oliot voivat keskittyä siihen, mitä tapahtui, sen sijaan että niiden tarvitsisi tulkita komponentin tapahtumia hiiren tai näppäimistön toiminnasta kertovista tapahtumista. ActionEvent:it lähetetään kaikille ActionListener-olioille jotka on rekisteröity komponentin kuuntelijoiksi

Tapahtumat - events Lisää tapahtumia MouseEvent kertoo hiiren painalluksista MouseMotionEvent hiiren liikkeistä ComponentEvent komponenttien kokojen muutoksista, näkymisestä jne AdjustmentEvent scrollbar :ien arvojen muutoksista jne... (näitä on paljon)

Tapahtumankuuntelijat Tapahtumankuuntelijaksi, (EventListener) kutsutaan oliota, joka: Täyttää halutun kuuntelijarajapinnan Sisältää usein vain muutaman metodin, joita kuunneltava komponentti kutsuu kun jotain tapahtuu esim ActionListener-rajapinnan void actionperformed(actionevent ae) Tyypillisesti metodi vain saa parametrina tapahtumaolion, joka kuvaa mitä tapahtui. Voidaan rekisteröidä kuuntelemaan mitä jossakin komponentissa tapahtuu. Kuuntelee vain tietyntyyppisiä tapahtumia esim public void addactionlistener(actionlistener lisattavakuuntelija)

TapahtumanKuuntelijat Esimerkki : painonapin (Button) painamiseen reagoiva ohjelma public class NapinKuuntelija implements ActionListener { public void actionperformed(actionevent tapahtuma){ System.out.println( Nappia painettiin!! ); } } public class JokuLuokka extends...{ private JButton painike;... painike = new JButton( Paina tästä! ); painike.addactionlistener(new NapinKuuntelija());... }

Tapahtumankäsittelijät Scalassa Osa edellisestä esimerkistä val quit = new Button { text = "Quit" }... listento(quit) reactions += { case ButtonClicked(`quit`) => exit(0) } } } HelloGUI.scala Scalassa on oma rajapinta tapahtumien käsittelyyn koodi on vähän Javaa lyhyempää myös Java-mallia (ActionListener) voi halutessaan käyttää listento(quit) kertoo, että quit-napin tapahtumat annetaan reactions-kokoelman funktioille reactionsiin voi lisätä funktioita niin paljon kuin haluaa ButtonClicked(`quit`) sovittaa hahmon case classiin, jossa parametrina on quit-muuttujassa oleva olio: kuten ButtonClicked(x) if x == quit { case... } on ns. osittain määritelty (partially applied) funktio: tekee jotain vain jos hahmo sopii

Esimerkki ajastetusta tapahtumasta Digitaalinen kello-ohjelma Clock.scala object Clock extends SimpleSwingApplication { def top = new MainFrame { title = "Clock" val label = new Label { text = "000 000 00 00:00:00 0000 0000" } val start = new Button { text = "Start" } val stop = new Button { text = "Stop" } contents = new GridBagPanel { var c = new Constraints c.insets = new java.awt.insets(10, 10, 10, 10) c.gridwidth = 2; add(label, c) c.gridwidth = 1; c.gridy = 1; add(start, c); add(stop, c) border = Swing.EmptyBorder(15, 15, 15, 15) } val timerlistener = new java.awt.event.actionlistener() { def actionperformed(evt: java.awt.event.actionevent) { val s = java.util.calendar.getinstance.gettime.tostring label.text = s } } val timer = new javax.swing.timer(1000, timerlistener) listento(start, stop) reactions += { case ButtonClicked(`start`) => timer.start() case ButtonClicked(`stop`) => timer.stop() } } }

Sisältö 1 Graasten käyttöliittymien oliomalli 2 Graikan piirtäminen itse 3 Komponentteja ja säiliöitä 4 Komponenttien asettelu 5 Tapahtumankäsittelijät 6 Composite- ja Observer-suunnittelumallit 7 Lisälukemista

Composite Joissakin tietorakenteissa (esim. puu) rakenteen osaset koostuvat pienemmistä osasista (lapset), jotka taas koostuvat pienemmistä osasista jne. Composite-mallissa koko rakenteelle voi suorittaa operaation tekemällä sen vain yhdelle osaselle Toteutuksessa suurempaa rakennetta ja sen osasia käsitellään samalla tavalla. Kaikki osaset täyttävät saman rajapinnan. Isomman rakenteen operaatio tehdään myös sen lapsille 10:03

Composite Esimerkki Tekstinkäsittelyohjelma, jossa kappaleet koostuvat alikappaleista ja tekstistä, jotka molemmat täyttävät rajapinnan TekstiRakenne TekstiRakenne-luokassa on metodi oikolue() Kappale-luokan oikolue kutsuu metodia oikolue() sisältämilleen Kappale-olioille ja sisältämälleen Teksti-oliolle Teksti-olio suorittaa oikoluvun normaalisti. Etuja: Koko tekstin tai osan siitä voi oikolukea kutsumalla metodia oikolue vain kerran. Muun osan koodia ei tarvitse toimia eri tavalla riippuen siitä, millaista tekstirakennetta käsitellään, koska toiminta on 10:03 ulospäin samanlaista.

Composite UML-kaavio Huomaa että toteutuksessa erilaisia Komponentti-rajapinnan täyttäviä rakenteita voi olla paljon erilaisia, tai jopa vain yksi Käyttävä Luokka <<interface>> Komponentti +operaatio( ) lapset Alkio +operaatio() Komposiitti +operaatio() Suorittaa kaikille lapsille metodin operaatio() 10:03

Patterns & AWT/Swing Suunnittelumallit (Design Patterns) ovat kuvauksia toimivasta ratkaisusta johonkin yleiseen ongelmaan Joitakin Swing-grafiikkakirjastossa esiintyviä suunnittelumalleja Observer-pattern Tapahtumankuuntelijat Composite-pattern Komponenttien piirtäminen Komponenttien asettelu ruudulle Abstract Factory Käyttöliittymän ulkoasun vaihtaminen

Observer-Malli Observer-Malli Observer mahdollistaa toiminnan, jossa muutos yhdessä oliossa aiheuttaa automaattisesti muutoksen kaikissa siitä riippuvissa olioissa Riippuvat oliot vain pyytävät kiinnostavaa oliota kertomaan muutoksista Käytännössä kiinnostavalla oliolla on lista johon kiinnostuneet (Listener, Observer) voivat ilmoittautua Kun jotain tapahtuu, käydään jokainen listallaolija läpi ja kutsutaan jokaisen kohdalla ilmoitusmetodia. Yleensä ilmoitusmetodille vielä annetaan pikku viesti (Event) joka kuvaa tapahtuneen asian Kuunneltavan ei tarvitse tietää kuuntelijasta muuta kuin että se täyttää kuuntelija -rajapinnan

Observer UML-kaavio UML-luokkakaavio Tästä lisää muutaman luennon kuluttua... <<interface>> Havainnoitava +lisaakuuntelija( ) +poistakuuntelija( ) +ilmoitamuutos( ) havainnoijat[] <<interface>> Havainnoija +ilmoitamuutos() sopimus: rajapinnan täyttävä luokka kutsuu kaikkien havainnoijien metodia ilmoitamuutos() SeurattavaLuokka Toteutus voi reagoida muutokseen haluamallaan tavalla HavainnoijaToteutus

Observer Observer-malli Yksi parhaista esimerkeistä Observer-mallin käytöstä on javan Swing- ja AWT-käyttöliittymien käyttämät tapahtumankuuntelijat Käytännössä mallia voidaan käyttää mihin tahansa tilanteeseen, jossa useamman paikan ohjelmassa tulee reagoida johonkin muutokseen. Tulostus päättyy Puuhun lisätään solmu Äänikanava suljetaan jne..

import java.awt.event.*; import javax.swing.jbutton; import javax.swing.jframe; public class Example extends JFrame { private JButton mybutton; } public static void main(string args[]) { Example ex = new Example(); ex.setvisible(true); ex.setdefaultcloseoperation(jframe.exit_on_close); } } public Example(){ mybutton = new JButton("Press Me"); ActionListener hello = new HelloListener(); mybutton.addactionlistener(hello); mybutton.addactionlistener(new ActionListener(){ public void actionperformed(actionevent ae){ mybutton.settext("pressed!"); } }); this.getcontentpane().add(mybutton); pack(); class HelloListener implements ActionListener { public void actionperformed(actionevent ae) { System.out.println("Hello World!"); } } Esimerkki

Sisältö 1 Graasten käyttöliittymien oliomalli 2 Graikan piirtäminen itse 3 Komponentteja ja säiliöitä 4 Komponenttien asettelu 5 Tapahtumankäsittelijät 6 Composite- ja Observer-suunnittelumallit 7 Lisälukemista

Java Swing Tutorial Itseopiskelijalle suositellaan aloituspaikaksi Sunin Java Swing Tutorial sivustoa Java Swing tutorial http://java.sun.com/docs/books/tutorial/uiswing/ Yksittäisten komponenttien käyttöohjeet http://java.sun.com/docs/books/tutorial/uiswing/components/index.html

Muuta luettavaa Javan graasista käyttöliittymistä löytyy lisää myös ei-laajan kurssin kalvoista (luento 7. 2. GUI 1/2) Scalan Swing-kirjastosta kerrotaan mm. kirjassa Loverdos & Syropoulos: Steps in Scala (Cambridge Univ. Press, 2010) Javan ja Scalan API-dokumentaatio Swingistä: esim. paketista scala.swing voi lähteä liikkeelle: http://www.scala-lang.org/api/current/scala/swing/package.html tai hakea yksittäisiä asioita esim. Googlella (mutta Scalan Swing-kirjasto tuntuu muuttuvan tiheään) muutkin GUI-kirjastot ovat perusrakenteeltaan hyvin samanlaisia (esim. GTK, Qt ja Windowsin MFC ja Forms)