How does qpainter perform low-level painting?

Mestring af 2D-grafik med QPainter i Qt

29/06/2009

Rating: 4.79 (15395 votes)

I hjertet af Qt's grafiske brugerflader ligger et kraftfuldt og fleksibelt malesystem, der gør det muligt for udviklere at skabe alt fra simple knapper til komplekse, interaktive diagrammer. Centralt i dette system er QPainter-klassen, et alsidigt værktøj, der fungerer som en digital kunstner, klar til at male på forskellige overflader. At forstå QPainter er essentielt for enhver Qt-udvikler, der ønsker at have fuld kontrol over udseendet og fornemmelsen af deres applikationer. Denne artikel vil guide dig gennem QPainter's funktioner, fra de grundlæggende principper til avancerede teknikker, og give dig den viden, du har brug for til at bringe dine grafiske visioner til live.

What does qpainter do?
QPainter provides highly optimized functions to do most of the drawing GUI programs require. It can draw everything from simple lines to complex shapes like pies and chords. It can also draw aligned text and pixmaps. Qt->Qt Gui Application:
Indholdsfortegnelse

Kernen i Qt's Malesystem: Trioen QPainter, QPaintDevice og QPaintEngine

For at forstå, hvordan QPainter fungerer, er det vigtigt at kende de to andre klasser, det arbejder tæt sammen med. Tilsammen udgør de grundlaget for al tegning i Qt.

  • QPaintDevice: Dette er lærredet. Et QPaintDevice er en abstraktion af ethvert objekt, der kan tegnes på. De mest almindelige eksempler er en QWidget (et vindueselement), en QPixmap (et off-screen billede optimeret til skærmvisning) eller en QImage (en hardware-uafhængig billedrepræsentation).
  • QPainter: Dette er kunstneren. QPainter indeholder alle tegnefunktionerne, såsom drawLine(), drawRect() og drawText(). Du giver QPainter kommandoer om, hvad der skal tegnes, og hvor det skal tegnes.
  • QPaintEngine: Dette er oversætteren. QPaintEngine er en intern klasse, der fungerer som broen mellem QPainter's abstrakte kommandoer og den specifikke QPaintDevice. For eksempel vil en QPaintEngine for en QWidget oversætte tegnekommandoer til native kald til operativsystemets grafik-API, mens en QPaintEngine for en QImage vil manipulere pixeldata direkte i hukommelsen.

Denne adskillelse gør QPainter utrolig fleksibel. Den samme tegnekode kan bruges til at tegne på skærmen, generere en billedfil eller sende output til en printer, blot ved at initialisere QPainter med en anden QPaintDevice.

Sådan Kommer Du i Gang: paintEvent og QPainter's Livscyklus

Den mest almindelige måde at bruge QPainter på er inden i en paintEvent()-metode for en custom widget. Denne metode kaldes automatisk af Qt, hver gang widget'en skal genoptegnes, f.eks. når den først vises, ændrer størrelse eller bliver afdækket.

En typisk livscyklus ser således ud:

  1. En QPaintEvent udløses.
  2. Inden i din overskrevne paintEvent(QPaintEvent *event)-metode opretter du et QPainter-objekt.
  3. Du initialiserer maleren, oftest ved at give den en reference til den aktuelle widget: QPainter painter(this);.
  4. Du bruger malerens funktioner til at tegne.
  5. Når paintEvent-metoden afsluttes, destrueres QPainter-objektet automatisk, hvilket frigør alle ressourcer.

Konstruktøren QPainter(QPaintDevice *device) kalder automatisk begin() for at aktivere maleren. Når objektet går ud af scope, kalder destruktøren automatisk end(). Dette er den foretrukne metode for kortlivede malere, som dem i et paintEvent. For langvarige operationer eller tegning på enheder, hvor initialisering kan fejle (som en printer), er det sikrere at bruge den tomme konstruktør og manuelt kalde begin() og end() for at kunne håndtere eventuelle fejl.

Grundlæggende Værktøjer: Pen og Pensel

