Signaalit ja slotit¶
Tällä kierroksella käytämme Colorpicker-ohjelmaa sekä esimerkkinä
että harjoituksen koodipohjana.
Tässä osiossa tutkimme sen käyttölittymäkomponentteja ja toiminnallisuutta.
Kopioi projekti hakemistosta template/12/colorpicker_designer
hakemistoon student/12/colorpicker_designer
,
ja suorita sen sisältämä ohjelma.
Alla olevassa kuvassa näkyy Colorpicker-koodipohjan käyttöliittymä
ja lopullisen ohjelman käyttöliittymä sen jälkeen, kun olet täydentänyt koodipohjan eli suorittanut seuraavan Plussa-osion harjoituksen.
Colorpicker-ohjelman lopullisessa käyttöliittymässä on kolme liukusäädintä (slider) ja kolme valintalaatikkoa (spinbox), joiden avulla voidaan valita värin RGB-arvon värikomponentit, eli punaisen värin määrä, vihreän värin määrä ja sinisen värin määrä. Lisäksi näytöllä on etiketti (label), jossa käyttäjälle näytetään valittua väriä, joka käyttöliittymäkomponenteissa valituista arvoista kullakin hetkellä muodostuu. Kokeile ohjelman toimintaa vaihtamalla värikomponenttien arvoja ja seuraa, miten näytöllä esitetty väri muuttuu.
Huomaat, että värilaatikko (label) on sidottu kaikkien liukusäädinten arvoihin, koska sen väri muuttuu minkä tahansa em. komponentin arvon muuttuessa.
Signal & slot -mekanismi¶
Qt:ssa kaikki komponentit on toteutettu siten, että ne on
periytetty QWidget
-luokasta, kuten myös edellisessä materiaaliosiossa
mainittu QMainWindow
.
Edellä kuvattu käyttöliittymäkomponenttien liittäminen toisiinsa
tapahtuu nk. signal-slot-mekanismilla. Yksinkertaistetusti
sanottuna ideana on, että kaikki QObject
-luokasta perityt luokat
voivat lähettää signaaleja ja vastaanottaa niitä slotien avulla.
Signaalin lähetys tapahtuu avainsanan emit
avulla esim.
liukusäätimellä voisi olla
emit valueChanged(value_);
tai
emit valueChanged(42);
Kun katsomme ohjelmakoodin tasolla, signaali näyttää funktiolta. Voit halutessasi ajatella signaalin lähettämistä funktiokutsuna. Erona tavalliseen funktiokutsuun on se, että signaalin lähettävä komponentti ei tiedä, kuka/mikä signaalin ottaa vastaan. Lisäksi vastaanottajia voi olla useampia.
Colorpicker-ohjelmassa liukusäätimen arvon
muuttaminen aiheuttaa valueChanged
-signaalin lähetyksen. Qt
toimii siten, että signaalin lähetys aiheuttaa siihen sidottujen
slotien aktivoitumisen.
Lopullisessa Colorpicker-ohjelmassa liukusäätimen
lähettämä valueChanged
-signaali aiheuttaa sen “parina” olevan
valintalaatikon setValue
-slotin aktivoitumisen, joka johtaa
valintalaatikon arvon muuttumiseen. Valintalaatikon arvon muuttuminen
aiheuttaa vastaavalla tavalla sekä sen “parina” olevan liukusäätimen
arvon muuttumisen että värilabelin värin muuttumisen.
Kuvana nämä suhteet voisi esittää vaikkapa tähän tyyliin:
Tämä oli hyvin yksinkertaistettu esitys Qt:n signaalien toiminnasta. Halutessasi perehtyä aiheeseen paremmin, suosittelemme lukemaan Qt:n dokumentaatiota signals & slots -mekanismista. Qt:n dokumentaatiossa asiat on selitetty yleisellä tasolla, toisin kuin kurssimateriaalissa, jossa käytetään esimerkkinä yhtä ohjelmaa.
Colorpickerin ohjelmakoodi¶
Tutkitaan Colorpickerin ohjelmakoodia.
Tiedostossa main.cpp
ei ole mitään eroa edellisessä materiaaliosiossa
tutkimaamme tyhjään ikkunaan verrattuna, joten
aloitamme tiedostosta MainWindow.hh
.
Kuten edellisessä osiossakin, tässäkin luokka MainWindow
on
periytetty luokasta QMainWindow
ja rajapinnassa lukee ensimmäisenä
Q_OBJECT
. Samoin luokan julkisessa rajapinnassa on rakentajan ja
purkajan määrittelyt.
Osasta private slots
löytyvät ne slotit, jotka pääikkunassa on
toteutettuna luokan omaan käyttöön, eli vain luokka itse voi sitoa
signaaleja niihin.
Jos lisäksi luokalla olisi osa public slots
, sisältäisi se
signaaleja, joita voisi käyttää myös luokan ulkopuolelta.
Slot-osien näkyvyydet ovat siis yhdenmukaisia aiemmin
oppimiemme luokkarajapintojen kanssa.
Luokalla MainWindow
on toteutettuna yksi slot, onColorChanged
,
jossa kerrotaan, miten ikkunan on tarkoitus toimia, kun käyttäjä
muuttaa värin arvoa.
Luokan private
-osassa on määriteltynä jäsenmuuttujat aivan kuten
muillakin luokilla.
Kuten edellisellä ohjelmointikurssilla opimme, käyttöliittymäluokan
jäsenmuuttujina voi olla sen sisältämiä käyttöliittymäkomponentteja.
Jäsenmuuttujiksi kannattaa tallettaa vain ne käyttöliittymäkomponentit,
joita meidän pitää pystyä käsittelemään ohjelmakoodissa.
Tästä syystä luokalla ei ole yhtään widgettiä attribuuttinaan.
Tässä esimerkissä kaikki widgetit on määritelty Qt Designerin kautta,
jota opit käyttämään seuraavassa harjoitusosiossa.
Ohjelmakoodissa näihin widgeteihin voidaan viitata käyttöliittymän (ui
)
kautta.
Luokkarajapinnassa on määriteltynä myös vakio RGB-arvojen maksimiarvolle.
Seuraavaksi avataan tiedosto MainWindow.cpp
.
Rakentajan alustuslistassa alustetaan kaikki jäsenmuuttujina olevat
käyttöliittymäkomponentit, kuten olemme jäsenmuuttujille tottuneet tekemään.
Rakentajan rungossa tehdään käyttöliittymäkomponenteille
vielä joitain asetuksia, joita niiden rakentajassa ei suoraan voi
tehdä (setMinimum
ja setMaximum
).
Tärkeimpänä kohtana rakentajan rungon lopussa nähdään, miten jokaisen
liukusäätimen muutossignaali yhdistetään MainWindow
-olion slotiin
onColorChanged
, jonka tarkoitus jo edellä mainittiinkin.
Harjoitustehtäväksi on jätetty liukusäätimien ja valintalaatikoiden
muutossignaalien yhdistäminen toisiinsa pareittain.
Signaalien ja slotien lopullinen tilanne on esitetty edellisessä kuvassa. Vertaile koodia ja kuvaa toisiinsa ja yritä selvittää, mitkä kytkennät on jo tehty ja mitkä on jätetty harjoitustehtäväksi.
Rakentajan lopussa kutsutaan slotia onColorChanged()
tavallisen
funktion tavoin, jotta värilabelin väri muuttuu värivalitsimien
alkuarvojen mukaiseksi.
Slotin onColorChanged
toteutus on lyhyt.
Siinä luodaan QColor
-tyyppinen olio, jonka voi näyttää QLabel
-oliossa.
Luotavan olion RGB-arvo, joka välitetään rakentajalle,
saadaan haettua liukusäädinolioilta.
Lopuksi on hyvä pysähtyä miettimään, miksi
onColorChanged
-slot on toteutettu MainWindow
-luokkaan.
Tarkemmin ajateltuna se on colorLabel
-olio, joka muuttaa väriään.
Slotissa pitää päästä käsittelemään
liukusäädinolioita, joten se on helpointa toteuttaa pääikkunassa.
Liukusäädinoliot ovat pääikkunan lapsia, eli siksi ne ovat
käsiteltävissä pääikkunassa.
(Liukusäädinolioita tai viitteitä niihin olisi toki mahdollista välittää
parametreina luokan ulkopuolellekin, mutta ei pohdita sitä ratkaisua tässä.)
Lopuksi¶
Käyttääkseen Qt:ta täytyy ohjelmoijan ymmärtää hyvin paljon C++-ohjelmointikielen ominaisuuksia, koska kaikki käyttöliittymäkomponentit on toteutettu periytettyinä luokkina, ja niistä luodut oliot talletetaan osoittimien avulla. Nyt ymmärrämme, miksi tätä opintojaksoa ei aloitettu suoraan graafisista käyttöliittymistä, vaikka se olisikin tuntunut kivalta edellisen ohjelmointikurssin päätyttyä graafisten käyttöliittymien alkeisiin.