Luento 5 T-106.1240 Ohjelmoinnin jatkokurssi T1 & T-106.1243 Ohjelmoinnin jatkokurssi L1 Luennoitsija: Otto Seppälä Kurssin WWW: http://www.cs.hut.fi/opinnot/t-106.1240/s2007
Patterns & AWT/Swing Observer-pattern Tapahtumankuuntelijat Composite-pattern Komponenttien piirtäminen Komponenttien asettelu ruudulle Abstract Factory Käyttöliittymän ulkoasun vaihtaminen
Observer Observer 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 <<interface>> Havainnoitava +lisaakuuntelija( ) +poistakuuntelija( ) +ilmoitamuutos( ) havainnoijat[] Suorittaa kaikille havainnoijille metodin ilmoitamuutos() <<interface>> Havainnoija +ilmoitamuutos() SeurattavaLuokka HToteutus voi halutessaan reagoida muutokseen 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..
Observer import java.awt.*; import java.awt.event.*; public class Example extends Frame{ public static void main(string args[]){ new Example().start(); } public void start(){ final Button mybutton = new Button( Press Me ); ActionListener hello = new HelloListener(); mybutton.addactionlistener(hello); mybutton.addactionlistener(new ActionListener(){ public void actionperformed(actionevent ae){ mybutton.setlabel( Pressed! ); } }); add(mybutton); pack(); setvisible(true); } } public class HelloListener implements ActionListener{ public void actionperformed(actionevent ae){ System.out.println( Hello World! ); } }
Tulevia luentoja (alustava) 8.10 Graafiset käyttöliittymät, Versionhallinta Tapahtumat ja tapahtumankäsittely, GUI:n perustoiminnallisuus, Grafiikan piirtäminen. Versionhallinta. 15.10 Rinnakkaisohjelmoinnin alkeet Javan rinnakkaisuusprimitiivit, Luokka Thread, Runnablerajapinta, Perus Producer-Consumer esimerkkitoteutus, blocking, potentiaaliset ongelmat kuten deadlock. Graafiset käyttöliittymät ja rinnakkaisuus 22.10 Vaihtelevia aiheita Esim. Ohjelmien profilointi ja profiilien tulkinta, asiaa koodin optimoinnista, Lisää kirjastoja, yleiskatsaus palautettuihin suunnitelmiin ja ohjeistusta projektiin.
Graafiset käyttöliittymät
Graafiset käyttöliittymät AWT ja Swing-kirjastot Muutama peruskomponentti Tapahtumankäsittely Tapahtumaoliot Tapahtumankuuntelijat Komponenttien sijoittelu Komponenttien lisääminen ja poistaminen toisista komponenteista Layout managerit Grafiikka (ensi viikolla) Piirtäminen komponentteihin
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 Vaikka monet Swing-kirjaston luokista käyttävätkin AWT-luokkia tai periytyvät suoraan niistä, voimme aloittaa tutustumisen graafisiin käyttöliittymiin Swing-kirjastosta Tulemme tarvitsemaan luokkia myös täältä...
AWT-kirjasto Koko luokkahierarkian huipulla on luokka java.awt.component Kaikki graafiset komponentit (myös Swing-kirjaston) periytyvät tästä luokasta Napit, teksti-ikkunat, jne... Olennaisin Component-luokan aliluokka on luokka Container, joka kuvaa kaikkia komponentteja joihin voidaan lisätä muita komponentteja esim. painikkeita (Button) voidaan lisätä ikkunaan (Frame, Window)
Tapahtumat - events Event Komponentit tiedottavat niihin kohdistuneista käyttöliittymätapauksista luomalla tapahtunutta kuvaavan tapahtumaolion, (event) Tapahtumaluokkien hierarkian ylin luokka on java awt.event.awtevent, jonka metodeista alla kaksi tärkeintä public Object getsource(); Palauttaa komponentin jolta tapahtumaolio on lähtöisin public int getid() Palauttaa tapahtuman tyyppiä kuvaavan luvun. Tapahtumaluokissa on tyypillisesti määritelty vakioita, joihin lukua verrataan.
Tapahtumat - events Aina tapahtumaoliolle ei tarvitse kutsua metodeja lainkaan Joskus riittää vain tieto siitä että tapahtuma tapahtui. Nappia painettiin Hiirtä napsautettiin
Tapahtumat - events 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 Jokainen rekisteröity kuuntelija laitetaan talteen komponentin kentässä määriteltyyn listaan. Kun jotain tapahtuu luodaan tapahtumaolio, käydään lista läpi silmukalla ja kutsutaan jokaisen listan sisältämän kuuntelijan kohdalla olennaista metodia antaen parametrina tapahtumaolio.
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());... }
Swing-kirjasto Swing-kirjasto on nykyisin suurelta osin korvannut AWT-kirjaston. Käyttöliittymän kaikista komponenteista (Napit, ikkunat, jne.)on olemassa Swing-versiot Swing:in kanssa kuitenkin käytetään suurta joukkoa AWT:n ei-komponenttiluokkia, esim ActionListener Swing kirjasto sijaitsee paketissa javax.swing ja sen alipaketeissa
Swing-kirjasto Olennaisimmat erot AWT-kirjastoon ovat: Komponenttien lisäämisessä toisiin komponentteihin getcontentpane Komponenttien piirtämisessä paintcomponent Kaikki Swing-komponentit ovat lightweight, eli ne piirretään javan puolella (AWT sisälsi natiivikomponentteja)
Komponenttityypit www-selaimen ikkuna sisältää tyypillisesti valikkorivin, jonkinlaisen painikkeiden rivin, tilan jossa www-sivut 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
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 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
Top-level Containers Top-level container on säiliö, jota ei voi (eikä tarvitse) sisällyttää muihin säiliöihin. Jotta 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. Ylimmän tason säiliöihin voi lisätä myös valikoita. JWindow on muuten kuin JFrame, mutta se tarvitsee jo luontivaiheessa jonkin JFrame:n joka toimii sen isänä.
Top-level containers Koko käyttöliittymä ikkunoineen tulee näkyviin vasta kun ylimmän tason säiliölle kutsutaan metodia setvisible boolean-arvolla true. public void setvisible(boolean näkyykö)
Joitakin Swing- komponentteja
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
Säiliöluokkia Kehittyneemmät säiliöluokat JScrollPane on pitkälti kuin JPanel, joka mahdollistaa suurempien komponenttien näyttämisen esittämällä sisältämänsä komponentin vierityspalkeilla (scrollbar) varustettuna. JTabbedPane on komponentti joka mahdollistaa sisältönsä vaihtamisen painamalla haluttua välilehteä (tab). JSplitPane on komponentti joka sisältää näkymän joka on jaettu joko pysty tai vaakasuunnassa kahteen osaan. Tätä jakoa voi muuttaa hiirellä. Myös muita: LayeredPane
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
Tekstikomponentteja...Lisää tekstikenttiä ja editoreja JTextArea on karkeasti määriteltynä monirivinen versio JTextField:istä. Siihen ei voi lisätä ActionListener:iä, vaan muutoksia seurataan muilla kuuntelijoilla Kursorin paikka CaretListener Tekstin sisältö DocumentListener (komponentin sisältämään dokumenttiin ) Usein muutoksia ei tarvitse kuunnella, koska monesti käyttöliittymissä tapahtumat laukaistaan lopulta painamalla painikkeita. Sitten vain käydään lukemassa tämänhetkinen teksti Jos kuitenkin halutaan automaattisesti päivittää tietoja muualla ohjelmassa kuuntelijoita tarvitaan.
Tekstikomponentteja Tekstikenttiä ja editoreja JEditorPane ja JTextPane pidemmälle kehittyneitä versioita editoitavista tekstialueista. Molemmat tukevat eri kirjasimien käyttöä tekstissä, ja kuvien lisäämistä tekstin joukkoon. JEditorPane tukee oletusarvoisesti HTML, RTF ja plaintext dokumenttien lukemista ja kirjoittamista.
Komponenttien asettelu
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 Layout Manager Layout manager käyttää sijoittelun päättelyyn komponenteilta saamaansa tietoa niiden koosta sekä itse LayoutManagerille annettuja lisätoiveita (Vaihtelee managereittain). Käytännössä vakiokomponentit hoitavat tämän automaattisesti Jos teet omia komponentteja niin komponenttisi voi tiedottaa kokotoiveistaan korvaamalla metodit (tarvitaan aika harvoin) public Dimension getminimumsize().. palauttaa minimikoon public Dimension getmaximumsize()..palauttaa maksimikoon public Dimension getpreferredsize()..palauttaa halutun koon Kaikki managerit (mm. GridLayout) eivät kunnioita näitä
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.
Kertaus Esiteltiin joukko yleisimpiä graafisia komponentteja Esiteltiin, kuinka komponentteihin voidaan liittää toiminnallisuutta tapahtumankuuntelijat Kerrottiin komponenteista ja säiliöistä. Esiteltiin ns. ylimmän tason säiliöt ja kuinka ikkunan saa näkyväksi Esitettiin kuinka komponentteja lisätään ja poistetaan säiliöistä Esiteltiin, kuinka komponenttien asetteluun säiliössä voi vaikuttaa layout managereilla
Versionhallinta Versionhallintajärjestelmä säilöö kirjoittamasi koodin historian. Jos koodiin tulee bugi, voit palata takaisin vanhaan versioon Jos vahingossa poistat tiedoston, voit hakea sen takaisin Jos poistit koodia joka olikin tarpeellista voit hakea sen takaisin Jos teet työtä ryhmässä (ei tällä kurssilla :^) Niin yhteisen versionhallinnan kautta voit helposti jakaa tiedostot toisten kanssa Tämä on paljon kätevämpää kuin tiesostojen kopiointi tai mailailu käyttäjältä toiselle
Versionhallinta On hyvän tavan mukaista laittaa versionhallintaan vain ehjiä (kääntyviä ja näennäisen bugittomia versioita)...ainakin monen koodaajan projektissa Tällä kurssilla voit harjoitella versionhallinnan kanssa ja laittaa myös keskeneräisiä versioita versionhallintaan kukaan muu ei ainakaan kärsi
CVS CVS on ehkä yleisimmin käytetty versionhallintajärjestelmä Mm. Eclipse tukee CVS:ää suoraan Kurssin sivuille tulee ohjeet CVS:n ja SubVersion:in käytöstä Demo cvs -d :ext:oseppala@kosh.hut.fi:/m/fs/user3/b/48/oseppala/cvstest/cvs init cvs -d :ext:oseppala@kosh.hut.fi:/m/fs/user3/b/48/oseppala/cvstest/cvs import -m "Huippuohjelma" projekti otto main_branch