En esta página

Ejemplo de rutas de pintura

El ejemplo de rutas de pintado muestra cómo utilizar rutas de pintado para construir formas complejas para el renderizado.

Aplicación que muestra diversas formas y opciones gráficas

La clase QPainterPath proporciona un contenedor para operaciones de pintado, permitiendo construir y reutilizar formas gráficas.

Un trazado de pintor es un objeto compuesto por una serie de bloques de construcción gráficos (como rectángulos, elipses, líneas y curvas), y puede utilizarse para rellenar, contornear y recortar. La principal ventaja de los trazados de pintor sobre las operaciones de dibujo normales es que las formas complejas sólo necesitan crearse una vez, pero pueden dibujarse muchas veces utilizando únicamente llamadas a QPainter::drawPath().

El ejemplo consta de dos clases:

  • La clase RenderArea que es un widget personalizado que muestra un único trazado de pintor.
  • La clase Window que es la ventana principal de la aplicación que muestra varios widgets RenderArea, y permite al usuario manipular el relleno, la pluma, el color y el ángulo de rotación de los trazados del pintor.

Primero revisaremos la clase Window, después echaremos un vistazo a la clase RenderArea.

Definición de la clase Window

La clase Window hereda de QWidget, y es la ventana principal de la aplicación que muestra varios widgets de RenderArea, y permite al usuario manipular el relleno, la pluma, el color y el ángulo de rotación de los trazados del pintor.

class Window : public QWidget
{
    Q_OBJECT

public:
    Window();

private slots:
    void fillRuleChanged();
    void fillGradientChanged();
    void penColorChanged();

Declaramos tres ranuras privadas para responder a la entrada del usuario en relación con el relleno y el color: fillRuleChanged(), fillGradientChanged() y penColorChanged().

Cuando el usuario cambia la anchura del lápiz y el ángulo de rotación, el nuevo valor se pasa directamente a los widgets RenderArea utilizando la señal QSpinBox::valueChanged(). La razón por la que debemos implementar ranuras para actualizar el relleno y el color, es que QComboBox no proporciona una señal similar pasando el nuevo valor como argumento; así que necesitamos recuperar el nuevo valor, o valores, antes de poder actualizar los widgets RenderArea.

private:
    void populateWithColors(QComboBox *comboBox);
    QVariant currentItemData(QComboBox *comboBox);

También declaramos un par de funciones privadas convenientes: populateWithColors() rellena un QComboBox dado con elementos correspondientes a los nombres de color que Qt conoce, y currentItemData() devuelve el elemento actual para un QComboBox dado.

    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;
};

A continuación, declaramos los distintos componentes del widget de la ventana principal. También declaramos una constante que especifica el número de widgets RenderArea.

Implementación de la clase Window

En el constructor Window, definimos los distintos trazados del pintor y creamos los widgets RenderArea correspondientes que renderizarán las formas gráficas:

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();

Construimos un rectángulo con esquinas afiladas utilizando las funciones QPainterPath::moveTo() y QPainterPath::lineTo().

QPainterPath::moveTo() mueve el punto actual al punto pasado como argumento. Una trayectoria de pintor es un objeto compuesto por una serie de bloques de construcción gráficos, es decir, subtrayectorias. Al desplazar el punto actual también se iniciará un nuevo subtrayecto (cerrando implícitamente el trayecto actual cuando se inicie el nuevo). La función QPainterPath::lineTo() añade una línea recta desde el punto actual hasta el punto final dado. Después de dibujar la línea, el punto actual se actualiza para estar en el punto final de la línea.

Primero movemos el punto actual comenzando un nuevo subcamino, y dibujamos tres de los lados del rectángulo. Luego llamamos a la función QPainterPath::closeSubpath() que dibuja una línea hasta el comienzo del subtrayecto actual. Un nuevo subtrayecto se inicia automáticamente cuando se cierra el subtrayecto actual. El punto actual del nuevo camino es (0, 0). También podríamos haber llamado a QPainterPath::lineTo() para dibujar también la última línea, y luego iniciar explícitamente un nuevo subtrayecto utilizando la función QPainterPath::moveTo().

