Qt-ohjelmointi
Mikä on Qt?

Qt on alustariippumaton ohjelmistojen ja graafisten käyttöliittymien käyttöliittymäkirjasto ja ohjelmointiympäristö. Qt on alunperin norjalaisen Trolltechin tekemä käyttöliittymien ja ohjelmakoodin toteutukseen tarkoitettu työkalu. Qt:stä on ladattavissa sekä maksullinen, että ilmainen versio (LGPL versio). Molemmat voi ladata osoitteesta https://www.qt.io/download

Tämän oppaan tarkoitus on esittää HTTP-protokollan käyttö Qt-sovelluksissa. Jos Qt ohjelmointi ei ole tuttua, kannattaa aluksi tehdä sivustolla mainitut harjoitukset. Harjoitusten koodit löytyvät osoitteesta https://github.com/alaluuk/qt_tutorial.

Qt Widget / Qt Quick

Qt:ssa on kaksi mahdollisuutta käyttöliittymän luomiseen:

  • Qt Widget on "perinteinen" tapa luoda työpöytäsovelluksia. Nämä sovellukset eivät skaalaudu kovin joustavasti eri kokoisille näytöille.
  • Qt Quick sovelluksissa käyttöliittymä luodaan QML-kielellä. Nämä käyttöliittymät skaalautuvat eri kokoisille näytöille ja sopivat hyvin esim. mobiililaitteille.

Qt Widget sovelluksissa toteutus kirjoitetaan C++ kielellä. Qt Quick sovellusten toteutukset voidaan kirjoittaa käyttäen C++:aa ja/tai JavaScriptiä.

Tämän oppaan esimerkeissä keskitytään Qt Widget sovellusten tekoon.

Qt Creator

Qt Creator on ns. IDE (Integrated Development Environment) eli integroitu kehitysympäristö. Koodin kirjoittamista nopeuttaa, kun opettelee käyttämään editorin pikanäppäimia (quick keys). Alla muutamia hyödyllisimpiä:

  • CTRL + /: Valitun lohkon kommentointi/kommentoinnin kumoaminen
  • CTRL + F: Etsi ja korvaa
  • CTRL + ALT + Down: Monista rivi

Qt-asennus

Qt:n asennusohjeet löytyvät sivulta https://peatutor.com/c_kieli/qt_asennus.php

Jotta gitin käyttö ryhmässä sujuisi helpommin, kannattaa määrittää build-kansio ohjeessa https://peatutor.com/c_kieli/qt_asennus.php#build annetun mallin mukaisesti.

Kun build kansio määritellään edellisen ohjeen mukaan, Qt-Creator luo projektikansion alle kansion build, joka on kannattaa kirjoittaa .gitignore tiedostoon.

QObject luokka
QObject on Qt-kirjaston perusluokka, josta monet muut Qt-luokat periytyvät. Se tarjoaa tärkeät ominaisuudet, kuten:
  1. Signaalit ja slotit: Näiden avulla eri objektit voivat kommunikoida keskenään asynkronisesti.
  2. Muistin hallinta: QObjectilla on sisäänrakennettu vanhempi-lapsi -järjestelmä, joka auttaa hallitsemaan objektien elinkaaria automaattisesti.
  3. Metatieto: QObject tukee dynaamista tyyppitarkistusta ja tarjoaa mahdollisuuden käyttää objektin ominaisuuksia ja metodeja ajonaikaisesti (reflection).
Q_OBJECT makro

Q_OBJECT on Qt-kirjaston olennainen makro, joka tarjoaa tärkeitä ominaisuuksia C++-luokille. Se on keskeisessä roolissa, kun luodaan luokkia, jotka hyödyntävät Qt:n signal- ja slot-mekanismia, dynaamista ominaisuusjärjestelmää sekä RTTI:tä (Run-Time Type Information).