Før du kan tegne noget, skal du definere, hvordan det skal se ud. QPainter bruger to primære værktøjer til dette: pennen (QPen) og penslen (QBrush).

QPen: Definition af Konturer

En QPen bruges til at tegne linjer og omrids af former. Du kan kontrollere tre hovedegenskaber:

  • Farve: Definerer farven på linjen.
  • Bredde: Angiver tykkelsen af linjen i pixels.
  • Stil: Bestemmer, om linjen skal være solid, stiplet, prikket osv. (f.eks. Qt::SolidLine, Qt::DashLine).

Du indstiller pennen på maleren med painter.setPen(myPen);.

What are qpaintdevice and qpaintengine?
Together with the QPaintDevice and QPaintEngine classes, QPainter form the basis for Qt's paint system. QPainter is the class used to perform drawing operations. QPaintDevice represents a device that can be painted on using a QPainter. QPaintEngine provides the interface that the painter uses to draw onto different types of devices.

QBrush: Udfyldning af Former

En QBrush bruges til at udfylde det indre af lukkede former som rektangler, ellipser og polygoner. En pensel har en farve og en stil.

  • Farve: Definerer udfyldningsfarven.
  • Stil: Kan være en solid farve (Qt::SolidPattern), et mønster (f.eks. Qt::Dense1Pattern, Qt::CrossPattern) eller endda en gradient eller en tekstur.

Du indstiller penslen med painter.setBrush(myBrush);.

Tegning af Primitive Former

QPainter tilbyder en rig samling af funktioner til at tegne forskellige geometriske former. Alle disse funktioner findes i versioner, der accepterer både heltal (int) og flydende tal (qreal) for højere præcision.

Simple Former

  • drawPoint(x, y): Tegner et enkelt punkt.
  • drawLine(x1, y1, x2, y2): Tegner en linje mellem to punkter.
  • drawRect(x, y, width, height): Tegner et rektangel.
  • drawRoundedRect(...): Tegner et rektangel med afrundede hjørner.
  • drawEllipse(x, y, width, height): Tegner en ellipse inden for det angivne rektangel.

Komplekse Former og Stier

For mere komplekse former er QPainterPath et utroligt kraftfuldt værktøj. En Painter Path er en container for tegneoperationer, der kan genbruges. Du kan bygge en form ved at flytte til et startpunkt (moveTo()) og derefter tilføje linjer (lineTo()), kurver (cubicTo()) og andre former.

Når din sti er defineret, kan du tegne den med et enkelt kald:

  • drawPath(path): Tegner omridset af stien med den aktuelle pen.
  • fillPath(path, brush): Udfylder det indre af stien med den angivne pensel.

Avancerede Funktioner

Ud over grundlæggende former tilbyder QPainter avancerede muligheder for at manipulere tegneoperationer.

Koordinattransformationer

Normalt tegner QPainter i enhedens eget koordinatsystem (typisk pixels med (0,0) i øverste venstre hjørne). Men du kan transformere koordinatsystemet for at opnå komplekse effekter uden at skulle genberegne alle dine punkter manuelt.

What are qpaintdevice and qpaintengine?
Together with the QPaintDevice and QPaintEngine classes, QPainter form the basis for Qt's paint system. QPainter is the class used to perform drawing operations. QPaintDevice represents a device that can be painted on using a QPainter. QPaintEngine provides the interface that the painter uses to draw onto different types of devices.
  • translate(dx, dy): Flytter origo (0,0) til en ny position.
  • scale(sx, sy): Skalerer alt, hvad der tegnes efterfølgende.
  • rotate(angle): Roterer koordinatsystemet med uret om origo.
  • shear(sh, sv): Forvrænger koordinatsystemet.

Disse transformationer er kumulative. Det er god praksis at gemme malerens tilstand med painter.save() før du anvender transformationer, og gendanne den bagefter med painter.restore() for at undgå uventede sideeffekter.

Klipning (Clipping)