QPainterPath también proporciona la función de conveniencia QPainterPath::addRect(), que añade un rectángulo dado al camino como un subcamino cerrado. El rectángulo se añade como un conjunto de líneas en el sentido de las agujas del reloj. La posición actual de la ruta del pintor después de añadir el rectángulo es la esquina superior izquierda del rectángulo.

    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();

A continuación, construimos un rectángulo con esquinas redondeadas. Como antes, utilizamos las funciones QPainterPath::moveTo() y QPainterPath::lineTo() para dibujar los lados del rectángulo. Para crear las esquinas redondeadas utilizamos la función QPainterPath::arcTo().

QPainterPath::arcTo() crea un arco que ocupa el rectángulo dado (especificado por QRect o las coordenadas del rectángulo), comenzando en el ángulo inicial dado y extendiéndose los grados dados en sentido contrario a las agujas del reloj. Los ángulos se especifican en grados. Los arcos en el sentido de las agujas del reloj pueden especificarse utilizando ángulos negativos. La función conecta el punto actual con el punto inicial del arco si no están ya conectados.

    QPainterPath ellipsePath;
    ellipsePath.moveTo(80.0, 50.0);
    ellipsePath.arcTo(20.0, 30.0, 60.0, 40.0, 0.0, 360.0);

También utilizamos la función QPainterPath::arcTo() para construir la trayectoria de la elipse. Primero movemos el punto actual iniciando una nueva trayectoria. Luego llamamos a QPainterPath::arcTo() con ángulo inicial 0.0 y 360.0 grados como último argumento, creando una elipse.

De nuevo, QPainterPath proporciona una función de conveniencia ( QPainterPath::addEllipse()) que crea una elipse dentro de un rectángulo delimitador dado y la añade a la trayectoria del pintor. Si el subtrayecto actual está cerrado, se inicia un nuevo subtrayecto. La elipse se compone de una curva en el sentido de las agujas del reloj, que comienza y termina en cero grados (la posición de las 3 en punto).

    QPainterPath piePath;
    piePath.moveTo(50.0, 50.0);
    piePath.arcTo(20.0, 30.0, 60.0, 40.0, 60.0, 240.0);
    piePath.closeSubpath();

Al construir la trayectoria del gráfico circular seguimos utilizando una combinación de las funciones mencionadas: Primero movemos el punto actual, iniciando un nuevo subtrayecto. Después creamos una línea desde el centro del gráfico hasta el arco, y el propio arco. Cuando cerramos el subtrayecto, implícitamente construimos la última línea de vuelta al centro del gráfico.

    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();

Construir un polígono es equivalente a construir un rectángulo.

QPainterPath también proporciona la función de conveniencia QPainterPath::addPolygon() que añade el polígono dado al trazado como un nuevo subtrazado. La posición actual después de añadir el polígono es el último punto del polígono.

    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();

A continuación, creamos un trayecto formado por un grupo de subtrayectos: Primero movemos el punto actual, y creamos un círculo usando la función QPainterPath::arcTo() con ángulo inicial 0.0, y 360 grados como último argumento, como hicimos cuando creamos la trayectoria elipse. A continuación, volvemos a mover el punto actual, iniciando un nuevo subtrayecto, y construimos tres lados de un cuadrado utilizando la función QPainterPath::lineTo().

Ahora, cuando llamamos a la función QPainterPath::closeSubpath() se crea el último lado. Recuerda que la función QPainterPath::closeSubpath() dibuja una línea hasta el principio del subcamino actual, es decir, el cuadrado.

QPainterPath proporcionan una función de conveniencia, QPainterPath::addPath() que añade un camino dado al camino que llama la función.

    QPainterPath textPath;
    QFont timesFont("Times", 50);
    timesFont.setStyleStrategy(QFont::ForceOutline);
    textPath.addText(10, 70, timesFont, tr("Qt"));

Al crear la ruta de texto, primero creamos la fuente. A continuación, establecemos la estrategia de estilo de la fuente que indica al algoritmo de correspondencia de fuentes qué tipo de fuentes se deben utilizar para encontrar una familia predeterminada adecuada. QFont::ForceOutline fuerza el uso de fuentes de contorno.

