Kapitel 2. Grafik

Indholdsfortegnelse

Lavniveaugrafik med QPainter.
Struktureret grafik med QCanvas
3D-grafik med OpenGL

Lavniveaugrafik med QPainter.

Optegning med QPainter

Qt's lavniveau tegnemodel er baseret på de muligheder som tilbydes af X11 og andre vinduessystemer hvor en version af Qt findes. Men den udvider dem også ved at implementere yderligere funktioner såsom vilkårlige affine transformationer for tekst og billeder.

Den centrale grafiske klasse til at tegne todimensionalt med Qt er QPainter. Den kan tegne på en QPaintDevice. Der er tre mulige tegneenheder implementerede: En er QWidget, som repræsenterer en grafisk kontrol på skærmen. Den anden er QPrinter, som repræsenterer en printer, og producerer Postscript-udskrift. Den tredje er klassen QPicture, som indspiller tegnekommandoer og kan gemme dem til disk, og derefter afspille dem. Et muligt lagringsformat for tegnekommandoer er W3C-standarden SVG.

Altså er det muligt at genbruge visningskoden som du bruger til for at vise en grafisk kontrol for udskrift, med støtte for samme funktioner. Naturligvis bruges koden i praksis i en noget anderledes sammenhæng. Tegning på en grafisk kontrol gøres næsten kun i metoden paintEvent() i en kontrolklasse.

void MinKomponent::paintEvent()
{
    QPainter p(this);
    // Indstil
    // Brug
}

Når der tegnes på en printer, skal du sikre dig at bruge QPrinter::newPage() for at afslutte en side, og begynde på en ny: noget som ikke er relevant for at tegne grafiske kontroller. Ved udskrift vil du måske også bruge enhedsmetrikker for at beregne koordinater.

Transformationer

Normalt når QPainter bruges, tegner den i det naturlige koordinatsystemet som bruges af enheden. Det betyder at hvis du tegner en linje med længden 10 enheder, tegnes den som en vandret linje på skærmen med længden 10 billedpunkter. QPainter kan dog bruge vilkårlige affine transformationer før former og kurver rent faktisk toptegnes. En affin transformation overfører x- og y-koordinater lineært til x' og y' som følger:



QPainter::setWorldMatrix() kan bruges til at angive denne 3x3 matrix i ligningen, som har typen QWMatrix. Normalt er dette identitetsmatricen, dvs. m11 og m22 er et, og de øvrige værdier er nul. Der er basalt set tre forskellige grupper af transformationer:

  • Translationer. Disse flytter alle et objekts punkter med en fast værdi i en eller anden retning. En flytningsmatrix kan opnås ved at kalde metoden m.translate(dx, dy) med en QWMatrix. Det svarer til matricen:



  • Skalering. Disse forstørrer eller formindsker et objekts koordinater, og gør det større eller mindre uden at forvrænge det. En skaleringstransformation kan udføres for en QWMatrix ved at kalde m.scale(sx, sy). Det svarer til matricen:



    Ved at give en af parametrene en negativ værdi, kan man opnå spejling af koordinatsystemet.

  • Forskydning. En forvrængning af koordinatsystemet med to parametre. En forskydningstransformation kan udføres ved at kalde m.shear(sh, sv), hvilket svarer til matricen:



  • Rotation. Dette roterer et objekt. En rotationstransformation kan udføres ved at kalde m.rotate(alfa). Bemærk at vinklen skal angives i grader, ikke som en matematisk vinkel! Tilsvarende matrix er:



    Bemærk at rotation er ækvivalent med en kombination af skalering og forskydning.

Her er nogle billeder som viser effekten af de grundlæggende transformationer for vores maskot:









a) Normalb) Roteret 30 graderc) Forskudt med 0,4d) Spejlet

Transformationer kan kombineres ved at multiplicere grundlæggende matricer. Bemærk at matrixoperationer ikke i almindelighed kommutative, og derfor afhænger den kombinerede effekt af en sammensætning af rækkefølgen som matricerne multipliceres med.

Angiv stregegenskaber

Fremvisning af linjer, kurver og polygonkanter kan ændres ved at angive en særlig pen med QPainter::setPen(). Argumentet til denne funktion er et QPen-objekt. Egenskaberne som opbevares i det er en stil, en farve, en sammenføjningsstil og en slutstil.

Pennestilen er et medlem af nummereringstypen Qt::PenStyle. og kan have en af følgende værdier:



Sammenføjningsstilen er et medlem af nummereringstypen Qt::PenJoinStyle. Den angiver hvordan forbindelsen mellem flere linjer som sættes sammen tegnes. Den kan have en af følgende værdier:







a) MiterJoinc) BevelJoinb) RoundJoin

Slutstilen er et medlem af nummereringstypen Qt::PenCapStyle og angiver hvordan linjernes endepunkter tegnes. Den antager en værdi fra følgende tabel:







a) FlatCapb) SquareCapc) RoundCap

Angiv udfyldningsegenskaber

Udfyldningsstilen for polygoner, cirkler eller rektangler kan ændres ved at angive en særlig pensel med QPainter::setBrush(). Denne funktions argument er et QBrush-objekt. Pensler kan laves på fire forskellige måder:

  • QBrush::QBrush(): dette laver en pensel som ikke udfylder former.

  • QBrush::QBrush(BrushStyle): dette laver en sort pensel, med et af de fordefinerede mønstre som vises nedenfor.

  • QBrush::QBrush(const QColor &, BrushStyle): dette laver en farvet pensel, med et af de fordefinerede mønstre som vises nedenfor.

  • QBrush::QBrush(const QColor &, const QPixmap): dette laver en farvet pensel, med det egne mønster som angives som anden parameter.