Kun luokkaan lisätään Q_OBJECT-makro, se mahdollistaa seuraavat Qt:n tarjoamat ominaisuudet:

  • Signaalit ja slotit: Q_OBJECT mahdollistaa signaalien ja slottien käytön, jotka ovat Qt:n oma tapa käsitellä tapahtumia ja kommunikointia objektien välillä.
  • Dynaaminen ominaisuusjärjestelmä: Qt:n ominaisuusjärjestelmä tukee luokkien ominaisuuksien määrittämistä ja käsittelyä dynaamisesti, eli ajonaikaisesti.
  • Metaobjekti: Q_OBJECT-makron avulla luokasta tulee metaobjekti, mikä mahdollistaa mm. luokan tyyppitietojen (kuten metodien ja ominaisuuksien) saamisen ajonaikana.

Alla on esimerkki Qt-luokasta, joka hyödyntää Q_OBJECT-makroa:


#include <QObject>

class MyClass : public QObject {
    Q_OBJECT

public:
    MyClass(QObject* parent = nullptr) : QObject(parent) {}

signals:
    void mySignal();

public slots:
    void mySlot();
};

Tässä esimerkissä Q_OBJECT-makro mahdollistaa MyClass-luokan käytön signaalien ja slottien kanssa.

Huom!

On tärkeää muistaa, että jos luokka sisältää Q_OBJECT-makron, luokan tulee olla peritty QObject-luokasta, ja sen tulee myös olla erillisenä tiedostona (esim. .cpp tai .h), jotta moc (Meta-Object Compiler) voi käsitellä sen oikein.

Signal/Slot

Signaalien ja Slottien avulla oliot voivat kommunikoida keskenään ilman perinteisiä callback-funktioita. QObject-luokan connect-funktiolla ensimmäisen olion signaali-funktio voidaan kytkeä toisen olion slot-funktioon.

Signal/Slot on ns. Observer design patternin mukainen toteutus.

Vaikket itse kirjoittaisikaan sovellukseesi signal- ja slot-funktioita, tulet varmaan käyttämään niitä. Esimerkiksi, kun lisäät sovellukseesi Buttonin ja sen klikkaukselle jonkin toiminnan, käytät signal-slot systeemiä. Kun buttonia klikataan kutsutaan signal-funktiota ja tämä funktio connectoidaan slot-funktioon, jossa määritetään mitä buttonin painallus saa aikaan.

Parent-Child

Qt tarjoaa tehokkaan ja helpon tavan hallita olioiden elinkaarta. Systeemi toimii niin, että kun olion parent tuhotaan, myös sen lapsi oliot tuhotaan automaattisesti.

Esimerkiksi sovelluksessa on ikkunat Mainwindow ja LoginForm. MainWindow:sa on painike, jolla avataan LoginForm. Painikkeen clicked tapahtumaan on kirjoitettu koodi:

LoginForm *objectLoginForm = new LoginForm(this);
objectLoginForm -> show();
Edellä this-osoittimella asetetaan LoginFormin parentiksi MainWindows, jolloin objectLoginForm olion tuhoamisesta ei tarvitse itse huolehtia.

QMAKE ja CMAKE

Ohjelmistokehityksen maailmassa rakennusjärjestelmillä on keskeinen rooli prosessissa, jossa lähdekoodi muunnetaan suoritettaviksi ohjelmiksi. Kaksi suosittua C++-kehityksessä käytettyä rakennusjärjestelmää ovat QMAKE ja CMAKE.

Mitä on QMAKE?

QMAKE on rakennusjärjestelmätyökalu, joka on osa Qt-kehystä, ja sitä käytetään pääasiassa Qt-sovellusten rakentamiseen. Se yksinkertaistaa rakennusprosessia tuottamalla Makefile-tiedostoja projektitiedostojen (.pro-tiedostojen) perusteella. QMAKE automatisoi lähdetiedostojen, otsikkotiedostojen ja muiden resurssien käsittelyn, mikä helpottaa kehittäjiä projektien kääntämisessä eri alustoilla.

