...
- 1. Mallinna liikennevalot UML-tilakonekaaviona esim käyttäen kaavionpiirto-ohjelmaa. Voit olettaa, että tilakoneeseen tulee tapahtuma "30 sekuntia kulunut" jolloin valoja voi vaihtaa. Voit halutessasi mallintaa myös liikennevalojen välitilat joissa keltainen valo on päällä. http://en.wikipedia.org/wiki/UML_state_machine
- 2. Toteuta tilakoneesi tehtävästä 1 switch-case rakenteella tai if-lauseilla. Voit käyttää koodin kirjoittamiseen esimerkiksi http://ideone.com/ -ympäristöä. Kieleksi voi valita esim. C++11
Esimerkki tällä tavalla toteutetusta tilakoneesta löytyy sivulta Yksinkertainen Caps Lock -tilakonemalli tai osoitteesta http://en.wikipedia.org/wiki/Event-driven_finite-state_machine - 3. Tee Qt Creatorissa uusi käyttöliittymäsovellus. Muunna tehtävän 2 tilakone Qt-sovellukseksi.
- Kopioi C++-sovelluksesi tapahtumankäsittelijäfunktio mainwindow.cpp:hen MainWindown alaiseksi funktioksi.
- Kopioi enum-määrittelysi (tilat ja tapahtumat) mainwindow.h -tiedostoon ennen class MainWindow : public QMainWindow riviä eli varsinaisen luokkamäärittelyn ulkopuolelle
- Lisää käyttöliittymään textbrowser-ikkuna ja tulosta tilakoneen tulosteet seuraavalla addText -funktiolla cout-käskyjen sijaan. (Lisää allaoleva funktio omaan sovellukseesi, lisää funktion esittely .h -tiedostoon, ja mukauta tarvittaessa textBrowser-elementin nimi, jos olet muuttanut sitä)
void MainWindow::addText(QString text) {QString currentText=ui->textBrowser->toPlainText();
QString newText=currentText+"\n"+text;
ui->textBrowser->setText(newText);
}
- Kopioi vanhan main-funktiosi sisältö MainWindow::MainWindow(QWidget *parent) -konstruktoriin. - 4. Lisää tehtävän 3 tilakoneeseesi QTimer-ajastin joka kutsuu ("tikkaa") tilakonetta säännöllisin väliajoin, esim. sekunnin välein. ks. QTimerillä toimiva Caps Lock -esimerkki. Tapahtumia on mahdollista käsitellä joka kerralla, kun tapahtumankäsittelijä käynnistyy, mikäli tapahtuma-jäsenmuuttujaan on asetettu tapahtuma.
QTimerin käyttö edellyttää muutoksia ohjelmaan:
- QTimer-olio lähettää signaaleja, joilla ei ole parametreja. Tämän takia tilakoneen nykyinen tila pitää välittää tapahtumankäsittelijälle toisella tapaa: Esittele tilakoneen tilaa ilmaiseva muuttuja, entisen main-funktion sijaan, mainwindow.h:ssa luokan jäsenmuuttujana. (Caps Lock -esimerkissä CapsState -tyyppinen muuttuja) Tällöin se on saatavilla kaikille luokan funktioille, ja sen arvo säilyy koko ohjelman suorituksen ajan.
- QTimer osaa kutsua vain slot-funktioita, joten lisää mainwindow.h:hon private slots: otsikko, ja siirrä tapahtumankäsittelijän esittely sinne.
- Myös tapahtumat välitetään tässä mallissa tilakoneelle jäsenmuuttujan avulla. (Caps Lock -esimerkissä Event-tyyppinen muuttuja)
- Lisää enumeraatioon, jossa mahdollisten tapahtumien valikoima on määritelty, erityinen NO_EVENT -arvo, ja tilakoneeseesi tälle tapahtumalle käsittelijä, joka ei tee mitään.
- Lisää tilakoneesi kaikkien muiden tapahtumien käsittelyihin tapahtuma-jäsenmuuttujan nollaaminen NO_EVENT -arvoon.
- Lisää #include <QTimer> mainwindow.cpp:n alkuun jotta voit käyttää QTimer-luokkaa
- Tee MainWindow-luokan konstruktorissa/rakentimessa QTimer-olio, joka kutsuu kasitteleTapatuma()-slotia sekunnin välein
- Nyt voit muuttaa tilakoneen tilaa muuttamalla tapahtuma-jäsenmuuttujan arvoa ohjelman ollessa käynnissä.
Lisää jokaista tapahtumaasi kohti yksi tapahtumanlaukaisijafunktio (slot) mainwindow.cpp:hen (ja sen esittely mainwindow.h:hon private slots: otsikon alle). Nimeä funktio kunkin tapahtuman mukaan:void MainWindow::keyApressed(){
Voit tämän jälkeen muuttaa tilaa esimerkiksi ajastamalla QTimer::singleShot -funktion kutsumaan ylläolevanlaista funktiota (slotia)
currentEvent=KEY_A_PRESSED;
}
QTimer::singleShot(3000,this,SLOT(keyApressed()));Kutsu kaikkia tapahtumanlaukaisijoitasi ajastetusti MainWindow::MainWindow-konstruktorista singleShot-kutsujen avulla. Huomaa, että singleShot laukeaa millisekunteina sen kutsumahetkestä, eli seuraava laukaisee tapthtumanlaukaisijoita sekunneilla 3,4,5,6 ja 7 koko sovelluksen käynnistyksestä:
QTimer::singleShot(3000,this,SLOT(keyApressed()));QTimer::singleShot(4000,this,SLOT(capsLockPressed()));
QTimer::singleShot(5000,this,SLOT(keyApressed()));
QTimer::singleShot(6000,this,SLOT(capsLockPressed()));
QTimer::singleShot(7000,this,SLOT(keyApressed()));
Vaihtoehtoisesti voit toki lisätä sovellukseen jokaista tapahtumaa kohti painikkeita, joilla käyttäjä voi vapaasti laukoa tapahtumia silloin, kun haluaa. (Kytke tällöin painikkeiden clicked-signaalit omiin tapahtumanlaukaisijafunktioihisi, singleShotin käyttämisen sijaan.) - 5. Mallinna kerrostalon hissi UML-tilakonekaaviona esim käyttäen kaavionpiirto-ohjelmaa. Sisällytä toiminnallisuuteen ainakin perustoiminnallisuus eli esim. kaikkien kerrosten painikkeet ja näytöt, jotka kertovat hissin tilasta.
...