You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 155 Next »

Harjoitustehtävät Qt:n ja C++:n oppimiseen. Jokainen tehtävä on 2 pisteen arvoinen. Näytä opettajalle tekemäsi tehtävä, niin saat pisteet kotiin. Pisteet lisätään saamiisi kokeen pisteisiin. Kurssin kokonaispistemäärä on noin 100 ja sillä saa vitosen. Noin 50 pisteellä saa ykkösen. Tutustu kurssin oppimateriaaliin, sieltä löytyy moneen tehtävään miltei valmis ratkaisu. Lisäksi Qt:n omat sivut ovat erittäin hyvä oppimislähde, niihin kannattaa tutustua. Näiden tehtävien yksi tärkeä tehtävä on opettaa opiskelijaa käyttämään Qt:n help-sivustoja, joten kaikki tehtävien yhteydessä olevat linkit kannattaa käydä läpi.

  1. Tee Qt Creator ohjelmalla dialogi-sovellus. Laita dialogiin liukupalkki ja "lcd"-näyttö QLCDNumber. Johda liukupalkin signaali (valueChanged) "lcd"-näytön slotiin (display) signal-slot tilassa (F4). Tee graafisella editorilla kytkennät "widgettien" välille. Testaa sovellus.
  2. Tee edellinen tehtävä connect-funktion avulla eli lisää Dialogin muodostimeen connect.... Alla esimerkki connect-funktion käytöstä:
    //alla olevasta koodista löydät viisi ensimmäistä riviä valmiina Dialogi.h tiedostosta, lisää connect funktio niiden perään
    //kuten tässäkin on tehty
        Dialogi::Dialogi(QWidget *parent) :
        QDialog(parent),
        ui(new Ui::Dialogi)
        {
          ui->setupUi(this);//tämä on jo tehty puolestasi automaattisesti
          //yhdistetaan signaalit ja slotit, valitse komponentit valikosta ALÄ KOPIOI ettei mene suteen
          //ui-> tarkoittaa sitä, että komponentti on käyttöliittymässä ja ui-> on osoite käyttöliittymään
          connect(ui->horizontalSlider,SIGNAL(valueChanged(int)),ui->lcd,SLOT(display(int)));
          ....
    
  3. Laita graafisessa editorissa edellisen liukupalkin alarajaksi -100 ja ylärajaksi 100. Testaa.
  4. Vie liukupalkin arvo edistymispalkin " QProgressBar " arvoksi. Tee kytkentä graafisella editorilla.
  5. Tee edellinen tehtävä connect-funktiolla samaan tapaan kuin tehtävässä kaksi.
  6. Tässä tehtävässä viet haluamasi tekstin labeliin eli tekstinäyttöön ruudulla, kun painat dialogissa olevaa nappulaa. Eli tee dialogi, johon luot graafisessa editorissa  painonapin ja labelin. Nimeä nappi ja label siten, että muistat niiden merkityksen. Tee .h-tiedostoon oma slotin esittely seuraavasti eli avaa Dialog.h ja aaltosulkeiden sisälle ennen lopettavaa sulkua lisää alla oleva teksti. Jos ei muistu mieleen slotit ja signaalit, niin katso täältä: ohjeita signaaleista ja sloteista
    ...
    public slots:
        void nayta();
    ...
    
    Tee slotin toteutus tiedostoon Dialog.cpp. Lisää tiedostoon funktio, joka näyttää tekstin label ruudulla.
    //tämän lisäät Dialog.cpp tiedoston loppuun
    void Dialog::nayta()
    {
        //laita ui-> jos olet tehnyt labelin dialogiin
        QString Tekstia;//tämä on muuttuja joka tallettaa merkkijonoja
        Tekstia="juttuja";
        ui->label->setText(Tekstia);//tällä laitat tekstin labeliin
    }
    
    Liitä napin signaali omaan slotiisi. Tee tämä dialogin muodostimessa (slot on nyt Dialogissa).
    ui->setupUi(this);//tämä on jo tullut automaattisesti
    //yhdistetaan signaalit ja slotit, valitse komponentit valikosta ÄLÄ KOPIOI ettei mene suteen
    //this alla tarkoittaa, että vastaanottaja on tämän tiedoston (luokan) slot
    connect(ui->Nappi,SIGNAL(clicked()),this,SLOT(nayta()));
    
  7. Tässä tehtävässä on tarkoituksena tehdä sekuntikello, jonka voi käynnistää, laittaa tauolle, käynnistää uudelleen ja pysäyttää nappien avulla. Kello toteutetaan QTimer-luokan avulla (tutustu QTimer linkin alta löytyvään tekstiin!!!). Tee dialogiin painikkeet start, pause, jatka, stop ja nollaus. Tee painikkeille slotit (go to slot) sekä vielä lcd-näyttö kellon arvoa varten. Tee QTimer timer; muuttuja Dialog.h tiedostoon alla olevan esimerkin mukaisesti.
    #include <QDialog> // tämä on jo tehty puolestasi eli lisää alla oleva rivi
    #include <QTimer>  //lisää tämä, tähänhän jo tutustuit QTimer helpissä
    
        ... lisää seuraavat muuttujat luokan esittelyyn Dialog.h tiedostossa
        ~Dialog();// tämä on jo tehty puolestasi automaattisesti, lisää alla olevat muuttujat
        QTimer timer;//ajastin ajan laskentaa varten, tämä rivi sinun täytyy lisätä
        int laskuri;//laskuri joka laskee ajastimen timeout eli kertoja jotka ajastin on käynyt loppuun
        ...
        private slots:
        void on_StopTimer_clicked();//tämä tuli automaattiseti kun teit Stop painikkeen ja sille slotin "go to slot" määrittelyllä
        void on_StartTimer_clicked();//ja tuli kanssa samalla tavoin
        void PaivitaNaytto();//tämän joudut tekemään itse ja vastaavan funktion Dialog.cpp tiedostoon
    };
    
    Nyt timer on muuttuja, joka sisältää ajastimen. Esimerkiksi timer.start(1000) käynnistää ajastimen yhden sekunnin resoluutiolla. Ajastimen timeout signaalin joudut kiinnittämään itse tekemääsi slotiin PavitaNaytto seuraavasti Dialogin muodostimessa, muistathan että muodostin on se jossa luokan nimi on sama kuin funktion nimi.
    ui->setupUi(this);//tämä on jo Dialogin muodotimessa
    //tämän liitynnän ajastimen timeout signaalista ja  PaivitaNaytto
    //& merkki tarkoitaa siirtymistä muuttujasta osoitteeseen
    //eli timer on muuttuja &timer on muuttujan osoite
    connect(&timer,SIGNAL(timeout()),this,SLOT(PaivitaNaytto()));
    
    Ja sitten vielä funktioiden sisällöt Dialog.cpp tiedostoon. Muistathan, että teit funktioiden rungot "go to slot" mekanismilla.
    void Dialog::on_StartTimer_clicked()//tämän olet tehnyt "go to slot" määrittelyllä
    {
        timer.start(100);
        laskuri=0;
    }
    
    void Dialog::on_StopTimer_clicked()//tämän olet tehnyt "go to slot" määrittelyllä
    {
        timer.stop();
    }
    //ja tähän ilmestyy loppujen painikkeiden slotit, kun teet ne "go to slot" määrittelyllä
    
    //ajetaan läpi timeoutista eli tämän teet itse
    void Dialog::PaivitaNaytto()
    {
        laskuri++;
        ui->lcdNumber->display(laskuri);
    }
    
    Lisää vielä sisällöt funktioille Jatka ja Pause sekä tee kaikki tarvittavat funktiot ja testaa ohjelma.
  8. Muuta edellisen tehtävän kelloa siten, että tarkkuus on 0.01 sekuntia. Eli joudut muuttamaan timerin start-asetusta. kts. QTimer help
  9. Muuta edellisen tehtävää siten, että nyt on vain painonapit start/pause, stop ja nollaus. Eli muuta start/pause-napin tekstiä sen mukaan onko ajastin tilassa käynnissä/pysäytettynä. Huom! tarvitset luokkaan muuttujan, jossa pidät yllä laskurin tilaa.
    void Dialog::on_StartTimer_clicked()
    {
        QString TekstiPainikkeessa;
        if(FlipFlop==false)//FlipFlop on bool tyypin muuttuja, joka on esiteltävä luokkamäärittelyssä Dialog.h  bool FlipFlop;
        {       
            timer.start(100);
            laskuri=0;//tämä rivi kannattanee siirtää muodostimeen, jos et muista mikä on muodostin niin tarkasta tehtävästä kaksi
            FlipFlop=true; //esittele tämä muuttuja Dialog.h tiedostossa bool FlipFlop; ja aseta
            //FlipFlop asetetaan tilaan false Dialogin muodostimessa (muodostin kts teht. 2)
            TekstiPainikkeessa="Pause";
            ui->StartTimer->setText(TekstiPainikkeessa);
        }
        else
        {
            timer.stop();
            FlipFlop=false;
            TekstiPainikkeessa="Start";
            ui->StartTimer->setText(TekstiPainikkeessa);
        }
    }
    
  10. Muuta edellistä tehtävää siten, että voit muuttaa tarkkuutta vaikka spinBox "widgetillä". Muistat tietysti määritellä spinBoxin graafisessa käyttöliittymässä.
    void Dialog::on_StartTimer_clicked()
    {
        int aika= ui->spinBox->value();
        timer.start(aika);
        laskuri=0;
    ....
    
  11. Tässä tehtävässä opetellaan muuttujan ja osoittimen eroa. Joku fiksu jo varmaan ihmetteli, että miksi ajastin esiteltiin connect funktiossa näin connect(&timer.... Tämä johtuu siitä, connect vaatii lähteen ja kohteen osoitteen sulkujen sisälle. Muuttujan osoite saadaan & merkillä, mutta voimme esitellä muuttujan jo valmiiksi osoitteena. Tällöin ohjelman syntaksi muuttuu ja timer muuttujaa ei enää käytetäkään esimerkiksi timer.start(100); vaan timer->start(100). Tässä tapauksessa timer muuttujalle täytyy myös varata muistia ja esittely tehdään toisella tavoin.
    class Dialog : public QDialog {
        Q_OBJECT
    public:
        Dialog(QWidget *parent = 0);
        ~Dialog();
        //kun timer muuttujan eteen laitetaan * se on osoitin eikä muuttuja
        QTimer *timer;
        //laskuri joka laskee ajastimen timeout eli kertoja jotka ajastin on käynyt loppuun
        int laskuri;
    
     
    Lisäksi joudutaan tekemään Dialog.cpp tiedostossa muodostimeen lisäys muistinvarausta varten.
    Dialog::Dialog(QWidget *parent) :
        QDialog(parent),
        ui(new Ui::Dialog)
    {
        ui->setupUi(this);
        timer = new QTimer();// nyt muisti on varattu ja timer osoitin on käytettävissä
        //eli nyt voidaan & merkki ottaa timer muuttujan edestä pois
        //this on muuten myös  osoitin, kuten huomaat senkään edessä ei ole & merkkiä
        connect(timer,SIGNAL(timeout()),this,SLOT(PaivitaNaytto()));
        FlipFlop=false;
    }
    
    Lisäksi joudut käymään läpi kaikki kohdat, joissa olet käyttänyt timer muuttujaa ja muuttamaan pisteet "nuoliksi".
  12. Tee ohjelma, joka sisältää painonapin "PushButton" ja viesti-ikkunan "MessageBox". Kun painetaan nappia, ohjelma näyttää viestiruudulla "MessageBox" viestin "nappia painettu".
  13. Vie edellisen tehtävän teksti QLabel ikkunaan.
  14. Vie edellisen tehtävän teksti QLineEdit ikkunaan
  15. Tutustu Qt:n QDebug luokkaan ja tulosta sen avulla edellisen tehtävän teksti komentoikkunaan.
  16. Tee ohjelma, joka ilmoittaa millä välillä annettu luku on. Laita annettu arvo lineEdit "ikkunaan" ja nappia "pushButton" painettaessa testaa if-lauseella arvoalue. Aseta "RadioButton"in  (yhden kolmesta) arvo osoittamaan arvoväliä 0...10, 11...100 tai >100.
  17. Tee edellinen tehtävä siten, että painonapilla vaihdat tekstikentän  validaattoria "lennosta" ja laitat samalla vastaavan radioButtonin osoittamaan sallittua lukualuetta.
  18. Vie liukupalkin data muuttujaan ja testaa debugerilla ja breakpointin avulla, että siirto onnistui. ohjeita
  19. Tee Radio button valikko kolmella painikkeella dialogiin. Lisää teksiruutu, jossa kerrot mitä painikkeista on painettu.
  20. Tee ohjelmallisesti dialogi, jossa on oikealla plus-, miinus-, kerto- ja jakopainikkeet. Ohjeita. Vasemmalla on kolme teksti-ikkunaa, kahden ylimmän ruudun tulos laitetaan alimpaan ruutuun riippuen painettavasta napista. Lisää tekstikenttiin validaattorit, ettei numerokenttiin voi syöttää kirjaimia kts. mallia esimerkistä double validator.
  21. Tee dialogi, jossa on progress bar, joka etenee ajastimen tahdissa. Progress barin voi käynnistää, nollata ja pysäyttää painikkeilla. Laita ajastimen jaksoajaksi 0,5 sekuntia. Näytä arvo myös "lcd"-näytöllä.
  22. Tee graafisella editorilla dialogi, johon sijoitat kuusi haluamaasi widgettiä ja erottele rinnakkaiset widgetit spacerilla toisistaan. Ryhmittele widgetit kolmeen allekkaiseen ryhmään kolmella horisonttaalisella layoutilla.
  23. Jatka edellistä tehtävää siten, että teet groupboxin rinnakkaisten widgettien ympärille ja ylimmän ryhmän napilla kätket alemmat widget-ryhmät. Kokeile sizehint käskyä muotoillaksesi dialogia oikean kokoiseksi.
  24. Tee edellisen tehtävän dialogi ( ohjeita  ) graaffisella editorilla.
  25. Tee dialogi esimerkki, jossa pino on aliluokkana. Tee nappula "Laita pinoon" ja "Ota pinosta".
  26. Tee edellinen esimerkki QStack template luokkaa käyttäen.
  27. Tee dialogi, jolla voit laittaa ja katsella lukuja vektorissa, käytä QVector objektia.
  28. Tee dialogi, jolla voit laittaa ja katsella lukuja vektorissa, käytä QList objektia.

*********2. sarja tehtäviä ***********

  1. Tutustu Kvaserin simplewrite.c ohjelmaan ja liitä se Qt- dialogiin siten, että voit syöttää ohjelman tiedot dialogsta.  
  2. Tutustu Kvaserin canmonitor.c ohjelmaan ja liitä se Qt- dialogiin siten, että voit syöttää ohjelman tiedot dialogsta.
  3. Tutustu Qwt esimerkkeihin ja tee kolmannen esimerkin pohjalta ohjelma, joka piirtää plot-ikkunaan cosini-käyrää. 
  4. Tee sql esimerkin avulla projektitietokanta, jossa on sarakkeet ProjektinNimi, AloitusPvm, Projektipaallikko, Budjetti.
  5. Ota paluuarvot talteen edellisen tehtävän sql-kyselyistä ja näytä virheet QMessageBoxilla. Käyttäjätunnus root ja salasana huhtikuu.
  6. Asenna tietokooneeseen MySql palvelin ja core.
  7. Asenna MySql Administrator, Query Browser ja Worbench
  8. Tee tehtävän 18. taulu MySql-tietokantaan.
  9. Suunnittele luokkamalli koneelle. Luokka Kone koostuu luokista Toimilaite ja Prosessi. Toimilaite koostaa luokan Liikeanturi ja VoimaAnturi. Nämä luokat taas perivät luokan Anturi. Tee luokista ensin UML-malli  Dia:lla ja sitten Qt:llä.
  10. Muokkaa mallia siten, että teet luokan dialogi ja laitat sen jäseneksi luokan Kone. Periytä Kone luokasta QThread. 
  11. Korjaa Dialla tekemä malli edellisen tehtävän mukaiseksi.
  12. Lisää anturille jäsenet double vahvistus, double offset, double tulo, double tuloSiYksikkona, double taarattuTuloSiYksikkona, double KeskiarvoistusVektori[10], i , int paikkaVektorissa,  double Summa

  13. Tee käyttöliittymään nappi MittaaTulo ja  sille Dialog luokkaan slot Mittaa. Laita myös LineEdit tai lcd, josta voit lukea mitatun arvon.
  14. Tee Dialog luokkaan signaali MittaaTulonArvo.
  15. Tee luokkaan Anturi slot void PaivitaTulo();
  16. Yhdistä signaali MittaaTulonArvo slotiin PaivitaTulo.
  17. Emitoi (lähetä) signaali MittaaTulonArvo käyttöliittymän slotissa Mittaa.
  18. Tee luokkaan Anturi signaali LahetaMitattuArvo(double) ja ota se vastaan käyttöliittymässä.

    ui

    Dialog

     

    Anturi

    MittaaTulo->

    ->Mittaa

     

     

     

    MittaaTulonArvo->

     

    ->PaivitaTulo

     

    ArvonNaytto<-

     

    <- LahetaMitattuArvo(double)

  19. Laita jokin arvo emitoimaasi signaaliin LahetaMitattuArvo(double) ja testaa, että arvo tulee näytölle.
  20. Tee käyttöliittymään Horizontal Slider ja välitä se signaali - slot mekanismilla  Anturi- luokan muuttujaan tulo.
  21. Tee Anturi-luokkaan funktio Paivita. Kutsu tätä edellisessä tehtävässä tekemästäsi slotista.
  22. Laita Paivita - funktion sisällöksi tuloSiYksikkona=tulo*vahvistu+offset;
  23. Testaa, että vahvistettu tulo tulee näytölle.
  24. Tee  Umbrello -ohjelmalla UML-malli tähän asti tekemästäsi softasta.
  25. Tässä tehtävässä toteutamme asynkronisen säikeen, joka lukee anturia ja lähettää signaalilla tiedon käyttöliittymälle. Tee Kone luokkaan run-funktio ja  siihen forever toistorakenne. Katso mallia säikeistetystä ohjelmasta.\
    //tämä luokan esittelyyn
    QTime displayUpdateTimer;
    
    forever
      {
            //Tähän anturin tiedon laskenta
              if (NayttoAjastin.elapsed() > Paivitysaika)
              {
                  Nayttoajastin.restart();
                  emit LahetaAnturinTiedot(Arvo);
              }
    }
    
  26. Hae koneen arvot Sqlite tietokannasta esimerkin mukaisesti.
  27. Tee  Qwt plot esimerkki.
  28. Hyödynnä esimerkkiä ja tulosta anturin arvo qwtplotissa.
  29. Päivitä edellisiä tehtäviä kuvaava Umbrello malli.
  30. Tee kone esimerkki siten, että teet kaikista luokista dialogeja. Laita luokkiin toimilaite ja anturi liukupalkit, joilla voit säätää niiden antamia arvoja. Älä käytä enää QThread luokkaa kone luokan perinnässä.
  31. Tee dialog perustainen ohjelma ja koosta se kahdesta alidialogista. Kokeile dialogien avausta show ja exec funktioilla, mitä huomaat? Ohjeita: sisällytä "include" alidialogit päädialogin otsikkotiedostoon, tee dialogeille muuttujat päädialogiin, tee päädialogiin nappi, jolla avaat alidialogit funktioilla exec tai show.    
  32. Lisää edellisen tehtävän dilogeihin viestinvälitystä. Lähetä viesti päädialogista molempiin alidialogeihin. Esimerkiksi niin, että teet dialogiin napin, joka lähettää editline viestin molemmille alidialogeille.
  33. Lisää alidialogeihin viestinvälitys toiseen alidialogiin edellisessä tehtävässä kuvatulla tavalla.
  34. Lisää vielä alidialogeihin vistinvälitys päädialogiin.
  35. Tutustu Kvaserin simplewrite.c ohjelmaan ja liitä se Qt- dialogiin siten, että voit syöttää ohjelman tiedot dialogista.  
  36. Tutustu Kvaserin canmonitor.c ohjelmaan ja liitä se Qt- dialogiin siten, että voit syöttää ohjelman tiedot dialogista.
  37. Tee ohjaus manipulaattorille, joka nostaa laatikon pöydältä ja laittaa sen toiselle pöydälle.
  38. Tee edellinen tehtävä käyttäen switch-case rakennetta ja QTimer ajastinta. Kts. Qt:n wiki.
  39. Tee edellinen tehtävä käyttäen tilakoneessa omaa Säiettä QThread.
  40.  Asenna koneeseesi Synapticin avulla Sliteman Sqlite tietokanta editori.
  41. Tee tietokantataulu Sliteman ohjelmalla Sylinteri, jossa on kentät id, nimi, isku, vahvistus ja tulosta taulun asetukset tekstitiedostoon.
  42. Kokeile tehdä samainen taulu seuraavalla sql-komennolla:
    CREATE TABLE sylinteri
    (
        id INTEGER PRIMARY KEY NOT NULL,
        nimi TEXT,
        isku REAL,
        vahvistus REAL
    );
    
  43.  Tee Sqlite tietokanta, joka sisältää taulut sensori  kentillä sensor_id, vahvistus ja offset  sekä kalibrointi kentillä kalibrointi_id, sensor_id, Todellinen, Mitattu ja vielä vierasavain tauluun sensori. Vähän mallia
        FOREIGN KEY(sensor_id) REFERENCES sensor(sensor_id)
    
    Täytä tauluihin kahden anturin tiedot ja testaa tiesotjen hakua sql-komennoilla, esimeriksi
    SELECT * FROM kalibrointi WHERE sensor_id=1;
    
  44. Tee ohjelma, joka lukee sensorien määrän sensoritaulusta ja muodostaa tarvittavan määrän sensoreita.
     //luodaan sensori osoittimena Dilogi luokkaan
    QVector <Sensori> sensori; //luodaan vektori, joka sisältää sensoreja
    
    // esitellään dialog.h tiedostossa esimerkiksi näin
    Sensori *sensori;
    
    
    luetaan Dialogi.cpp :ssa sensorien määrä tietokannasta
    
     ja sitten luodaan new komennolla anturit
    
     sensori=new Sensori[maara];
    
    
  45. Tee sovellus, joka lukee sylinteritietokannasta sylinterien tiedot ja jokaiseen sylinteriin liittyy asema- ja voima-anturi ja niille kalibrointitaulu. Muista tehdä kalibrointitauluun vierasavain anturitauluun ja anturitauluun vierasavain sylinteritauluun. Näin saat yhdistettyä anturin oikealle sylinterille ja kalibrointitaulun oikealle anturille.
  46. Tässä tehtävässä tehdään säätöpiiri. Säätöpiirin tehtävänä on säätää sylinterille menevää ohjetta siten, että haluttu asema saavutetaan mahdollisimman hyvin. Jotta tehtävä olisi mielekäs, täytyy asema-anturin eli sylinterin oloarvon ja sylinterin halutun aseman eli sylinterin asetusarvon välistä suhdetta simuloida. Toteutetaan simulaattori tässä tehtävässä  mahdollisen yksinkertaisesti seuraavan ajatuksen mukaisesti: jos ohje on suurempi kuin todellinen asema, lisätään todellista asemaa kellolla (QTimer timer muuttujan timeoutilla)
    if(ohjesylinterille>olo)olo++;
    if(ohjesylinterille<olo)olo--;
    
    Säätöpiiri voidaan tehdä yksinkertaisesti vähennys-ja kertolaskuilla seuraavasti:
    ohjesylinterille = (asetus-olo)*vahvistus;
    
    Tehdään tehtävä aluksi ainoastaan hyödyntäen Dialog luokkaa. Eli tehdän Dialog luokkaan slider, jolla annetaan ohjearvoja ja lisäksi edistymispalkki johon laitetaan sylinterin todellinen asema. Ohjelmoi lisäksi tarvittava ajastin, jotta saat oloarvon muuttumaan edellä kuvatulla tavalla. Testaa millä vahvistuksen arvolla saat järjestelmän toimimaan (tee ohjelmaan editline ja sille validator, jolla rajataan vahvistuksen arvot välille 0...1000).
  47. Lisää tehtävään Qwt:n graafinen näyttö ja piirrä siihen asetus- oloarvot.
  48. Muuta edellisen tehtävän P-säädin PI-säätimeksi. 
     //listään summaan eroarvo, mujista nollata summa muodostimessa
     IntegraattorinSumma+=(asetus-oloarvo);
     //ja sitten säädin
     ohjearvosylinterille=(asetus-oloarvo)*P_vahvistus+ IntegraattorinSumma*I_vahvistus;
    
    Viritä säädin Ziegler Nichols'in säännöillä.
  • No labels
You must log in to comment.