Signaler og spor brukes til kommunikasjon mellom objekter. Signalene og sporlemekanismen er en sentral funksjon av Qt og sannsynligvis den delen som avviker mest fra funksjonene som tilbys av andre rammer.

Introduksjon.

I GUI programmering, nar vi endrer en widget, vil vi ofte ha en annen widget a bli varslet. Mer generelt vil vi ha objekter av noe slag for a kunne kommunisere med hverandre. For eksempel, hvis en bruker klikker pa en lukkeknapp, vil vi sannsynligvis ha vinduet n r () -funksjonen som skal kalles.

Eldre toolkits oppnar denne typen kommunikasjon ved hjelp av tilbakeringinger. En tilbakeringing er en peker til en funksjon, sa hvis du vil ha en behandlingsfunksjon for a varsle deg om noe arrangement, sender du en peker til en annen funksjon (tilbakeringingen) til behandlingsfunksjonen. Behandlingsfunksjonen kaller deretter tilbakeringingen nar det er aktuelt. Tilbakeringinger har to grunnleggende feil: For det forste er de ikke type-sikre. Vi kan aldri v re sikker pa at behandlingsfunksjonen vil ringe tilbakeringingen med de riktige argumentene. For det andre er tilbakeringingen sterkt koblet til behandlingsfunksjonen, siden behandlingsfunksjonen ma vite hvilken tilbakeringing som skal ringes.

Signaler og spor.

I Qt har vi et alternativ til tilbakekallingsteknikken: Vi bruker signaler og spor. Et signal sendes ut nar en bestemt hendelse oppstar. Qt widgets har mange forhandsdefinerte signaler, men vi kan alltid underklass widgets for a legge til vare egne signaler til dem. Et spor er en funksjon som kalles som svar pa et bestemt signal. Qts widgets har mange forhandsdefinerte spor, men det er vanlig a legge til underklass widgets og legge til egne spor slik at du kan handtere signalene du er interessert i.

Signalene og slotsmekanismen er type sikker: Signaturen til et signal ma samsvare med signaturen til mottakssporet. (Faktisk kan et spor ha en kortere signatur enn signalet mottar fordi det kan ignorere ekstra argumenter.) Siden signaturene er kompatible, kan kompilatoren hjelpe oss med a oppdage typen feilmatchinger. Signaler og spor er lost koblet: En klasse som sender et signal, vet heller ikke og bryr seg hvilke spor som mottar signalet. Qt’s signaler og slots mekanisme sikrer at hvis du kobler et signal til et spor, vil sporet bli kalt med signalets parametere til riktig tidspunkt. Signaler og spor kan ta noen argumenter av noe slag. De er helt trygge.

Alle klasser som arver fra QObject eller en av dens underklasser (f.eks. «QWidget») kan inneholde signaler og spor. Signaler sendes ut av objekter nar de endrer sin tilstand pa en mate som kan v re interessant for andre gjenstander. Dette er alt objektet gjor for a kommunisere. Det vet ikke eller bryr seg om noe mottar signaler det sender ut. Dette er sann informasjonskapsling, og sikrer at objektet kan brukes som en programvarekomponent.

Slots kan brukes til mottak av signaler, men de er ogsa normale medlemsfunksjoner. Akkurat som et objekt ikke vet om noe mottar sine signaler, vet et spor ikke om det har noen signaler knyttet til det. Dette sikrer at virkelig uavhengige komponenter kan opprettes med Qt.

Du kan koble til sa mange signaler som du vil ha et enkelt spor, og et signal kan kobles til sa mange spor som du trenger. Det er ogsa mulig a koble et signal direkte til et annet signal. (Dette vil sende det andre signalet straks hver gang den forste sendes ut.)

Sammen utgjor signaler og slots en kraftig komponent programmeringsmekanisme.

Et lite eksempel.

En minimal C + + klasse erkl ring kan lese:

En liten QObject-basert klasse kan lese:

Den QObject-baserte versjonen har samme interne tilstand, og gir offentlige metoder for tilgang til staten, men i tillegg har den stotte for komponentprogrammering ved hjelp av signaler og spor. Denne klassen kan fortelle omverdenen at dens tilstand har endret seg ved a sende et signal, valueChanged (), og det har en spor som andre objekter kan sende signaler til.

Alle klasser som inneholder signaler eller spor ma nevne Q_OBJECT pa toppen av deres erkl ring. De ma ogsa utlede (direkte eller indirekte) fra QObject.

