Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

  1. valitse:
    File-> New file or project
    -> Qt Widget Project
    -> Qt Gui Application
    -> Anna projektin nimi ja tallennuskansio
    -> aja loput oletusasetuksilla läpi.

    Valitse vasemmalta alhaalta Debug build. Käännä ja testaa sovellus painikkeella F5, ohjelman pitäisi käynnistyä ja (tyhjän) ikkunan piirtyä ruudulle. Tutustu koodiin ja etsi sieltä pääohjelma, muodostin = constructor sekä hajotin = destructor.

    Nimeä em. funktiot koodiin, kopioi koodi ja lähetä se tehtävän 1. vastauksena. Älä käytä liitetiedostoa, vaan maalaa koodi vastausikkunaan.
    ***********
     
  2. Laita breakpoint kaikkiin lähdekoodiin funktioihin aaltosulkujen väliin; laita yksi break point pääohjelmaan (main.cpp) ennen dialogin MainWindow-muodostinta ja yksi muodostimeen show-funktiokutsun eteen (mainmainwindow.cpp).

    Breakpointin voit asettaa viemällä hiiren kursorin rivinumeroinnin vasemmalle puolelle ja klikkaamalla siellä olevaa tyhjää aluetta. Aja F5:llä kaikki breakpointit läpi. Selvitä funktioiden ajojärjestys ja kirjoita se tehtävän vastaukseksi (tehtävässä 1 annetut 3 nimetä funktioille oikeassa järjestyksessä)
     
  3. Avaa Qt Creator. Valitse:

    File-> New file or project
    -> Qt Widget Project
    -> Qt Gui Application
    -> Anna projektin nimi ja tallennuskansio
    -> aja loput oletusasetuksilla läpi.

    Avaa juuri luomasi projektin käyttöliittymäsuunnittelunäkymä Forms-kohdan alta, tiedosto mainwindow.ui . Laita dialogiin ikkunaan liukupalkki (Horizontal tai Vertical Slider) ja "lcd"-näyttö QLCDNumber.

    Johda liukupalkin signaali (valueChanged) "lcd"-näytön slotiin (display) signal-slot tilassa (F4).

    Tee graafisella editorilla kytkennät "widgetien" välille. Testaa sovellus.

    Laita graafisessa editorissa edellisen liukupalkin alarajaksi -100 ja ylärajaksi 100. Testaa. Ota Snipping Toolilla kuva dialogista ikkunasta siten, että liitynnät näkyvät ja palauta se.
     
  4. Vie edellisen tehtävän liukupalkin arvo edistymispalkin QLCDNumber-elementin sijaan QProgressBar-elementin arvoksi. Ota Snipping Toolilla kuva dialogista ikkunasta siten, että liitynnät näkyvät ja palauta se.
     
  5. Tee uusi projekti (kuten tehtävässä nro 1) ja lisää dialogiin ikkunaan tehtävän 3 mukaiset widgetit.

    Kytke widgetit graafisen editorin sijaan toisiinsa connect-funktion avulla eli lisää MainWindowin muodostimeen connect....  Alla esimerkki connect-funktion käytöstä

    Code Block
    languagecpp
    //alla olevasta koodista löydät viisi ensimmäistä riviä valmiina mainwindow.cpp tiedostosta, lisää connect funktio niiden perään
    //kuten tässäkin on tehty
        MainWindow::MainWindow(QWidget *parent) :
          QMainWindow(parent),
          ui(new Ui::MainWindow)
        {
          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)));
          ....
    

    Palauta tehtävän lähdekoodi (mainwindow.cpp).

  6. Tee sovellus, jossa on Date Time Edit ja Calendar -widgetit. Kytke ne yhteen siten, että muutettaessa kumpaa tahansa, muuttuu myös toisen asetus.
    a.Tee  graafisella editorilla signal - slot -liityntä (eli nuolilla) . (ota kuva liitynnöistä Snipping toolilla ja palauta se)
    b. Ota nuolet pois ja tee liityntä connect-funktiolla. (palauta lähdekoodi)

    Huom. Jos ohjelma ei muuten toimi, lisää dialogmainwindow.h tiedostoon #include <QDate> muiden include komentojen alle.
     
  7. Tee sovellus, jossa Dial-valikon arvo menee lcd-näyttöön.
    a.Tee graafisella editorilla signal - slot -liityntä (eli nuolilla) ja testaa, ota kuva liitynnöistä ja palauta se. 
    b Tee liityntä connect-funktiolla. (palauta lähdekoodi)
     
  8. Tässä tehtävässä viet haluamasi tekstin labeliin eli tekstinäyttöön ruudulla, kun painat dialogissa ikkunassa olevaa nappulaa. Eli tee ikkuna, johon luot graafisessa editorissa  painonapin ja labelin. Nimeä nappi ja label siten, että muistat niiden merkityksen.

    Tee mainwindow.h-tiedostoon (Headers-otsikon alla) oma slotin esittely allaolevan esimerkin mukaisesti. Avaa mainwindow.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

    (klikkaa 'expand source' jos koodi alla ei näy)

    Code Block
    languagecpp
    collapsetrue
    ...
    public slots:
        void nayta();
    ...
    

    Tee uusi slot toteutustiedostoon mainwindow.cpp. Lisää tiedostoon funktio, joka näyttää tekstin label ruudulla.

    Code Block
    languagecpp
    collapsetrue
    //tämän lisäät mainwindow.cpp tiedoston loppuun
    void MainWindow::nayta()
    {
        //laita ui-> jos olet Designer-näkymässä tehnyt labelin dialogiinMainWindowiin
        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 MainWindowin muodostimessa (nayta-niminen slot on nyt MainWindowissa).

    Code Block
    languagecpp
    collapsetrue
    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()));
    
  9. 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 ikkunaan 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 mainwindow.h tiedostoon alla olevan esimerkin mukaisesti.

    Code Block
    languagecpp
    collapsetrue
    #include <QMainWindow> // 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 MainWindow.h tiedostossa
        ~MainWindow();// 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 MainWindow.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 PaivitaNaytto seuraavasti MainWindowin muodostimessa, muistathan että muodostin on se funktio, jossa luokan nimi on sama kuin funktion nimi.

    Code Block
    languagecpp
    ui->setupUi(this);//tämä on jo MainWindowin 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 mainwindow.cpp tiedostoon. Muistathan, että teit funktioiden rungot "go to slot" -mekanismilla.

    Code Block
    collapsetrue
    void MainWindow::on_StartTimer_clicked()//tämän olet tehnyt "go to slot" määrittelyllä
    {
        timer.start(100);
        laskuri=0;
    }
    
    void MainWindow::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 MainWindow::PaivitaNaytto()
    {
        laskuri++;
        ui->lcdNumber->display(laskuri);
    }
    

    Lisää vielä sisällöt funktioille Jatka ja Pause sekä tee kaikki tarvittavat funktiot ja testaa ohjelma.
     

  10. Muuta edellisen tehtävän kelloa siten, että tarkkuus on 0.01 sekuntia. Eli joudut muuttamaan timerin start-asetusta. kts. QTimer help. Sijoita laskuri double tyypin muuttujaan

    Code Block
    languagecpp
    double apu=laskuri;

    ja jaa apu 100:lla (kokeile lukuja 100 ja 100.0, miten ne eroaa?) sekä sijoita arvo lcd-näyttöön.
     

  11. 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 boolean-muuttujan (tosi/epätosi), jossa pidät yllä laskurin tilaa.

    Code Block
    languagecpp
    collapsetrue
    void MainWindow::on_StartTimer_clicked()
    {
        QString TekstiPainikkeessa;
        if(started==false)//started on bool tyypin muuttuja (tosi/epätosi), 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
            started=true; //esittele tämä muuttuja Dialog.h tiedostossa bool FlipFlop; ja aseta
            //runningasetetaan tilaan false Dialogin muodostimessa (muodostin kts teht. 2)
            TekstiPainikkeessa="Pause";
            ui->StartTimer->setText(TekstiPainikkeessa);
        }
        else
        {
            timer.stop();
            started=false;
            TekstiPainikkeessa="Start";
            ui->StartTimer->setText(TekstiPainikkeessa);
        }
    }
    
  12. Muuta edellistä tehtävää siten, että voit muuttaa kellon tarkkuutta (desimaalien lukumäärää) spinBox "widgetillä":
    - Näytetään vain sekunnit (aikaresoluutio: timer laukeaa 1000 ms välein)
    - Näytetään sekunnit ja kymmenesosat (aikaresoluutio: 100 ms)
    - Näytetään sekunnit ja sadasosat (aikaresoluutio: 10 ms)

    Muistat tietysti lisätä spinBoxin graafiseen käyttöliittymään.

    Code Block
    languagecpp
    collapsetrue
    void Dialog::on_StartTimer_clicked()
    {
        ui->spinBox->setMinimum(0);
        ui->spinBox->setMaximum(2);
        int desimaalit = ui->spinBox->value();
        if(desimaalit==0) aikaResoluutio=1000;//esittele aikaresoluutio .h tiedostossa
        if(desimaalit==1) aikaResoluutio=100;
        if(desimaalit==2) aikaResoluutio=10;
    
        timer.start(aikaResoluutio);
        laskuri=0;
    ....
    

    Lisäksi joudut asettamaan laskurin päivitysfunktioon seuraavanlaisen ehdon.

    Jos aikaresoluutio on 1000, lisäät laskurin arvoa jokaisella päivityksellä 1:llä
    Jos aikaresoluutio on 100, lisäät laskurin arvoa jokaisella päivityksellä 0.1:llä
    jne.

     

  13. Muuta edellistä tehtävää: 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ä (luoda) 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 header-tiedostossa:

    Code Block
    languagecpp
    collapsetrue
    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ätietoja esim. http://edu.phkk.fi/opiskelu/cppohjtekn/14_Osoittimet.htm ja muistinvaraus

    Lisäksi joudutaan tekemään Dialog.cpp tiedostossa muodostimeen lisäys muistinvarausta varten.

    Code Block
    languagecpp
    collapsetrue
    Dialog::Dialog(QWidget *parent) :
        QDialog(parent),
        ui(new Ui::Dialog)
    {
        ui->setupUi(this);
        timer = new QTimer(this);// 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" ("->").
     

  14. a.Tee ohjelma, jonka käyttöliittymään lisäät PushButton-painonapin.
    Kun painetaan nappia, ohjelma näyttää MessageBox -viesti-ikkunassa viestin "nappia painettu".

    b. Lisää dialogiin uusi nappi ja näytä edellisen tehtävän teksti MessageBoxin sijaan QLabel-widgetissä, jonka myös lisäät.
    c. Lisää dialogiin uusi nappi ja näytä teksti QLineEdit-widgetissä, jonka myös lisäät. 

    Tutustu Qt:n QDebug luokkaan ja tulosta sen avulla sama teksti vielä komentoikkunaan (Application output). Ks. QDebug-luokan dokumentaatiosta qDebug() -funktion käyttöohje.

    Palauta tehtävän vastauksena ohjelman lähdekoodi.

     
  15. a. Tee ohjelma, joka ilmoittaa millä välillä annettu luku on. Lisää yksi QPushButton-painonappi (tekstiksi "määritä arvoalue"), yksi QLineEdit ja kolme QRadioButton radiopainiketta, joiden arvot ovat 0...10, 11...100 ja >100. Aseta QRadioButtonien enabled-ominaisuus pois päältä; tällöin käyttäjä ei voi suoraan klikata radiopainikkeita.
    Lue käyttäjän syöttämä arvo lineEdit-widgetistä, pushButton-nappia painettaessa testaa if-lauseella arvoalue, ja valitse sen mukaisesti jokin kolmesta radiopainikkeesta.

    b. Aseta QRadioButtonien enabled-arvo nyt takaisin päälle ja poista QPushButton. Vaihda tekstikentän  validaattoria valitun QRadioButtonin arvon mukaiseksi, kun radiopainiketta painetaan.
     
  16. Lisää kolme Radiobuttonia uuteen dialogiin. Lisää tekstiruutu (label), jossa kerrot välittömästi radiopainiketta painettaessa, mitä painikkeista on painettu.
     
  17. Tee laskin, jossa on oikealla plus-, miinus-, kerto- ja jakopainikkeet.
    Vasemmalla on kolme tekstikenttää (QLineEdit).
    Kahden ylimmän kentän perusteella laskettu tulos laitetaan alimpaan ruutuun riippuen painettavasta napista.

    Laskin
    [tekstikenttä]+
    [tekstikenttä]-
     *
    [tekstikenttä tulos]/

    Lisää tekstikenttiin validaattorit, ettei numerokenttiin voi syöttää kirjaimia kts. mallia esimerkistä double validator. Katso myös tehtävä 28, joka on jatkoa tälle tehtävälle.

     

  18. Tee säännöllisiä lausekkeita (regular expression) käyttäen syöttöruutu, johon voi syöttää vain "Excel"-tyyppisiä solun tunnisteita. Näissä on on yksi kirjain ja numero välillä 1..99 eli esim A1, a1, mutta ei esimerkiksi 1a. QRegExpValidator
     
  19. 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ä.
     
  20. Tee graafisella editorilla dialogi, johon sijoitat kuusi haluamaasi widgettiä (käyttöliittymäelementtiä designerissä), joista ainakin yksi on nappi, ja erottele rinnakkaiset widgetit spacer-elementillä toisistaan. Ryhmittele widgetit kolmeen allekkaiseen ryhmään kolmella horisonttaalisella layoutilla.
     
  21. Jatka edellistä tehtävää siten, että teet groupboxin rinnakkaisten widgettien ympärille ja ylimmän ryhmän napilla kätket alemmat widget-ryhmät.
     
  22. Tee edellisen tehtävän dialogi ohjelmallisesti. kts ohjeita
     
  23. Tee dialogiesimerkki, jossa käytät Qt:n QStack-luokkaa QDialog-olion jäsenmuuttujana. Tee nappula "Laita pinoon" ja "Ota pinosta".
     
  24. Tee mallin 1. tilakone switch-case rakenteella mukainen tilakone ja lisää siihen kaksi askelta. Keksi jokin tapa näyttää askeleet.
     
  25. Tee tehtävä 23 QStack template-luokkaa käyttäen.
     
  26. Tee dialogi, jolla voit laittaa ja katsella lukuja vektorissa/listassa, käytä QVector-luokkaa.
     
  27. Tee dialogi, jolla voit laittaa ja katsella lukuja vektorissa/listassa, käytä QList-luokkaa.

  28. Refaktoroi (muokkaa) tehtävän 17 ratkaisua siten, että jokaisen laskutoimituksen tekemisen yhteydessä:
    - ohjelma käyttää noudaLuvut-jäsenfunktiota tulosten hakemiseen käyttöliittymästä jäsenmuuttujiin luku1 ja luku2. Varmista että funktio ja jäsenmuuttujat ovat mainwindow.h:ssa esiteltyinä.
    - ohjelma käyttää showTulos-jäsenfunktiota tulosten näyttämiseen käyttöliittymässä

    void MainWindow::noudaLuvut()

    {
        luku1=ui->lineEdit->text().toDouble();
        luku2=ui->lineEdit_2->text().toDouble();
    }
    void MainWindow::showTulos(double tulos)
    {
        QString tulosteksti=QString::number(tulos);
        ui->lineEdit_3->setText(tulosteksti);
    }

     

     

...