Du kan begrænse tegneområdet til en bestemt form. Alt, hvad der tegnes uden for denne form, vil blive ignoreret. Dette er kendt som klipning og er nyttigt til at skabe effekter som f.eks. et rundt profilbillede. Du kan indstille en klipningsregion med setClipRect(), setClipRegion() eller endda en kompleks setClipPath().

Rendering Hints for Bedre Kvalitet

For at opnå glattere og mere æstetisk tiltalende grafik kan du aktivere anti-aliasing. Dette udglatter de takkede kanter på former og tekst.

painter.setRenderHint(QPainter::Antialiasing, true);

Andre hints inkluderer TextAntialiasing for tekst og SmoothPixmapTransform for billeder af højere kvalitet under skalering.

Ydeevne: Hurtige og Langsomme Operationer

Ikke alle tegneoperationer er lige hurtige. I applikationer, hvor ydeevne er kritisk, er det vigtigt at vide, hvilke operationer der er optimeret. Qt fokuserer på at gøre visse operationer ekstremt hurtige på specifikke backends (som OpenGL eller raster-motoren).

Hurtige OperationerPotentielt Langsommere Operationer
Tegning af simple primitive former (linjer, rektangler)Komplekse gradienter og penselmønstre
Udfyldning af rektangler med solide farverTegning af komplekse QPainterPath-objekter
Tegning af pixmaps og billeder (drawPixmap, drawImage)Transformationer, der ikke er simple (f.eks. komplekse shear)
Tegning af forud-renderet tekst (QStaticText)Rendering med anti-aliasing (kræver flere beregninger)

Generelt er drawPixmap() ofte hurtigere til skærmvisning, da det kan optimeres af hardwaren, mens drawImage() kan være hurtigere på andre enheder som printere. For at opnå den bedste ydeevne, især ved gentagne tegninger af den samme komplekse form, kan det betale sig at cache resultatet i en QPixmap og derefter blot tegne denne pixmap.

What is qpainter constructor?
Constructs a painter that begins painting the paint device immediately. This constructor is convenient for short-lived painters, e.g. in a QWidget::paintEvent () and should be used only once. The constructor calls begin () for you and the QPainter destructor automatically calls end (). Here's an example using begin () and end (): QPainter p;

Ofte Stillede Spørgsmål (FAQ)

Hvad er forskellen mellem `QPainter`, `QPaintDevice` og `QPaintEngine`?

Tænk på det som en analogi: QPaintDevice er lærredet, QPainter er kunstneren med pensler og maling, og QPaintEngine er den teknik, kunstneren bruger til at påføre maling på den specifikke type lærred.

Skal jeg bruge `begin()`/`end()` eller konstruktøren?

For tegning inde i en paintEvent er det nemmest og sikrest at bruge konstruktøren: QPainter painter(this);. Destruktøren vil automatisk rydde op. Brug kun begin() og end() manuelt, hvis du har brug for at håndtere potentielle fejl under initialiseringen, eller hvis maleren skal leve længere end et enkelt scope.

Hvordan gør jeg min tegning glattere?

Brug rendering hints. Kald painter.setRenderHint(QPainter::Antialiasing, true); i starten af din paintEvent for at aktivere kantudglatning på dine former. Dette vil give et meget mere professionelt udseende.

Hvorfor virker min `QPainter` kun i `paintEvent()` på en widget?

Qt's GUI-system er event-drevet. En widget kan kun garantere, at dens visuelle repræsentation er i en stabil tilstand og klar til at blive tegnet på, når den udsender et paintEvent. At forsøge at tegne uden for denne metode kan føre til uforudsigelig adfærd, visuelle artefakter eller endda programnedbrud.

Hvad er forskellen på `drawPixmap` og `drawImage`?

QPixmap er optimeret til den specifikke skærm, den vises på, hvilket gør drawPixmap() meget hurtig til visning på skærmen. QImage er en hardware-uafhængig repræsentation, der er bedre egnet til pixel-manipulation og tegning på tværs af forskellige enheder, f.eks. når du gemmer til en fil eller printer.

Hvis du vil læse andre artikler, der ligner Mestring af 2D-grafik med QPainter i Qt, kan du besøge kategorien Sundhed.

Go up