Slots er implementert av applikasjonsprogrammereren. Her er en mulig implementering av Counter :: setValue () -sporet:

Utsendelseslinjen sender signalverdienChanged () fra objektet, med den nye verdien som argument.

I den folgende kodestykket oppretter vi to Tellerobjekter og kobler det forste objektets valueChanged () -signal til det andre objektets setValue () –spor ved hjelp av QObject :: connect ():

A ringe a.setValue (12) gir en avgivelse av et valueChanged (12) signal, som b vil motta i sin setValue () –spor, dvs & # x2e; b.setValue (12) kalles. Deretter sender b det samme valueChanged () signalet, men siden ingen spor er koblet til bs valueChanged () signal, ignoreres signalet.

Merk at setValue () -funksjonen setter verdien og sender signalet bare hvis verdien! = M_value. Dette forhindrer uendelig looping i tilfelle av sykliske tilkoblinger (for eksempel, hvis b.valueChanged () var koblet til a.setValue ()).

Som standard, for hver tilkobling du lager, sendes et signal; To signaler blir utgitt for dupliserte tilkoblinger. Du kan bryte alle disse tilkoblingene med en enkeltkobling () samtale. Hvis du passerer Qt :: UniqueConnection-typen, blir tilkoblingen bare gjort hvis den ikke er en duplikat. Hvis det allerede er en duplikat (noyaktig samme signal til noyaktig samme spor pa de samme objektene), vil forbindelsen mislykkes, og tilkoblingen vil returnere falsk.

Dette eksemplet illustrerer at objekter kan fungere sammen uten a matte vite noe om hverandre. For a aktivere dette, ma objektene bare kobles sammen, og dette kan oppnas med noen enkle QObject :: connect () funksjonssamtaler, eller med uics automatiske tilkoblingsfunksjon.

Bygg eksempelet.

C ++ preprosessoren endrer eller fjerner signaler, spor og sender nokkelord slik at kompilatoren presenteres med standard C ++.

Ved a kjore moc pa klassdefinisjoner som inneholder signaler eller spor, produseres en C ++ kildefil som skal kompileres og kobles sammen med de andre objektfilene for applikasjonen. Hvis du bruker qmake, vil makefile-reglene for a automatisk pakalle moc bli lagt til prosjektets makefile.

Signaler sendes ut av et objekt nar den interne tilstanden har endret seg pa en mate som kan v re interessant for objektets klient eller eier. Signaler er offentlige tilgangsfunksjoner og kan sendes fra hvor som helst, men vi anbefaler at du bare sender dem ut av klassen som definerer signalet og dets underklasser.

Nar et signal sendes ut, blir de slots som er koblet til det, vanligvis utfort umiddelbart, akkurat som en vanlig funksjonssamtale. Nar dette skjer, er signalene og sporlemekanismen helt uavhengig av hvilken som helst GUI-hendelsessloyfe. Utforelse av koden som folger utsendelseserkl ringen vil skje nar alle sporene er returnert. Situasjonen er litt annerledes nar du bruker koforbindelser; I sa fall fortsetter koden som folger emitteringsnavnet umiddelbart, og sporene vil bli kjort senere.

Hvis flere spor er koblet til ett signal, vil sporene bli utfort hverandre i den rekkefolgen de er koblet til nar signalet sendes ut.

Signaler genereres automatisk av moc og ma ikke implementeres i .cpp-filen. De kan aldri ha returtypene (dvs. bruke ugyldig).

Et notat om argumenter: Var erfaring viser at signaler og spor er mer gjenbrukbare hvis de ikke bruker spesielle typer. Hvis QScrollBar :: valueChanged () skulle bruke en spesiell type som den hypotetiske QScrollBar :: Range, kunne den bare kobles til spor som er spesielt utviklet for QScrollBar. A koble sammen forskjellige inngangs widgets sammen ville v re umulig.

Et spor blir kalt nar et signal som er koblet til det, blir sendt ut. Slots er normale C + + funksjoner og kan kalles normalt; deres eneste spesielle funksjon er at signaler kan kobles til dem.

Siden spor er normale medlemsfunksjoner, folger de de vanlige C ++-reglene nar de kalles direkte. Men som spor kan de paberopes av en hvilken som helst komponent, uavhengig av tilgangsnivaet, via en signal-slotsforbindelse. Dette betyr at et signal som sendes ut fra et tilfelle av en vilkarlig klasse, kan fore til at et privat spor blir pakalt i en tilfelle av en ikke-relatert klasse.

