Widgeteistä

Edellä olevassa Colorpicker-ohjelmassa käytettiin vain QLabel-, QSlider- ja QSpinBox-widgettejä. Qt sisältää kuitenkin paljon muitakin widgettejä. Kuten ohjelmoinnissa yleisesti, tässäkään vaihessa ei kurssimateriaaliin ole tarkoitus koota ohjeita niiden kaikkien käyttämiseen. Sen sijaan harjoittelemme widgettien käyttämistä seuraavissa harjoitustehtävissä. Niissä uutena widgettinä tulee esimerkiksi QPushButton.

Jos aiot jatkaa ohjelmistotekniikan opiskelua tämän opintojakson jälkeenkin, kannattaa tehtävien tekemisen yhteydessä tutustua myös Qt:n dokumentaatioon widgeteistä, josta ajantasaiset tiedot kaikista kirjaston sisältämistä widgeteistä löytyvät.

Parent-child -mekanismi

Ensinnäkin parent-child -mekanismi ei liity periytymiseen, vaan ennemminkin muistinhallintaan. Widgetin lapsilla tarkoitetaan widgetin sisällä olevia muita widgettejä. Esimerkiksi dialogin sisällä voi olla painikkeita ja liukusäätimiä.

Parent-child -mekanismi on toteutettu luokkaan QObject, joten se koskee muitakin graafisia olioita, ei pelkästään widgettejä. Kun luodaan olio, jolla on vanhempi, vanhempi lisää uuden lapsiolion lapsilistaansa. Kun vanhempi tuhotaan, lapsilista käydään läpi ja tuhotaan myös kaikki listalta löytyvät lapset. Jos lapsilla on omia lapsia, myös nämä tulee tuhottua.

Parent-child -mekanismi yksinkertaistaa muistinhallintaa, sillä se vähentää muistivuotojen vaaraa. Komentoa delete tarvitsee kutsua vain niille olioille, jotka on luotu komennolla new ja joilla ei ole vanhempia. Jos lapsi tuhotaan ennen vanhempaansa, Qt poistaa automaattisesti tuhotun lapsen vanhempansa lapsilistalta.

Vanhemmalla on erityismerkitys widgeteille: lapsi-widgetit näkyvät vanhempansa alueella (sisällä). Kun vanhempi-widget tuhotaan, lapsi-widget poistetaan sekä muistista että näytöltä.

Olioiden nimeäminen Qt:ssa

Ohjelman käyttöliittymää on mahdollista muokata suorituksen aikana lisäämällä widgettejä pääikkunan lapsiksi. Tällaisissa tilanteissa ohjelman suorituksen aikana lisätyillä widgeteillä ei välttämättä ole muuttujanimiä. (On myös muita tilanteita, joissa widgeteillä ei ole muuttujanimiä.)

Tällaisten tilanteiden vuoksi Qt:ssa on mahdollista antaa widgeteille nimi kutsumalla metodia setObjectName. Tämän jälkeen widgettejä on mahdollista hakea QObject-olion erilaisia find-metodeja käyttäen. Tällä kurssilla käytetään pääasiassa Qt Designeria, joka automaattisesti generoi widget-olioille nimet, esimerkiksi pushButton, pushButton_2 jne. Qt Designerissa on kuitenkin mahdollisuus muuttaa näitä generoituja nimiä valitsemalla changeObjectName oikealla puolella olevasta elementtien listasta.

Tällä opintojaksolla emme tarvitse widgeteille asetettuja nimiä muuten, mutta ohjelmien automaattinen arviointi vaatii, että widgeteillä on tietyt nimet. Tämän vuoksi joissakin tehtävänannoissa määritellään, mitkä nimet widgeteille pitää antaa.

Käyttöliittymä Qt Designerilla vs. koodina

Tällä opintojaksoilla widgetit on lisätty käyttöliittymään Qt Designerin kautta. Tällä tavalla on kuitenkin joitakin haittapuolia, joita aluksi tarkastellaan noppapeliesimerkin kautta. Noppapeli, jossa käyttäjä voi heittää useampaa noppaa, on tuttu edelliseltä ohjelmointikurssilta.

../../_images/nopat.png

Kun käyttöliittymässä on nappula Roll, joka käsittelee yhtä aikaa samalla tavalla useampia QLabel-olioita, ja toisaalta useampi samanlaisen toimenpiteen tekevä Keep-nappula, niin kukaan ei halua muokata ohjelmakoodia, jossa olisi talletettuna QLabel-olioita ja QPushButton-olioita erillisiin muuttujiin (noppa1, noppa2, noppa3, jne.). Järkevintä on toteuttaa joukko samalla idealla toimivia olioita kutsumalla widget-luokan rakentajaa toistorakenteessa, ja tallentamalla luodut oliot johonkin sopivaan tietorakenteeseen (esim. vector tai map).

Kun toteutimme Tkinter-käyttöliittymiä, tällä tavoin toimiminen oli luontevaa, koska käyttöliittymä piti joka tapauksessa koota kirjoittamalla Python-ohjelmakoodia. Tutustuttuamme Qt Designeriin, saattaa käyttöliittymän kirjoittaminen C++-koodina tuntua tylsältä vaihtoehdolta. Qt Designeria käyttäen päädytään kuitenkin tilanteeseen, jossa meillä on joukko olioita, jotka on nimetty tyyliin button1, button2, button3, jne.

Qt Designeria käyttäessä on hyvä tietää, että layoutin avulla asemoituihin widgeteihin päästään käsiksi Qt:n layout-olioiden metodia itemAt käyttäen. Tällöin voit käsitellä olioita toistorakenteessa, kun tiedät olioiden indeksit layoutissa.

Tip

Jos layoutin tietyn osan iteroiminen on hankalaa, voit myös tallettaa mihin tahansa sopivaan STL:n säiliöön osoittimet niihin widgetteihin, joita haluat käsitellä ryhmänä (eli keskenään samalla tavalla).

Toinen haittapuoli on se, että Qt Designerilla tehdyt käyttöliittymät eivät skaalaudu oikein, kun ikkunaa suurennetaan tai pienennetään. Tämä näkyy alla olevissa kuvissa.

../../_images/scaling_bad.png

Qt Designerilla toteutettu Colorpicker skaalattuna isommaksi

../../_images/scaling_good.png

C++-koodina toteutettu Colorpicker skaalattuna isommaksi

Jos käyttöliittymä toteutetaan koodissa, niin ui-päätteistä tiedostoa ei tarvita lainkaan. Kaikki widgetit luodaan koodissa kuten mitkä tahansa muutkin oliot. Tällaista tapaa toteuttaa graafisia käyttöliittymiä harjoitellaan seuraavalla ohjelmointikurssilla.