Para construir el texto, utilizamos la función QPainterPath::addText() que añade el texto dado a la ruta como un conjunto de sub-rutas cerradas creadas a partir de la fuente suministrada. Las subtrayectorias se colocan de modo que el extremo izquierdo de la línea de base del texto se encuentre en el punto especificado.

    QPainterPath bezierPath;
    bezierPath.moveTo(20, 30);
    bezierPath.cubicTo(80, 0, 50, 50, 80, 80);

Para crear la trayectoria Bezier, utilizamos la función QPainterPath::cubicTo() que añade una curva Bezier entre el punto actual y el punto final dado con el punto de control dado. Después de añadir la curva, el punto actual se actualiza para estar en el punto final de la curva.

En este caso omitimos cerrar el subtrayecto de forma que sólo tenemos una curva simple. Pero sigue existiendo una línea lógica desde el punto final de la curva hasta el principio de la subtrayectoria; se hace visible al rellenar la trayectoria, como puede verse en la ventana principal de la aplicación.

    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();

El trazado final que construimos muestra que se puede utilizar QPainterPath para construir formas bastante complejas utilizando únicamente las funciones anteriormente mencionadas QPainterPath::moveTo(), QPainterPath::lineTo() y QPainterPath::closeSubpath().

    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));

Ahora que hemos creado todos los trazados de pintor que necesitamos, creamos un widget RenderArea correspondiente para cada uno. Al final, nos aseguramos de que el número de áreas de renderizado es correcto utilizando la macro Q_ASSERT().

    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);

A continuación, creamos los widgets asociados a la regla de relleno de las rutas de pintado.

Hay dos reglas de relleno disponibles en Qt: La regla Qt::OddEvenFill determina si un punto está dentro de la forma dibujando una línea horizontal desde el punto hasta un lugar fuera de la forma, y cuenta el número de intersecciones. Si el número de intersecciones es impar, el punto está dentro de la forma. Esta regla es la predeterminada.

La regla Qt::WindingFill determina si un punto está dentro de la forma trazando una línea horizontal desde el punto hasta un lugar fuera de la forma. A continuación, determina si la dirección de la línea en cada punto de intersección es hacia arriba o hacia abajo. El número sinuoso se determina sumando la dirección de cada intersección. Si el número es distinto de cero, el punto está dentro de la forma.

La regla Qt::WindingFill puede considerarse en la mayoría de los casos como la intersección de formas cerradas.

    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);

También creamos los demás widgets asociados al relleno, la pluma y el ángulo de rotación.

    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);
    }

Conectamos las señales de los comboboxes activated() a los slots asociados en la clase Window, mientras que conectamos la señal de los spin boxes valueChanged() directamente a los slots respectivos del widget RenderArea.

    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);

Añadimos los widgets RenderArea a un diseño separado que luego añadimos al diseño principal junto con el resto de widgets.

    fillRuleChanged();
    fillGradientChanged();
    penColorChanged();
    penWidthSpinBox->setValue(2);

    setWindowTitle(tr("Painter Paths"));
}

Finalmente, inicializamos los widgets RenderArea llamando a los slots fillRuleChanged(), fillGradientChanged() y penColorChanged(), y establecemos el ancho inicial del lápiz y el título de la ventana.

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);
}

Las ranuras privadas se implementan para recuperar el nuevo valor, o valores, de los comboboxes asociados y actualizar los widgets RenderArea.

Primero determinamos el nuevo valor, o valores, utilizando la función privada currentItemData() y la función de plantilla qvariant_cast(). A continuación, llamamos a la ranura asociada para cada uno de los widgets RenderArea para actualizar las rutas del pintor.

void Window::populateWithColors(QComboBox *comboBox)
{
    const QStringList colorNames = QColor::colorNames();
    for (const QString &name : colorNames)
        comboBox->addItem(name, QColor(name));
}

La función populateWithColors() rellena el combobox dado con los elementos correspondientes a los nombres de color que Qt conoce proporcionados por la función estática QColor::colorNames().

QVariant Window::currentItemData(QComboBox *comboBox)
{
    return comboBox->itemData(comboBox->currentIndex());
}

La función currentItemData() simplemente devuelve el elemento actual del combobox dado.

Definición de la clase RenderArea

La clase RenderArea hereda de QWidget, y es un widget personalizado que muestra una única ruta de pintado.

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;