Yksi QMAKE:n vahvuuksista on sen tiivis integrointi Qt-kehykseen. Se tarjoaa ennalta määriteltyjä muuttujia ja funktioita, jotka on erityisesti suunniteltu Qt-kehitykseen, mikä mahdollistaa kehittäjille Qt:n ominaisuuksien, kuten käyttöliittymämuotojen ja käännösten, hallinnan helposti.

Mitä on CMAKE?

CMAKE on tehokas, avoimen lähdekoodin rakennusjärjestelmä, joka ei ole sidottu mihinkään tiettyyn kehykseen. Se on suunniteltu erittäin joustavaksi ja alustariippumattomaksi, ja se kykenee tuottamaan alkuperäisiä rakennustiedostoja laajalle valikoimalle käyttöjärjestelmiä ja kääntäjiä. CMAKE käyttää CMakeLists.txt-tiedostoja määritelläkseen rakennusmääritykset ja riippuvuudet.

CMAKE tunnetaan monipuolisuudestaan ja laajasta tuestaan erilaisille työkaluketjuille. Sitä voidaan käyttää projektien rakentamiseen, jotka tukeutuvat useisiin kirjastoihin ja kehyksiin, mikä tekee siitä suositun valinnan monimutkaisille projekteille, jotka vaativat monialustatukea. Lisäksi CMAKE tukee laajaa valikoimaa kolmannen osapuolen moduuleja ja laajennuksia, mikä parantaa sen ominaisuuksia entisestään.

QMAKE vs CMAKE

Sekä QMAKE:lla että CMAKE:lla on omat vahvuutensa, ja ne sopivat erilaisiin käyttötapauksiin. QMAKE on ihanteellinen projekteille, jotka nojaavat vahvasti Qt-kehykseen, sillä se tarjoaa sujuvan rakennusprosessin Qt-spesifisten ominaisuuksien avulla. Toisaalta CMAKE on monipuolisempi ja sitä voidaan käyttää laajempaan valikoimaan projekteja, sillä se tarjoaa suurempaa joustavuutta ja tukea eri alustoille ja työkaluketjuille.

Kun valitaan QMAKE:n ja CMAKE:n välillä, kehittäjien tulisi harkita projektinsa erityisvaatimuksia, käyttämiään kehyksiä ja tarvetta monialustatukeen.

Yhteenveto

Yhteenvetona voidaan todeta, että sekä QMAKE että CMAKE ovat tehokkaita työkaluja, jotka voivat merkittävästi parantaa C++-projektien rakennusprosessia. Niiden erojen ja vahvuuksien ymmärtäminen voi auttaa kehittäjiä valitsemaan oikean työkalun omiin tarpeisiinsa, mikä varmistaa tehokkaamman ja sujuvamman kehitystyönkulun.

MOC-tiedosto

Qt:n MOC (Meta-Object Compiler) tiedosto on automaattisesti luotu tiedosto, joka syntyy Qt:n metaobjektijärjestelmän osana. MOC tiedosto käsittelee C++-luokkia, joissa on Qt:n tarjoamia laajennuksia, kuten signaalit, slotit ja QObject-makrot.

MOC:n päätehtävänä on tuottaa koodi, joka mahdollistaa Qt:n signals and slots -mekanismin, RTTI:n (Run-Time Type Information) ja dynaamiset propertyt. MOC analysoi C++-lähdekoodin ja tuottaa siitä lähdekooditiedoston, joka lisätään osaksi projektin käännösprosessia.

Tämä mekanismi on keskeinen osa Qt:n dynaamista toiminnallisuutta, ja sen ansiosta Qt voi tarjota kehittyneitä ominaisuuksia, kuten tapahtumakäsittelyä ja GUI-komponenttien kommunikointia.



Toggle Menu