Koordinatensystem
Das Koordinatensystem wird von der Klasse QPainter gesteuert. Zusammen mit den Klassen QPaintDevice und QPaintEngine bildet QPainter die Grundlage des Qt-Malsystems Arthur. QPainter dient zur Durchführung von Zeichenoperationen, QPaintDevice ist eine Abstraktion eines zweidimensionalen Raums, auf den mit QPainter gezeichnet werden kann, und QPaintEngine bietet die Schnittstelle, die der Maler zum Zeichnen auf verschiedenen Gerätetypen verwendet.
Die Klasse QPaintDevice ist die Basisklasse der Objekte, die gezeichnet werden können: Ihre Zeichenfähigkeiten werden von den Klassen QWidget, QImage, QPixmap, QPicture und QOpenGLPaintDevice geerbt. Das Standardkoordinatensystem eines Malgeräts hat seinen Ursprung in der linken oberen Ecke. Die x-Werte steigen nach rechts und die y-Werte steigen nach unten. Die Standardeinheit ist ein Pixel bei pixelbasierten Geräten und ein Punkt (1/72 eines Zolls) bei Druckern.
Die Zuordnung der logischen Koordinaten von QPainter zu den physischen Koordinaten von QPaintDevice wird von der Transformationsmatrix, dem Ansichtsfenster und dem "Fenster" von QPainter vorgenommen. Das logische und das physikalische Koordinatensystem stimmen standardmäßig überein. QPainter unterstützt auch Koordinatentransformationen (z. B. Rotation und Skalierung).
Rendering
Logische Darstellung
Die Größe (Breite und Höhe) eines Grafikprimitivs entspricht immer seinem mathematischen Modell, ohne Berücksichtigung der Breite des Stifts, mit dem es gerendert wird:
![]() | ![]() |
QRect(QPoint(1, 2), QPoint(7, 6)) | QLine(QPoint(2, 7), QPoint(6, 1)) |
QLine(2, 7, 6, 1) | |
QRect(QPoint(1, 2), QSize(6, 4)) | |
QRect(1, 2, 6, 4) |
Verfremdete Malerei
Beim Zeichnen wird das Pixel-Rendering durch den Render-Hinweis QPainter::Antialiasing gesteuert.
Die Aufzählung RenderHint wird verwendet, um Flags für QPainter anzugeben, die von einer bestimmten Engine beachtet werden können oder nicht. Der Wert QPainter::Antialiasing gibt an, dass die Engine die Kanten von Primitiven nach Möglichkeit "antialias", d. h. durch Verwendung unterschiedlicher Farbintensitäten glätten sollte.
Standardmäßig ist der Maler jedoch aliasiert und es gelten andere Regeln: Beim Rendern mit einem ein Pixel breiten Stift werden die Pixel rechts und unterhalb der mathematisch definierten Punkte gerendert. Ein Beispiel:
![]() | ![]() |
Beim Rendering mit einem Stift mit einer geraden Anzahl von Pixeln werden die Pixel symmetrisch um die mathematisch definierten Punkte gerendert, während beim Rendering mit einem Stift mit einer ungeraden Anzahl von Pixeln die Ersatzpixel rechts und unterhalb des mathematischen Punktes gerendert werden, wie im Fall von einem Pixel. Konkrete Beispiele finden Sie in den folgenden QRectF Diagrammen.
QRectF | |
---|---|
![]() | ![]() |
Logische Darstellung | Ein Pixel breiter Stift |
![]() | ![]() |
Zwei Pixel breiter Stift | Drei Pixel breiter Stift |
Beachten Sie, dass aus historischen Gründen der Rückgabewert der Funktionen QRect::right() und QRect::bottom() von der tatsächlichen rechten unteren Ecke des Rechtecks abweicht.
QRectDie Funktion right() liefert left() + width() - 1 und die Funktion bottom() liefert top() + height() - 1. Der grüne Punkt unten rechts in den Diagrammen zeigt die Rückgabekoordinaten dieser Funktionen.
Wir empfehlen, dass Sie stattdessen einfach QRectF verwenden: Die Klasse QRectF definiert ein Rechteck in der Ebene und verwendet Fließkommakoordinaten für die Genauigkeit (QRect verwendet Ganzzahlkoordinaten), und die Funktionen QRectF::right() und QRectF::bottom() geben die wahre untere rechte Ecke zurück.
Alternativ können Sie mit QRect die Funktionen x() + width() und y() + height() verwenden, um die rechte untere Ecke zu finden, und die Funktionen right() und bottom() vermeiden.
Anti-Aliasing-Malerei
Wenn Sie den Rendering-Hinweis QPainter's anti-aliasing setzen, werden die Pixel auf beiden Seiten der mathematisch definierten Punkte symmetrisch gerendert:
![]() | ![]() |
Transformationen
Standardmäßig arbeitet QPainter mit dem eigenen Koordinatensystem des zugehörigen Geräts, bietet aber auch vollständige Unterstützung für affine Koordinatentransformationen.
Sie können das Koordinatensystem mit der Funktion QPainter::scale() um einen bestimmten Offset skalieren, mit der Funktion QPainter::rotate() im Uhrzeigersinn drehen und mit der Funktion QPainter::translate() übersetzen (d. h. einen bestimmten Offset zu den Punkten hinzufügen).
Sie können das Koordinatensystem auch mit der Funktion QPainter::shear() um den Ursprung drehen. Alle Transformationsoperationen wirken auf die Transformationsmatrix von QPainter, die Sie mit der Funktion QPainter::worldTransform() abrufen können. Eine Matrix transformiert einen Punkt in der Ebene in einen anderen Punkt.
Wenn Sie immer wieder die gleichen Transformationen benötigen, können Sie auch QTransform Objekte und die Funktionen QPainter::worldTransform() und QPainter::setWorldTransform() verwenden. Sie können die Transformationsmatrix von QPainter jederzeit speichern, indem Sie die Funktion QPainter::save() aufrufen, die die Matrix auf einem internen Stapel speichert. Die Funktion QPainter::restore() holt sie wieder zurück.
Die Transformationsmatrix wird häufig benötigt, wenn derselbe Zeichencode auf einer Vielzahl von Zeichengeräten wiederverwendet wird. Ohne Transformationen sind die Ergebnisse eng an die Auflösung des Malgeräts gebunden. Drucker haben eine hohe Auflösung, z. B. 600 Punkte pro Zoll, während Bildschirme oft zwischen 72 und 100 Punkten pro Zoll haben.
Beispiel einer analogen Uhr | |
---|---|
![]() | Das Analog Clock-Beispiel zeigt, wie der Inhalt eines benutzerdefinierten Widgets mit Hilfe der Transformationsmatrix von QPainter gezeichnet werden kann. Wir empfehlen, dieses Beispiel zu kompilieren und auszuführen, bevor Sie weiter lesen. Versuchen Sie insbesondere, die Größe des Fensters auf verschiedene Größen zu ändern. |
void AnalogClock::paintEvent(QPaintEvent *) { static const QPoint hourHand[4] = { QPoint(5, 14), QPoint(-5, 14), QPoint(-4, -71), QPoint(4, -71) }; static const QPoint minuteHand[4] = { QPoint(4, 14), QPoint(-4, 14), QPoint(-3, -89), QPoint(3, -89) }; static const QPoint secondsHand[4] = { QPoint(1, 14), QPoint(-1, 14), QPoint(-1, -89), QPoint(1, -89) }; const QColor hourColor(palette().color(QPalette::Text)); const QColor minuteColor(palette().color(QPalette::Text)); const QColor secondsColor(palette().color(QPalette::Accent)); int side = qMin(width(), height()); QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); painter.translate(width() / 2, height() / 2); painter.scale(side / 200.0, side / 200.0); Wir übersetzen das Koordinatensystem so, dass der Punkt (0, 0) in der Mitte des Widgets liegt, anstatt in der linken oberen Ecke. Außerdem skalieren wir das System um Dadurch erhalten wir einen quadratischen Bereich von 200 x 200, mit dem Ursprung (0, 0) in der Mitte, auf dem wir zeichnen können. Was wir zeichnen, wird in dem größtmöglichen Quadrat angezeigt, das in das Widget passt. Siehe auch den Abschnitt Fenster-Ansichtsfenster-Konvertierung. painter.save(); painter.rotate(30.0 * ((time.hour() + time.minute() / 60.0))); painter.drawConvexPolygon(hourHand, 4); painter.restore(); Wir zeichnen den Stundenzeiger der Uhr, indem wir das Koordinatensystem drehen und QPainter::drawConvexPolygon() aufrufen. Dank der Drehung wird er in die richtige Richtung gezeichnet. Das Polygon wird als Array von abwechselnden x- und y-Werten angegeben, die in der statischen Variablen Die Aufrufe von QPainter::save() und QPainter::restore(), die den Code umgeben, garantieren, dass der folgende Code nicht durch die von uns verwendeten Transformationen gestört wird. painter.setBrush(minuteColor); painter.save(); painter.rotate(6.0 * time.minute()); painter.drawConvexPolygon(minuteHand, 4); painter.restore(); Danach zeichnen wir die Stundenmarkierungen für das Ziffernblatt, das aus zwölf kurzen Linien in 30-Grad-Abständen besteht. Wenn diese Schleife beendet ist, ist der Maler um einen vollen Kreis zurück in seinen ursprünglichen Zustand gedreht worden, so dass wir den Zustand nicht speichern und wiederherstellen müssen. painter.save(); painter.rotate(6.0 * time.second()); painter.drawConvexPolygon(secondsHand, 4); painter.drawEllipse(-3, -3, 6, 6); painter.drawEllipse(-5, -68, 10, 10); painter.restore(); Dasselbe tun wir für den Minutenzeiger der Uhr, der durch die drei Punkte (7, 8), (-7, 8), (0, -70) definiert ist. Diese Koordinaten legen einen Zeiger fest, der dünner und länger als der Minutenzeiger ist. for (int j = 0; j < 60; ++j) { painter.drawLine(92, 0, 96, 0); painter.rotate(6.0); } Schließlich zeichnen wir die Minutenmarkierungen für das Ziffernblatt, das aus sechzig kurzen Linien in 6-Grad-Abständen besteht. Wir lassen jede fünfte Minutenmarkierung aus, weil wir nicht über die Stundenmarkierungen zeichnen wollen. Am Ende wird der Maler auf eine Weise gedreht, die nicht sehr nützlich ist, aber wir sind mit dem Malen fertig, also spielt das keine Rolle. |
Weitere Informationen über die Transformationsmatrix finden Sie in der Dokumentation QTransform.
Fenster-Ansichtsfenster-Konvertierung
Wenn wir mit QPainter zeichnen, geben wir Punkte mit logischen Koordinaten an, die dann in die physikalischen Koordinaten des Malgeräts umgewandelt werden.
Die Abbildung der logischen Koordinaten auf die physikalischen Koordinaten erfolgt durch die Welttransformation worldTransform() von QPainter(beschrieben im Abschnitt Transformationen ) sowie durch viewport() und window() von QPainter. Das Ansichtsfenster stellt die physikalischen Koordinaten dar und gibt ein beliebiges Rechteck an. Das "Fenster" beschreibt das gleiche Rechteck in logischen Koordinaten. Standardmäßig stimmen das logische und das physikalische Koordinatensystem überein und entsprechen dem Rechteck des Malgeräts.
Mit Hilfe der Fenster-Ansichtsfenster-Konvertierung können Sie das logische Koordinatensystem an Ihre Präferenzen anpassen. Der Mechanismus kann auch verwendet werden, um den Zeichencode unabhängig vom Zeichengerät zu machen. Sie können z. B. die logischen Koordinaten von (-50, -50) bis (50, 50) mit (0, 0) in der Mitte durch Aufruf der Funktion QPainter::setWindow() erweitern:
Nun entsprechen die logischen Koordinaten (-50,-50) den physischen Koordinaten (0, 0) des Malgeräts. Unabhängig vom Malgerät wird Ihr Malcode immer mit den angegebenen logischen Koordinaten arbeiten.
Durch das Setzen des "Fenster"- oder Viewport-Rechtecks führen Sie eine lineare Transformation der Koordinaten durch. Beachten Sie, dass jede Ecke des "Fensters" auf die entsprechende Ecke des Ansichtsfensters abgebildet wird und andersherum. Aus diesem Grund ist es in der Regel ratsam, dass das Ansichtsfenster und das "Fenster" das gleiche Seitenverhältnis haben, um Verformungen zu vermeiden:
int side = qMin(width(), height()); int x = (width() - side / 2); int y = (height() - side / 2); painter.setViewport(x, y, side, side);
Wenn wir das logische Koordinatensystem zu einem Quadrat machen, sollten wir auch das Ansichtsfenster mit Hilfe der Funktion QPainter::setViewport() zu einem Quadrat machen. Im obigen Beispiel entspricht es dem größten Quadrat, das in das Rechteck des Malgeräts passt. Durch die Berücksichtigung der Größe des Malgeräts beim Einstellen des Fensters oder des Ansichtsfensters ist es möglich, den Zeichencode unabhängig vom Malgerät zu halten.
Beachten Sie, dass die Umwandlung zwischen Fenster und Ansichtsfenster nur eine lineare Transformation ist, d.h. es wird kein Clipping durchgeführt. Das heißt, wenn Sie außerhalb des aktuell eingestellten "Fensters" malen, wird Ihr Bild trotzdem mit dem gleichen linearen algebraischen Ansatz in das Ansichtsfenster transformiert.
Das Ansichtsfenster, das "Fenster" und die Transformationsmatrix bestimmen, wie die logischen Koordinaten von QPainter auf die physischen Koordinaten des Malgeräts abgebildet werden. Standardmäßig ist die Welt-Transformationsmatrix die Identitätsmatrix, und die Einstellungen für "Fenster" und Ansichtsfenster entsprechen den Einstellungen des Malgeräts, d. h. die Koordinatensysteme der Welt, des "Fensters" und des Geräts sind äquivalent, aber wie wir gesehen haben, können die Systeme mit Hilfe von Transformationsoperationen und der Fenster-Viewport-Konvertierung manipuliert werden. Die obige Abbildung beschreibt diesen Vorgang.
Siehe auch Analoge Uhr.
© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.