Declaramos varias ranuras públicas que actualizan la ruta del pintor asociada al widget RenderArea. Además, reimplementamos las funciones QWidget::minimumSizeHint() y QWidget::sizeHint() para dar al widget RenderArea un tamaño razonable dentro de nuestra aplicación, y reimplementamos el manejador de eventos QWidget::paintEvent() para dibujar su ruta de pintor.

private:
    QPainterPath path;
    QColor fillColor1;
    QColor fillColor2;
    int penWidth;
    QColor penColor;
    int rotationAngle;
};

Cada instancia de la clase RenderArea tiene un QPainterPath, un par de colores de relleno, un ancho de pluma, un color de pluma y un ángulo de rotación.

Implementación de la clase RenderArea

El constructor toma un QPainterPath como argumento (además del padre opcional QWidget ):

RenderArea::RenderArea(const QPainterPath &path, QWidget *parent)
    : QWidget(parent), path(path)
{
    penWidth = 1;
    rotationAngle = 0;
    setBackgroundRole(QPalette::Base);
}

En el constructor inicializamos el widget RenderArea con el parámetro QPainterPath además de inicializar el ancho del lápiz y el ángulo de rotación. También establecemos el widget background role; QPalette::Base es típicamente blanco.

QSize RenderArea::minimumSizeHint() const
{
    return QSize(50, 50);
}

QSize RenderArea::sizeHint() const
{
    return QSize(100, 100);
}

Luego reimplementamos las funciones QWidget::minimumSizeHint() y QWidget::sizeHint() para dar al widget RenderArea un tamaño razonable dentro de nuestra aplicación.

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();
}

Las distintas ranuras públicas actualizan la ruta del pintor del widget RenderArea estableciendo la propiedad asociada y hacen una llamada a la función QWidget::update(), forzando un repintado del widget con las nuevas preferencias de renderizado.

La ranura QWidget::update() no provoca un repintado inmediato, sino que programa un evento de pintura para que se procese cuando Qt vuelva al bucle de eventos principal.

void RenderArea::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);

Un evento de pintura es una petición para repintar todo o parte del widget. La función paintEvent() es un manejador de eventos que puede ser reimplementado para recibir los eventos de pintado del widget. Reimplementamos el manejador de eventos para renderizar la ruta de pintado del widget RenderArea.

Primero, creamos un QPainter para la instancia RenderArea, y establecemos las pistas de renderizado del pintor. Los QPainter::RenderHints se utilizan para especificar banderas a QPainter que pueden, o no, ser respetadas por cualquier motor dado. QPainter::Antialiasing indica que el motor debe antialiasear los bordes de las primitivas si es posible, es decir, poner píxeles adicionales alrededor de los originales para suavizar los bordes.

    painter.scale(width() / 100.0, height() / 100.0);
    painter.translate(50.0, 50.0);
    painter.rotate(-rotationAngle);
    painter.translate(-50.0, -50.0);

A continuación, escalamos el sistema de coordenadas de QPainter para asegurarnos de que el trazado del pintor se renderiza en el tamaño correcto, es decir, que crece con el widget RenderArea cuando se redimensiona la aplicación. Cuando construimos los distintos trazados del pintor, todos se renderizaron dentro de un cuadrado con una anchura de 100 píxeles, lo que equivale a RenderArea::sizeHint(). La función QPainter::scale() escala el sistema de coordenadas según la anchura y altura actuales del widget RenderArea dividido por 100.

Ahora, cuando estemos seguros de que el trazado del pintor tiene el tamaño correcto, podemos trasladar el sistema de coordenadas para hacer que el trazado del pintor rote alrededor del centro del widget RenderArea. Una vez realizada la rotación, debemos acordarnos de volver a trasladar el sistema de coordenadas.

    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);
}

A continuación, configuramos el lápiz de QPainter con las preferencias de renderizado de la instancia. Creamos un QLinearGradient y establecemos sus colores correspondientes a los colores de relleno del widget RenderArea. Por último, establecemos el pincel de QPainter(el gradiente se convierte automáticamente en QBrush), y dibujamos la ruta del pintor del widget RenderArea utilizando la función QPainter::drawPath().

Proyecto de ejemplo @ code.qt.io

© 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.