Analoge Uhr
Das Beispiel „Analoge Uhr“ zeigt, wie der Inhalt eines benutzerdefinierten Widgets gezeichnet wird.

Screenshot des Beispiels „Analoge Uhr“
Dieses Beispiel veranschaulicht zudem, wie die Transformations- und Skalierungsfunktionen von „ QPainter “ genutzt werden können, um das Zeichnen benutzerdefinierter Widgets zu vereinfachen.
Definition der Klasse „AnalogClock“
Die Klasse „ AnalogClock “ stellt ein Uhr-Widget mit Stunden-, Minuten- und Sekundenzeiger bereit, das jede Sekunde automatisch aktualisiert wird. Wir erstellen eine Unterklasse von „ QWidget “ und implementieren die Standardfunktion „ paintEvent()“ neu, um das Zifferblatt zu zeichnen:
class AnalogClock : public QWidget
{
Q_OBJECT
public:
AnalogClock(QWidget *parent = nullptr);
protected:
void paintEvent(QPaintEvent *event) override;
};Implementierung der Klasse „AnalogClock“
Beim Erstellen des Widgets richten wir einen Ein-Sekunden-Timer ein, um die aktuelle Zeit zu verfolgen, und verbinden ihn mit dem Standard-Slot „ update()“, sodass das Zifferblatt aktualisiert wird, wenn der Timer das Signal „ timeout()“ aussendet. Schließlich passen wir die Größe des Widgets so an, dass es in einer angemessenen Größe angezeigt wird.
AnalogClock::AnalogClock(QWidget *parent)
: QWidget(parent)
{
QTimer *timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, QOverload<>::of(&AnalogClock::update));
timer->start(1000);
setWindowTitle(tr("Analog Clock"));
resize(200, 200);
}Die Funktion ` paintEvent() ` wird immer dann aufgerufen, wenn der Inhalt des Widgets aktualisiert werden muss. Dies geschieht, wenn das Widget zum ersten Mal angezeigt wird, wenn es verdeckt und anschließend wieder sichtbar gemacht wird, aber auch, wenn der Slot ` update()` des Widgets aufgerufen wird. Da wir das Signal ` timeout()` des Timers mit diesem Slot verbunden haben, wird dieser mindestens einmal pro Sekunde aufgerufen.
Bevor wir den Painter einrichten und die Uhr zeichnen, definieren wir zunächst drei Listen mit „ QPoints“ und drei „ QColors“, die für den Stunden-, Minuten- und Sekundenzeiger verwendet werden. Wir verwenden die Funktion ` palette()` (), um passende Farben zu erhalten, die sowohl im hellen als auch im dunklen Modus zum Rest des Fensters passen. Der Stunden- und der Minutenzeiger werden in der Vordergrundfarbe gezeichnet, der Sekundenzeiger in der Akzentfarbe.
Außerdem ermitteln wir die Länge der kürzesten Seite des Widgets, damit das Zifferblatt in das Widget passt. Es ist zudem sinnvoll, die aktuelle Uhrzeit zu ermitteln, bevor wir mit dem Zeichnen beginnen.
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());Der Inhalt benutzerdefinierter Widgets wird mit einem ` QPainter` gezeichnet. `Painters` können zum Zeichnen auf beliebigen ` QPaintDevice` verwendet werden, werden jedoch in der Regel mit Widgets eingesetzt, weshalb wir die Widget-Instanz an den Konstruktor des `Painters` übergeben.
Wir rufen ` QPainter::setRenderHint()` mit ` QPainter::Antialiasing ` auf, um Antialiasing zu aktivieren. Dadurch wird das Zeichnen diagonaler Linien deutlich glatter.
painter.setRenderHint(QPainter::Antialiasing);Die Verschiebung versetzt den Ursprung in die Mitte des Widgets, und die Skalierung stellt sicher, dass die folgenden Zeichenvorgänge so skaliert werden, dass sie in das Widget passen. Wir verwenden einen Skalierungsfaktor, der es uns ermöglicht, x- und y-Koordinaten zwischen -100 und 100 zu verwenden, und der sicherstellt, dass diese innerhalb der Länge der kürzesten Seite des Widgets liegen.
painter.translate(width() / 2, height() / 2);
painter.scale(side / 200.0, side / 200.0);Um unseren Code zu vereinfachen, zeichnen wir ein Zifferblatt mit fester Größe, das so positioniert und skaliert wird, dass es in der Mitte des Widgets liegt.
Der „Painter“ kümmert sich um alle Transformationen, die während des „Paint“-Ereignisses vorgenommen werden, und stellt sicher, dass alles korrekt gezeichnet wird. Es ist oft einfacher, den „Painter“ die Transformationen übernehmen zu lassen, als manuelle Berechnungen durchzuführen, nur um den Inhalt eines benutzerdefinierten Widgets zu zeichnen.

Wir setzen den Stift auf „ Qt::NoPen “, da wir keine Umrandung wünschen, und verwenden einen gefüllten Pinsel mit der für die Darstellung der Stunden geeigneten Farbe. Pinsel werden zum Ausfüllen von Polygonen und anderen geometrischen Formen verwendet.
painter.setPen(Qt::NoPen);
painter.setBrush(hourColor);Wir zeichnen zuerst den Stundenzeiger und verwenden dabei eine Formel, die das Koordinatensystem um eine durch die aktuelle Stunde und Minute bestimmte Anzahl von Grad gegen den Uhrzeigersinn dreht. Das bedeutet, dass der Zeiger um den erforderlichen Winkel im Uhrzeigersinn gedreht dargestellt wird. Wir speichern und stellen die Transformationsmatrix vor und nach der Drehung wieder her, indem wir eine „ QPainterStateGuard “ instanziieren, da wir den Minutenzeiger platzieren möchten, ohne vorherige Drehungen berücksichtigen zu müssen.
{
QPainterStateGuard guard(&painter);
painter.rotate(30.0 * ((time.hour() + time.minute() / 60.0)));
painter.drawConvexPolygon(hourHand, 4);
}Wir zeichnen für jede Stunde Markierungen am Rand der Uhr in derselben Farbe wie der Stundenzeiger. Wir zeichnen jede Markierung und drehen anschließend das Koordinatensystem, damit der Zeichner für die nächste bereit ist.
for (int i = 0; i < 12; ++i) {
painter.drawRect(73, -3, 16, 6);
painter.rotate(30.0);
}Der Minutenzeiger wird auf ähnliche Weise wie der Stundenzeiger gedreht und gezeichnet.
painter.setBrush(minuteColor);
{
QPainterStateGuard guard(&painter);
painter.rotate(6.0 * time.minute());
painter.drawConvexPolygon(minuteHand, 4);
}Für den Sekundenzeiger verfahren wir genauso und fügen zwei Kreise als optisches Highlight hinzu.
painter.setBrush(secondsColor);
{
QPainterStateGuard guard(&painter);
painter.rotate(6.0 * time.second());
painter.drawConvexPolygon(secondsHand, 4);
painter.drawEllipse(-3, -3, 6, 6);
painter.drawEllipse(-5, -68, 10, 10);
}Abschließend zeichnen wir Markierungen am Rand des Zifferblatts, die Minuten und Sekunden anzeigen. Diesmal zeichnen wir sie als Linien und stellen den Stift daher auf die jeweilige Farbe ein.
painter.setPen(minuteColor);
for (int j = 0; j < 60; ++j) {
painter.drawLine(92, 0, 96, 0);
painter.rotate(6.0);
}© 2026 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.