Du kan ogsa definere spor for a v re virtuell, som vi har funnet ganske nyttige i praksis.

Sammenlignet med tilbakeringinger, er signaler og slots litt langsommere pa grunn av den okte fleksibiliteten de gir, selv om forskjellen for virkelige applikasjoner er ubetydelig. Generelt sender det ut et signal som er koblet til noen spor, omtrent ti ganger langsommere enn a ringe mottakerne direkte, med ikke-virtuelle funksjonssamtaler. Dette er det overhead som kreves for a finne forbindelsesobjektet, for a sikre at det er sikkert a overfore alle tilkoblinger (det vil si at etterfolgende mottakere ikke har blitt odelagt under emisjonen), og a marshallere noen parametere generisk. Mens ti ikke-virtuelle funksjonssamtaler kan hores ut som mye, er det mye mindre overhead enn noe nytt eller slette operasjon, for eksempel. Sa snart du utforer en streng, vektor eller listeoperasjon som bak scenen krever ny eller slett, er signalene og slots overhead bare ansvarlig for en sv rt liten andel av de totale funksjonssamtalekostnadene. Det samme gjelder nar du foretar et systemanrop i et spor; eller indirekte ringe til mer enn ti funksjoner. Enkelheten og fleksibiliteten til signalene og sporlemekanismen er vel verdt overhead, som brukerne ikke engang vil legge merke til.

V r oppmerksom pa at andre biblioteker som definerer variabler som kalles signaler eller spor, kan forarsake kompilatoradvarsler og feil nar de kompileres sammen med en Qt-basert applikasjon. For a lose dette problemet, #undef det forbrytende preprosessorsymbolet.

Meta-Object Informasjon.

Meta-objekt-kompilatoren (moc) analyserer klassedeklarasjonen i en C ++-fil og genererer C ++-kode som initialiserer meta-objektet. Meta-objektet inneholder navnene pa alle signal- og sporelementene, samt pekere til disse funksjonene.

Meta-objektet inneholder tilleggsinformasjon som objektets klassenavn. Du kan ogsa sjekke om et objekt arver en bestemt klasse, for eksempel:

Meta-objekt-informasjonen brukes ogsa av qobject_cast & lt; T & gt; (), som ligner QObject :: arv (), men er mindre feilaktig:

Et reelt eksempel.

Her er et enkelt kommentert eksempel pa en widget.

LcdNumber arver QObject, som har mesteparten av signal-slot kunnskap, via QFrame og QWidget. Det ligner noe pa den innebygde QLCDNumber-widgeten.

Q_OBJECT makroen blir utvidet av preprosessoren for a erkl re flere medlemsfunksjoner som implementeres av moc; hvis du far kompilatorfeil i henhold til «udefinert referanse til vtable for LcdNumber», har du sannsynligvis glemt a kjore moc eller til a inkludere moc-utgangen i koblingskommandoen.

Det er ikke apenbart relevant for moc, men hvis du arver QWidget, vil du nesten sikkert ha foreldreargumentet i konstruktoren din og sende det til grunnklassens konstruktor.

Noen destruktorer og medlemsfunksjoner blir utelatt her; moc ignorerer medlemsfunksjoner.

LcdNumber gir et signal nar det blir bedt om a vise en umulig verdi.

Hvis du ikke bryr deg om overlop, eller du vet at overlop ikke kan forekomme, kan du ignorere overlopssignalet (i) og / eller x2e; Ikke koble den til noe spor.

Hvis du derimot vil ringe to forskjellige feilfunksjoner nar nummeret overloper, kobler du bare signalet til to forskjellige spor. Qt vil ringe begge (i den rekkefolgen de var koblet til).

Et spor er en mottaksfunksjon som brukes til a fa informasjon om tilstandsendringer i andre widgets. LcdNumber bruker den, som koden ovenfor indikerer, til a angi det viste nummeret. Siden displayet () er en del av klassens grensesnitt med resten av programmet, er sporet offentlig.

Flere av eksempelprogrammene forbinder valueChanged () signalet til en QScrollBar til skjermbildet (), slik at LCD-nummeret kontinuerlig viser verdien pa rullefeltet.

