Beispiel für Malerpfade
Das Beispiel „Painter Paths“ zeigt, wie man mit Painter-Pfaden komplexe Formen für die Darstellung erstellt.

Die Klasse „ QPainterPath “ stellt einen Container für Malvorgänge bereit, mit dem grafische Formen erstellt und wiederverwendet werden können.
Ein Painter-Pfad ist ein Objekt, das aus einer Reihe grafischer Bausteine (wie Rechtecken, Ellipsen, Linien und Kurven) besteht und zum Füllen, Umreißen und Ausschneiden verwendet werden kann. Der Hauptvorteil von Painter-Pfaden gegenüber normalen Zeichenoperationen besteht darin, dass komplexe Formen nur einmal erstellt werden müssen, aber mithilfe von Aufrufen von „ QPainter::drawPath()“ mehrfach gezeichnet werden können.
Das Beispiel besteht aus zwei Klassen:
- Die Klasse „
RenderArea“, ein benutzerdefiniertes Widget, das einen einzelnen Painter-Pfad anzeigt. - Die Klasse „
Window“, die das Hauptfenster der Anwendung darstellt, mehrere „RenderArea“-Widgets anzeigt und es dem Benutzer ermöglicht, die Füllung, den Stift, die Farbe und den Drehwinkel der Painter-Pfade zu bearbeiten.
Zunächst werden wir die Klasse „ Window “ betrachten, anschließend werfen wir einen Blick auf die Klasse „ RenderArea “.
Definition der „Window“-Klasse
Die Klasse „ Window “ erbt von „ QWidget “ und ist das Hauptfenster der Anwendung, das mehrere „ RenderArea “-Widgets anzeigt und es dem Benutzer ermöglicht, die Füllung, den Stift, die Farbe und den Drehwinkel der Zeichenpfade zu beeinflussen.
class Window : public QWidget
{
Q_OBJECT
public:
Window();
private slots:
void fillRuleChanged();
void fillGradientChanged();
void penColorChanged();Wir deklarieren drei private Slots, um auf Benutzereingaben bezüglich Füllung und Farbe zu reagieren: „ fillRuleChanged() “, „ fillGradientChanged() “ und „ penColorChanged() “.
Wenn der Benutzer die Stiftbreite und den Drehwinkel ändert, wird der neue Wert über das Signal „ QSpinBox::valueChanged()“ direkt an die „ RenderArea “-Widgets weitergeleitet. Der Grund, warum wir Slots implementieren müssen, um die Füllung und die Farbe zu aktualisieren, liegt darin, dass QComboBox kein entsprechendes Signal bereitstellt, das den neuen Wert als Argument übergibt; daher müssen wir den neuen Wert – oder die neuen Werte – abrufen, bevor wir die „ RenderArea “-Widgets aktualisieren können.
private:
void populateWithColors(QComboBox *comboBox);
QVariant currentItemData(QComboBox *comboBox);Außerdem deklarieren wir einige private Hilfsfunktionen: ` populateWithColors() ` füllt ein gegebenes ` QComboBox ` mit Elementen, die den Qt bekannten Farbnamen entsprechen, und ` currentItemData() ` gibt das aktuelle Element für ein gegebenes ` QComboBox` zurück.
QList<RenderArea*> renderAreas;
QLabel *fillRuleLabel;
QLabel *fillGradientLabel;
QLabel *fillToLabel;
QLabel *penWidthLabel;
QLabel *penColorLabel;
QLabel *rotationAngleLabel;
QComboBox *fillRuleComboBox;
QComboBox *fillColor1ComboBox;
QComboBox *fillColor2ComboBox;
QSpinBox *penWidthSpinBox;
QComboBox *penColorComboBox;
QSpinBox *rotationAngleSpinBox;
};Anschließend deklarieren wir die verschiedenen Komponenten des Hauptfenster-Widgets. Außerdem deklarieren wir eine Hilfs-Konstante, die die Anzahl der „ RenderArea “-Widgets angibt.
Implementierung der Fensterklasse
Im Konstruktor von ` Window ` definieren wir die verschiedenen Zeichenpfade und erstellen die entsprechenden ` RenderArea `-Widgets, die die grafischen Formen rendern:
Window::Window()
{
QPainterPath rectPath;
rectPath.moveTo(20.0, 30.0);
rectPath.lineTo(80.0, 30.0);
rectPath.lineTo(80.0, 70.0);
rectPath.lineTo(20.0, 70.0);
rectPath.closeSubpath();Wir konstruieren ein Rechteck mit scharfen Ecken mithilfe der Funktionen ` QPainterPath::moveTo()` und ` QPainterPath::lineTo()`.
QPainterPath::moveTo() verschiebt den aktuellen Punkt an den als Argument übergebenen Punkt. Ein Zeichenpfad ist ein Objekt, das aus einer Reihe grafischer Bausteine, d. h. Teilpfaden, besteht. Durch das Verschieben des aktuellen Punkts wird zudem ein neuer Teilpfad gestartet (wobei der zuvor aktuelle Pfad implizit geschlossen wird, sobald der neue gestartet wird). Die Funktion ` QPainterPath::lineTo()` fügt eine gerade Linie vom aktuellen Punkt zum angegebenen Endpunkt hinzu. Nachdem die Linie gezeichnet wurde, wird der aktuelle Punkt auf den Endpunkt der Linie aktualisiert.
Zunächst verschieben wir den aktuellen Punkt, wodurch ein neuer Teilpfad begonnen wird, und zeichnen drei Seiten des Rechtecks. Anschließend rufen wir die Funktion ` QPainterPath::closeSubpath()` auf, die eine Linie zum Anfang des aktuellen Teilpfads zeichnet. Ein neuer Teilpfad wird automatisch begonnen, wenn der aktuelle Teilpfad geschlossen wird. Der aktuelle Punkt des neuen Pfads ist (0, 0). Wir hätten auch ` QPainterPath::lineTo()` aufrufen können, um die letzte Linie ebenfalls zu zeichnen, und dann mit der Funktion ` QPainterPath::moveTo()` explizit einen neuen Teilpfad beginnen können.
QPainterPath Außerdem steht die Hilfsfunktion ` QPainterPath::addRect()` zur Verfügung, die ein angegebenes Rechteck als geschlossenen Teilpfad zum Pfad hinzufügt. Das Rechteck wird als eine Reihe von Linien im Uhrzeigersinn eingefügt. Die aktuelle Position des Zeichenpfads nach dem Hinzufügen des Rechtecks befindet sich in der oberen linken Ecke des Rechtecks.
QPainterPath roundRectPath;
roundRectPath.moveTo(80.0, 35.0);
roundRectPath.arcTo(70.0, 30.0, 10.0, 10.0, 0.0, 90.0);
roundRectPath.lineTo(25.0, 30.0);
roundRectPath.arcTo(20.0, 30.0, 10.0, 10.0, 90.0, 90.0);
roundRectPath.lineTo(20.0, 65.0);
roundRectPath.arcTo(20.0, 60.0, 10.0, 10.0, 180.0, 90.0);
roundRectPath.lineTo(75.0, 70.0);
roundRectPath.arcTo(70.0, 60.0, 10.0, 10.0, 270.0, 90.0);
roundRectPath.closeSubpath();Anschließend konstruieren wir ein Rechteck mit abgerundeten Ecken. Wie zuvor verwenden wir die Funktionen ` QPainterPath::moveTo()` und ` QPainterPath::lineTo()` zum Zeichnen der Seiten des Rechtecks. Um die abgerundeten Ecken zu erzeugen, verwenden wir die Funktion ` QPainterPath::arcTo()`.
QPainterPath::arcTo() erzeugt einen Bogen, der das angegebene Rechteck (definiert durch ein ` QRect ` oder die Koordinaten des Rechtecks) ausfüllt, beginnend beim angegebenen Startwinkel und sich um die angegebenen Grad gegen den Uhrzeigersinn erstreckend. Winkel werden in Grad angegeben. Bögen im Uhrzeigersinn können durch negative Winkel angegeben werden. Die Funktion verbindet den aktuellen Punkt mit dem Startpunkt des Bogens, sofern diese noch nicht miteinander verbunden sind.
QPainterPath ellipsePath;
ellipsePath.moveTo(80.0, 50.0);
ellipsePath.arcTo(20.0, 30.0, 60.0, 40.0, 0.0, 360.0);Wir verwenden außerdem die Funktion „ QPainterPath::arcTo()“, um den Ellipsenpfad zu konstruieren. Zunächst verschieben wir den aktuellen Punkt, um einen neuen Pfad zu beginnen. Dann rufen wir „ QPainterPath::arcTo()“ mit dem Startwinkel 0,0 und 360,0 Grad als letztem Argument auf, wodurch eine Ellipse erstellt wird.
Auch hier bietet ` QPainterPath ` eine Komfortfunktion (` QPainterPath::addEllipse()`), die eine Ellipse innerhalb eines vorgegebenen Begrenzungsrechtecks erstellt und diese dem Malerpfad hinzufügt. Ist der aktuelle Teilpfad geschlossen, wird ein neuer Teilpfad begonnen. Die Ellipse besteht aus einer Kurve im Uhrzeigersinn, die bei null Grad (der 3-Uhr-Position) beginnt und endet.
QPainterPath piePath;
piePath.moveTo(50.0, 50.0);
piePath.arcTo(20.0, 30.0, 60.0, 40.0, 60.0, 240.0);
piePath.closeSubpath();Beim Erstellen des Kreisdiagramm-Pfades verwenden wir weiterhin eine Kombination der genannten Funktionen: Zunächst verschieben wir den aktuellen Punkt und beginnen damit einen neuen Teilpfad. Dann erstellen wir eine Linie vom Mittelpunkt des Diagramms zum Bogen sowie den Bogen selbst. Wenn wir den Teilpfad schließen, erstellen wir implizit die letzte Linie zurück zum Mittelpunkt des Diagramms.
QPainterPath polygonPath;
polygonPath.moveTo(10.0, 80.0);
polygonPath.lineTo(20.0, 10.0);
polygonPath.lineTo(80.0, 30.0);
polygonPath.lineTo(90.0, 70.0);
polygonPath.closeSubpath();Das Zeichnen eines Polygons entspricht dem Zeichnen eines Rechtecks.
QPainterPath Außerdem steht die Hilfsfunktion ` QPainterPath::addPolygon()` zur Verfügung, die das angegebene Polygon als neuen Teilpfad zum Pfad hinzufügt. Die aktuelle Position nach dem Hinzufügen des Polygons ist der letzte Punkt des Polygons.
QPainterPath groupPath;
groupPath.moveTo(60.0, 40.0);
groupPath.arcTo(20.0, 20.0, 40.0, 40.0, 0.0, 360.0);
groupPath.moveTo(40.0, 40.0);
groupPath.lineTo(40.0, 80.0);
groupPath.lineTo(80.0, 80.0);
groupPath.lineTo(80.0, 40.0);
groupPath.closeSubpath();Anschließend erstellen wir einen Pfad, der aus einer Gruppe von Teilpfaden besteht: Zunächst verschieben wir den aktuellen Punkt und erstellen mit der Funktion ` QPainterPath::arcTo()` einen Kreis mit dem Startwinkel 0,0 und 360 Grad als letztem Argument – genau wie bei der Erstellung des Ellipsenpfads. Anschließend verschieben wir den aktuellen Punkt erneut, beginnen einen neuen Teilpfad und konstruieren drei Seiten eines Quadrats mithilfe der Funktion ` QPainterPath::lineTo()`.
Wenn wir nun die Funktion ` QPainterPath::closeSubpath()` aufrufen, wird die letzte Seite erstellt. Beachten Sie, dass die Funktion ` QPainterPath::closeSubpath()` eine Linie zum Anfang des aktuellen Teilpfads, d. h. des Quadrats, zeichnet.
QPainterPath Stellen Sie eine Hilfsfunktion „ QPainterPath::addPath()“ bereit, die einen angegebenen Pfad zu dem Pfad hinzufügt, der die Funktion aufruft.
QPainterPath textPath;
QFont timesFont("Times", 50);
timesFont.setStyleStrategy(QFont::ForceOutline);
textPath.addText(10, 70, timesFont, tr("Qt"));Beim Erstellen des Textpfads erstellen wir zunächst die Schriftart. Anschließend legen wir die Stilstrategie der Schriftart fest, die dem Schriftart-Matching-Algorithmus mitteilt, welche Art von Schriftarten verwendet werden soll, um eine geeignete Standardfamilie zu finden. ` QFont::ForceOutline ` erzwingt die Verwendung von Outline-Schriftarten.
Um den Text zu erstellen, verwenden wir die Funktion ` QPainterPath::addText()`, die den angegebenen Text als eine Reihe geschlossener Teilpfade, die aus der bereitgestellten Schriftart erstellt wurden, zum Pfad hinzufügt. Die Teilpfade werden so positioniert, dass das linke Ende der Grundlinie des Textes am angegebenen Punkt liegt.
QPainterPath bezierPath;
bezierPath.moveTo(20, 30);
bezierPath.cubicTo(80, 0, 50, 50, 80, 80);Um den Bézier-Pfad zu erstellen, verwenden wir die Funktion ` QPainterPath::cubicTo()`, die eine Bézier-Kurve zwischen dem aktuellen Punkt und dem angegebenen Endpunkt mit dem angegebenen Kontrollpunkt hinzufügt. Nachdem die Kurve hinzugefügt wurde, wird der aktuelle Punkt so aktualisiert, dass er am Endpunkt der Kurve liegt.
In diesem Fall verzichten wir darauf, den Teilpfad zu schließen, sodass wir nur eine einfache Kurve erhalten. Es gibt jedoch weiterhin eine logische Linie vom Endpunkt der Kurve zurück zum Anfang des Teilpfads; diese wird sichtbar, wenn der Pfad gefüllt wird, wie im Hauptfenster der Anwendung zu sehen ist.
QPainterPath starPath;
starPath.moveTo(90, 50);
for (int i = 1; i < 5; ++i) {
starPath.lineTo(50 + 40 * std::cos(0.8 * i * M_PI),
50 + 40 * std::sin(0.8 * i * M_PI));
}
starPath.closeSubpath();Der endgültige Pfad, den wir konstruieren, zeigt, dass man mit „ QPainterPath “ recht komplexe Formen erstellen kann, indem man ausschließlich die zuvor erwähnten Funktionen „ QPainterPath::moveTo()“, „ QPainterPath::lineTo()“ und „ QPainterPath::closeSubpath()“ verwendet.
renderAreas.push_back(new RenderArea(rectPath));
renderAreas.push_back(new RenderArea(roundRectPath));
renderAreas.push_back(new RenderArea(ellipsePath));
renderAreas.push_back(new RenderArea(piePath));
renderAreas.push_back(new RenderArea(polygonPath));
renderAreas.push_back(new RenderArea(groupPath));
renderAreas.push_back(new RenderArea(textPath));
renderAreas.push_back(new RenderArea(bezierPath));
renderAreas.push_back(new RenderArea(starPath));Nachdem wir nun alle benötigten Malpfade erstellt haben, erstellen wir für jeden ein entsprechendes „ RenderArea “-Widget. Abschließend stellen wir mithilfe des Makros „ Q_ASSERT()“ sicher, dass die Anzahl der Renderbereiche korrekt ist.
fillRuleComboBox = new QComboBox;
fillRuleComboBox->addItem(tr("Odd Even"), Qt::OddEvenFill);
fillRuleComboBox->addItem(tr("Winding"), Qt::WindingFill);
fillRuleLabel = new QLabel(tr("Fill &Rule:"));
fillRuleLabel->setBuddy(fillRuleComboBox);Anschließend erstellen wir die Widgets, die mit der Füllregel der Malerpfade verknüpft sind.
In Qt stehen zwei Füllregeln zur Verfügung: Die Regel „ Qt::OddEvenFill “ ermittelt, ob sich ein Punkt innerhalb der Form befindet, indem sie eine horizontale Linie vom Punkt zu einer Stelle außerhalb der Form zeichnet und die Anzahl der Schnittpunkte zählt. Ist die Anzahl der Schnittpunkte ungerade, befindet sich der Punkt innerhalb der Form. Diese Regel ist die Standardregel.
Die Regel „ Qt::WindingFill “ bestimmt, ob sich ein Punkt innerhalb der Form befindet, indem eine horizontale Linie von dem Punkt zu einer Stelle außerhalb der Form gezogen wird. Anschließend wird ermittelt, ob die Richtung der Linie an jedem Schnittpunkt nach oben oder nach unten verläuft. Die Winding-Zahl wird durch Summierung der Richtungen an jedem Schnittpunkt ermittelt. Ist die Zahl ungleich Null, befindet sich der Punkt innerhalb der Form.
Die Regel „ Qt::WindingFill “ kann in den meisten Fällen als Schnittmenge geschlossener Formen betrachtet werden.
fillColor1ComboBox = new QComboBox;
populateWithColors(fillColor1ComboBox);
fillColor1ComboBox->setCurrentIndex(fillColor1ComboBox->findText("mediumslateblue"));
fillColor2ComboBox = new QComboBox;
populateWithColors(fillColor2ComboBox);
fillColor2ComboBox->setCurrentIndex(fillColor2ComboBox->findText("cornsilk"));
fillGradientLabel = new QLabel(tr("&Fill Gradient:"));
fillGradientLabel->setBuddy(fillColor1ComboBox);
fillToLabel = new QLabel(tr("to"));
fillToLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
penWidthSpinBox = new QSpinBox;
penWidthSpinBox->setRange(0, 20);
penWidthLabel = new QLabel(tr("&Pen Width:"));
penWidthLabel->setBuddy(penWidthSpinBox);
penColorComboBox = new QComboBox;
populateWithColors(penColorComboBox);
penColorComboBox->setCurrentIndex(penColorComboBox->findText("darkslateblue"));
penColorLabel = new QLabel(tr("Pen &Color:"));
penColorLabel->setBuddy(penColorComboBox);
rotationAngleSpinBox = new QSpinBox;
rotationAngleSpinBox->setRange(0, 359);
rotationAngleSpinBox->setWrapping(true);
rotationAngleSpinBox->setSuffix(QLatin1String("\xB0"));
rotationAngleLabel = new QLabel(tr("&Rotation Angle:"));
rotationAngleLabel->setBuddy(rotationAngleSpinBox);Außerdem erstellen wir die anderen Widgets, die mit der Füllung, dem Stift und dem Drehwinkel zusammenhängen.
connect(fillRuleComboBox, &QComboBox::activated,
this, &Window::fillRuleChanged);
connect(fillColor1ComboBox, &QComboBox::activated,
this, &Window::fillGradientChanged);
connect(fillColor2ComboBox, &QComboBox::activated,
this, &Window::fillGradientChanged);
connect(penColorComboBox, &QComboBox::activated,
this, &Window::penColorChanged);
for (RenderArea *area : std::as_const(renderAreas)) {
connect(penWidthSpinBox, &QSpinBox::valueChanged,
area, &RenderArea::setPenWidth);
connect(rotationAngleSpinBox, &QSpinBox::valueChanged,
area, &RenderArea::setRotationAngle);
}Wir verbinden die Signale „ activated()“ der Comboboxen mit den zugehörigen Slots in der Klasse „ Window “, während wir das Signal „ valueChanged()“ der Spinboxen direkt mit den jeweiligen Slots des Widgets „ RenderArea “ verbinden.
QGridLayout *topLayout = new QGridLayout;
int i = 0;
for (RenderArea *area : std::as_const(renderAreas)) {
topLayout->addWidget(area, i / 3, i % 3);
++i;
}
QGridLayout *mainLayout = new QGridLayout;
mainLayout->addLayout(topLayout, 0, 0, 1, 4);
mainLayout->addWidget(fillRuleLabel, 1, 0);
mainLayout->addWidget(fillRuleComboBox, 1, 1, 1, 3);
mainLayout->addWidget(fillGradientLabel, 2, 0);
mainLayout->addWidget(fillColor1ComboBox, 2, 1);
mainLayout->addWidget(fillToLabel, 2, 2);
mainLayout->addWidget(fillColor2ComboBox, 2, 3);
mainLayout->addWidget(penWidthLabel, 3, 0);
mainLayout->addWidget(penWidthSpinBox, 3, 1, 1, 3);
mainLayout->addWidget(penColorLabel, 4, 0);
mainLayout->addWidget(penColorComboBox, 4, 1, 1, 3);
mainLayout->addWidget(rotationAngleLabel, 5, 0);
mainLayout->addWidget(rotationAngleSpinBox, 5, 1, 1, 3);
setLayout(mainLayout);Wir fügen die Widgets „ RenderArea “ zu einem separaten Layout hinzu, das wir anschließend zusammen mit den übrigen Widgets in das Hauptlayout einfügen.
fillRuleChanged();
fillGradientChanged();
penColorChanged();
penWidthSpinBox->setValue(2);
setWindowTitle(tr("Painter Paths"));
}Abschließend initialisieren wir die „ RenderArea “-Widgets, indem wir die Slots „ fillRuleChanged() “, „ fillGradientChanged() “ und „ penColorChanged() “ aufrufen, und legen die anfängliche Stiftbreite sowie den Fenstertitel fest.
void Window::fillRuleChanged()
{
Qt::FillRule rule = (Qt::FillRule)currentItemData(fillRuleComboBox).toInt();
for (RenderArea *area : std::as_const(renderAreas))
area->setFillRule(rule);
}
void Window::fillGradientChanged()
{
QColor color1 = qvariant_cast<QColor>(currentItemData(fillColor1ComboBox));
QColor color2 = qvariant_cast<QColor>(currentItemData(fillColor2ComboBox));
for (RenderArea *area : std::as_const(renderAreas))
area->setFillGradient(color1, color2);
}
void Window::penColorChanged()
{
QColor color = qvariant_cast<QColor>(currentItemData(penColorComboBox));
for (RenderArea *area : std::as_const(renderAreas))
area->setPenColor(color);
}Die privaten Slots dienen dazu, den neuen Wert oder die neuen Werte aus den zugehörigen Comboboxen abzurufen und die „RenderArea“-Widgets zu aktualisieren.
Zunächst ermitteln wir den neuen Wert oder die neuen Werte mithilfe der privaten Funktion ` currentItemData() ` und der Template-Funktion ` qvariant_cast()`. Anschließend rufen wir für jedes der ` RenderArea `-Widgets den zugehörigen Slot auf, um die Malpfade zu aktualisieren.
void Window::populateWithColors(QComboBox *comboBox)
{
const QStringList colorNames = QColor::colorNames();
for (const QString &name : colorNames)
comboBox->addItem(name, QColor(name));
}Die Funktion ` populateWithColors() ` füllt die angegebene Combobox mit Elementen, die den Qt bekannten Farbnamen entsprechen, die von der statischen Funktion ` QColor::colorNames()` bereitgestellt werden.
QVariant Window::currentItemData(QComboBox *comboBox)
{
return comboBox->itemData(comboBox->currentIndex());
}Die Funktion „ currentItemData() “ gibt einfach den aktuellen Eintrag der angegebenen Combobox zurück.
Definition der Klasse „RenderArea“
Die Klasse ` RenderArea ` erbt von ` QWidget` und ist ein benutzerdefiniertes Widget, das einen einzelnen Malerpfad anzeigt.
class RenderArea : public QWidget
{
Q_OBJECT
public:
explicit RenderArea(const QPainterPath &path, QWidget *parent = nullptr);
QSize minimumSizeHint() const override;
QSize sizeHint() const override;
public slots:
void setFillRule(Qt::FillRule rule);
void setFillGradient(const QColor &color1, const QColor &color2);
void setPenWidth(int width);
void setPenColor(const QColor &color);
void setRotationAngle(int degrees);
protected:
void paintEvent(QPaintEvent *event) override;Wir deklarieren mehrere öffentliche Slots, die den zugehörigen Malpfad des „ RenderArea “-Widgets aktualisieren. Darüber hinaus implementieren wir die Funktionen „ QWidget::minimumSizeHint()“ und „ QWidget::sizeHint()“ neu, um dem „ RenderArea “-Widget eine angemessene Größe innerhalb unserer Anwendung zu geben, und wir implementieren den Ereignis-Handler „ QWidget::paintEvent()“ neu, um seinen Malpfad zu zeichnen.
private:
QPainterPath path;
QColor fillColor1;
QColor fillColor2;
int penWidth;
QColor penColor;
int rotationAngle;
};Jede Instanz der Klasse „ RenderArea “ verfügt über ein „ QPainterPath “, einige Füllfarben, eine Stiftbreite, eine Stiftfarbe und einen Drehwinkel.
Implementierung der Klasse „RenderArea“
Der Konstruktor nimmt ein ` QPainterPath ` als Argument entgegen (zusätzlich zum optionalen übergeordneten ` QWidget `):
RenderArea::RenderArea(const QPainterPath &path, QWidget *parent)
: QWidget(parent), path(path)
{
penWidth = 1;
rotationAngle = 0;
setBackgroundRole(QPalette::Base);
}Im Konstruktor initialisieren wir das „ RenderArea “-Widget mit dem Parameter „ QPainterPath “ sowie die Stiftbreite und den Drehwinkel. Außerdem legen wir die Widget-Eigenschaften „ background role “ und „ QPalette::Base “ fest; „ “ ist in der Regel weiß.
QSize RenderArea::minimumSizeHint() const
{
return QSize(50, 50);
}
QSize RenderArea::sizeHint() const
{
return QSize(100, 100);
}Anschließend implementieren wir die Funktionen „ QWidget::minimumSizeHint()“ und „ QWidget::sizeHint()“ neu, um dem Widget „ RenderArea “ eine angemessene Größe innerhalb unserer Anwendung zuzuweisen.
void RenderArea::setFillRule(Qt::FillRule rule)
{
path.setFillRule(rule);
update();
}
void RenderArea::setFillGradient(const QColor &color1, const QColor &color2)
{
fillColor1 = color1;
fillColor2 = color2;
update();
}
void RenderArea::setPenWidth(int width)
{
penWidth = width;
update();
}
void RenderArea::setPenColor(const QColor &color)
{
penColor = color;
update();
}
void RenderArea::setRotationAngle(int degrees)
{
rotationAngle = degrees;
update();
}Die verschiedenen öffentlichen Slots aktualisieren den Malpfad des „ RenderArea “-Widgets, indem sie die zugehörige Eigenschaft setzen und die Funktion „ QWidget::update()“ aufrufen, wodurch ein Neuzurzeichnen des Widgets mit den neuen Darstellungseinstellungen erzwungen wird.
Der Slot „ QWidget::update()“ löst keine sofortige Neuzeichnung aus; stattdessen plant er ein Paint-Ereignis zur Verarbeitung ein, sobald Qt zur Hauptereignisschleife zurückkehrt.
void RenderArea::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);Ein Malereignis ist eine Anforderung, das Widget ganz oder teilweise neu zu zeichnen. Die Funktion `paintEvent()` ist ein Ereignis-Handler, der neu implementiert werden kann, um die Malereignisse des Widgets zu empfangen. Wir implementieren den Ereignis-Handler neu, um den Malpfad des „ RenderArea “-Widgets zu rendern.
Zunächst erstellen wir ein „ QPainter “ für die Instanz „ RenderArea “ und legen die Render-Hinweise für den Painter fest. Die „ QPainter::RenderHints “ dienen dazu, Flags an „ QPainter “ zu übergeben, die von einer bestimmten Engine berücksichtigt werden können – oder auch nicht. „ QPainter::Antialiasing “ gibt an, dass die Engine die Kanten von Primitiven nach Möglichkeit glätten soll, d. h. zusätzliche Pixel um die ursprünglichen herum platzieren soll, um die Kanten zu glätten.
painter.scale(width() / 100.0, height() / 100.0);
painter.translate(50.0, 50.0);
painter.rotate(-rotationAngle);
painter.translate(-50.0, -50.0);Anschließend skalieren wir das Koordinatensystem von ` QPainter`, um sicherzustellen, dass der Painter-Pfad in der richtigen Größe gerendert wird, d. h., dass er mit dem Widget ` RenderArea ` mitwächst, wenn die Größe der Anwendung geändert wird. Als wir die verschiedenen Malpfade erstellt haben, wurden sie alle innerhalb eines Quadrats mit einer Breite von 100 Pixeln gerendert, was RenderArea::sizeHint() entspricht. Die Funktion „ QPainter::scale()“ skaliert das Koordinatensystem um die aktuelle Breite und Höhe des Widgets „ RenderArea “, geteilt durch 100.
Sobald wir sicher sind, dass der Malpfad die richtige Größe hat, können wir das Koordinatensystem verschieben, damit sich der Malpfad um den Mittelpunkt des Widgets „ RenderArea “ dreht. Nachdem wir die Drehung durchgeführt haben, müssen wir daran denken, das Koordinatensystem wieder zurück zu verschieben.
painter.setPen(QPen(penColor, penWidth, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
QLinearGradient gradient(0, 0, 0, 100);
gradient.setColorAt(0.0, fillColor1);
gradient.setColorAt(1.0, fillColor2);
painter.setBrush(gradient);
painter.drawPath(path);
}Anschließend legen wir den Stift des „ QPainter “-Widgets anhand der Darstellungspräferenzen der Instanz fest. Wir erstellen ein „ QLinearGradient “ und legen dessen Farben entsprechend den Füllfarben des „ RenderArea “-Widgets fest. Schließlich legen wir den Pinsel des „ QPainter “-Widgets fest (der Farbverlauf wird automatisch in ein „ QBrush “-Widget umgewandelt) und zeichnen den Malpfad des „ RenderArea “-Widgets mithilfe der Funktion „ QPainter::drawPath()“.
© 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.