En standardpenselstil fra nummereringstypen Qt::BrushStyle. Her er et billede af alle fordefinerede mønstre:



Yderligere en måde at indstille en pensels opførsel er at bruge funktionen QPainter::setBrushOrigin().

Farve

Farver har betydning både når kurvor tegnes, og når former udfyldes. Farver repræsenteres af klassen QColor i Qt. Qt understøtter ikke avancerede grafikfunktioner såsom ICC-farveprofiler og farvekorrektion. Farver laves oftest ved at angive deres røde, grønne og blå komponenter, eftersom RGB-modellen er måden som billedpunkter sammensættes en billedskærm.

Det er også muligt at bruge farvetone, mætning og værdi. Denne HSV-repræsentation er den som bruges i GTK's farvedialog, f.eks. i GIMP. Der svarer farvetonen til en vinkel i farvehjulet, mens farvemætningen svarer til afstanden fra cirklens midte. Værdien vælges med en separat glider.

Øvrige indstillinger

Normalt når du tegner på en tegneenhed, så erstatter billedpunkterne dem som var der tidligere. Det betyder at hvis du udfylder et vist område med rød farve, og derefter udfylder samme område med blå farve, så er kun den blå farven synlig. Qt's billedmodel tillader ikke gennemsigtighed, dvs. en måde at blande forgrunden som tegnes med baggrunden. Der er dog en enkel måde at kombinere baggrund og forgrund med Booleske operationer. Metoden QPainter::setRasterOp() angiver operationen som bruges, som kommer fra nummereringstypen RasterOp.

Standardværdien er CopyROP, som ignorerer baggrunden. Et andet populært valg er XorROP. Hvis du tegner en sort linje med denne operationen på et farvet billede, så inverteres området som dækkes. Denne effekt bruges for eksempel til at oprette gummibåndsmarkeringer i billedbehandlingsprogrammer, som er kendte under navnet "vandrende myrer".

Tegn grafiske primitiver

I det følgende giver vi en liste over de grundlæggende grafiske elementer som understøttes af QPainter. De fleste af dem findes i flere overbelastede versioner som har forskellige antal argumenter. Metoder som håndterer rektangler, har for eksempel oftest en QRect som argument, eller et sæt med fire heltal.

  • Tegn et enkelt punkt: drawPoint().

  • Tegn linjer: drawLine(), drawLineSegments() og drawPolyLine().

  • Tegn og udfyld rektangler: drawRect(), drawRoundRect(), fillRect() og eraseRect().

  • Tegn og udfyld i cirkler, ellipser og dele af dem: drawEllipse(), drawArc(), drawPie og drawChord().

  • Tegn og udfyld generelle polygoner: drawPolygon().

  • Tegn Bezierkurvor: drawQuadBezier() [drawCubicBezier i Qt 3.0].

Tegn pixmaps og billeder

Qt sørger for to meget forskellige klasser til at repræsentere billeder.

QPixmap svarer direkte til pixmapsobjekter i X11. En pixmap er et objekt på serversiden og kan, med et moderne grafikkort, til og med opbevares direkte i kortets hukommelse. Det gør det meget effektivt at overføre en pixmap til skærmen. En pixmap virker også som en svarende til grafiske kontroller udenfor skærmen. QPixmap-klassen er en delklasse til QPaintDevice, så det er muligt at tegne på den med en QPainter. Elementære tegneoperationer accelereres ofte af moderne grafik. Derfor er et almindeligt brugsmønster at bruge en pixmap til dobbeltbuffering. Dette betyder at i stedet for at tegne direkte på en grafisk kontrol, tegner man på et tilfældigt pixmapobjekt og bruger funktionen bitBlt til at overføre det til kontrollen. For komplekse gentegninger, hjælper dette med at undgå flimmer.

I modsætning til dette, er der QImage-objekter på klientsiden. Deres hovedopgave er at give direkte adgang til billedpunkterne i billederne. Det gør dem nyttige til billedhåndtering, og ting såsom at indlæse og gemme til disk (Metoden load() for QPixmap bruger QImage som et mellemtrin). På den anden siden, så bliver optegning af et billede på en grafisk kontrol en ganske krævende handling, eftersom det indebærer en overførsel til X-serveren, hvilket kan tage en vis tid, især for store billeder og fjernservere. Afhængig af farvedybden, kan konvertering fra QImage til QPixmap også kræve brug af dithering.

Tegn tekst

Tekst kan tegnes med en af de overbelastede varianter af metoden QPainter::drawText(). Disse tegner en QString, enten ved et given punkt eller inde i en given rektangel, med skrifttypen som indstilles med QPainter::setFont(). Der er også en parameter som tager en ELLER-kombination af visse flag fra nummereringstyperne Qt::AlignmentFlags og Qt::TextFlags.

Begyndende i version 3.0, håndterer Qt fuldstændig tekstlayout også for sprog som skrives fra højre til venstre.

En mere avanceret måde at vise opmarkeret tekst, er klassen QSimpleRichText. Objekter fra klassen kan laves med et tekststykke som bruger en delmængde af HTML-mærkerne, som er ganske omfattende og til og med tilbyder tabeller. Tekststilen kan indstilles ved at bruge QStyleSheet (mærkernes dokumentation findes også her). Så snart tekstobjektet er lavet, kan det tegnes op på en grafisk kontrol eller en anden tegneenhed med metoden QSimpleRichText::draw().