Legg merke til at displayet () er overbelastet; Qt vil velge riktig versjon nar du kobler et signal til sporet. Med tilbakeringinger ma du finne fem forskjellige navn og holde orden pa typene selv.

Noen irrelevante medlemsfunksjoner er utelatt fra dette eksemplet.

Signaler og spor med standardargumenter.

Signaturene til signaler og spor kan inneholde argumenter, og argumentene kan ha standardverdier. Vurder QObject :: odelagt ():

Nar et QObject blir slettet, sender det ut dette QObject :: destroyed () signalet. Vi onsker a fange dette signalet, hvor vi kan ha en dangling referanse til den slettede QObject, slik at vi kan rydde opp det. En passende sporet signatur kan v re:

For a koble signalet til sporet bruker vi QObject :: connect (). Det er flere mater a koble til signal og spor. Den forste er a bruke funksjonspekere:

Det er flere fordeler med a bruke tilkobling () med funksjonspekere. For det forste tillater kompilatoren a kontrollere at signalets argumenter er kompatible med sporets argumenter. Argumenter kan ogsa implisitt konverteres av kompilatoren, om nodvendig.

Du kan ogsa koble til funktorer eller C ++ 11 lamdas:

Merk at hvis din kompilator ikke stotter C ++ 11 variadiske maler, fungerer denne syntaksen bare hvis signalet og sporet har 6 argumenter eller mindre.

Den andre maten a koble et signal til et spor er a bruke QObject :: connect () og SIGNAL og SLOT-makroene. Regelen om a inkludere argumenter eller ikke i SIGNAL () og SLOT () makroene, hvis argumentene har standardverdier, er at signaturen som sendes til SIGNAL () -makroen, ikke ma ha f rre argumenter enn signaturen som er sendt til SLOT () makro.

Alle disse ville fungere:

Men dette vil ikke fungere:

. fordi sporet vil vente et QObject som signalet ikke vil sende. Denne tilkoblingen vil rapportere en kjoretidsfeil.

Merk at signal- og sporargumentene ikke blir sjekket av kompilatoren nar du bruker denne QObject :: connect () overbelastningen.

Avansert signaler og sporbruk.

For tilfeller der du kanskje trenger informasjon om senderen av signalet, gir Qt QObject :: sender () -funksjonen, som returnerer en peker til objektet som sendte signalet.

QSignalMapper-klassen er gitt for situasjoner der mange signaler er koblet til samme spor og sporet ma handtere hvert signal annerledes.

Anta at du har tre trykknapper som bestemmer hvilken fil du vil apne: «Skattfil», «Kontoerfil», eller «Rapporter fil».

For a apne den riktige filen bruker du QSignalMapper :: setMapping () for a kartlegge alle klikkte () signaler til et QSignalMapper-objekt. Deretter kobler du filens QPushButton :: clicked () signal til QSignalMapper :: map () -sporet.

Deretter kobler du til mapped () signalet til readFile () der en annen fil apnes, avhengig av hvilken trykknapp som trykkes.

Bruke Qt med tredjeparts signaler og spor.

Det er mulig a bruke Qt med en tredjeparts signal / spor mekanisme. Du kan til og med bruke begge mekanismer i samme prosjekt. Bare legg til folgende linje i qmake-prosjektet (.pro) -filen.

Det forteller Qt a ikke definere moc sokeord signaler, spor og sende, fordi disse navnene vil bli brukt av et tredje part bibliotek, for eksempel & # x2e; Oke. Deretter fortsetter du a bruke Qt-signaler og spor med no_keywords-flagget, erstatt alle bruk av Qt moc-sokeordene i kildene dine med de tilsvarende Qt-makroene Q_SIGNALS (eller Q_SIGNAL), Q_SLOTS (eller Q_SLOT) og Q_EMIT.

&kopiere; 2012 Digia Plc og / eller dets datterselskaper. Dokumentasjon bidrag inkludert her er opphavsrettene til deres respektive eiere.

Dokumentasjonen som er gitt her, er lisensiert i henhold til vilkarene i GNU Free Documentation License versjon 1.3 som publisert av Free Software Foundation.

Dokumentasjonskilder kan hentes fra www.qt-project.org.

Digia, Qt og deres respektive logoer er varemerker for Digia Plc i Finland og / eller andre land over hele verden. Alle andre varemerker tilhorer deres respektive eiere. Personvernregler.