jkj yuio
jkj yuio

Reputation: 2613

QT QML How to add LinearGradient to a Rectangle with a border?

I would like to have a more specific gradient than the default vertical one for a Rectangle. I try adding a LinearGradient for a diagonal effect, but it overwrites the border.

Consider this example. Top Rectangle ok with vertical gradient and border. Bottom Rectangle gradient overwrites border and radius. I tried clip and gradient: LinearGradient but they didn't work either.

import QtQuick 2.7
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import QtGraphicalEffects 1.0

ApplicationWindow
{
    visible: true
    width: 640
    height: 480

    Column
    {
        spacing: 20
        width: parent.width
        Rectangle 
        {
            width: 200
            height: 200

            border.width: 4
            border.color: "#888"
            radius: 10

            // adds a vertical gradient to button
            gradient: Gradient
            {
                GradientStop 
                {
                    position: 0
                    color: "#eee"
                }
                GradientStop
                {
                    position: 1
                    color: "#ccc"
                }
            }
        }

        Rectangle 
        {
            width: 200
            height: 200

            border.width: 4
            border.color: "#888"
            radius: 10

            // try to add diagonal gradient, but overwrites button border
            // also can't do, gradient: LinearGradient  ?
            LinearGradient
            {
                anchors.fill: parent
                start: Qt.point(0,0)
                end: Qt.point(parent.width,parent.height)

                gradient: Gradient
                {
                    GradientStop 
                    {
                        position: 0
                        color: "#eee"
                    }
                    GradientStop
                    {
                        position: 1
                        color: "#ccc"
                    }
                }
            }
        }
    }
}

Results in this:

enter image description here

I can see why this might have this result, but how to clip the gradient to a Rectangle with a radius?

Upvotes: 4

Views: 7592

Answers (2)

derM
derM

Reputation: 13691

clip always clips at the bounding rectangle of the Item that is clipping, and does not care for alpha-values.

However the LinearGradient has another tool, to achive what you want:
- the source-property.

See this example:

import QtQuick 2.0
import QtQuick.Window 2.0
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import QtGraphicalEffects 1.0
Window {
    width: 1024
    height: 800
    visible: true

    Rectangle {
        id: rect1
        width: 100
        height: 100
        radius: 20
    }

    LinearGradient {
        anchors.fill: rect1
        source: rect1          <-- Here is where you specify its shape. 
        start: Qt.point(0, 0)
        end: Qt.point(300, 300)
        gradient: Gradient {
            GradientStop { position: 0.0; color: "white" }
            GradientStop { position: 1.0; color: "black" }
        }
    }
}

Upvotes: 5

dtech
dtech

Reputation: 49279

QML only supports vertical gradients. You can fake horizontal gradients by flipping the item's width and height and rotating it.

For a diagonal that won't work, as the rectangle would also be rotated.

As for the plan to use clipping, that won't work either, because the QML screnegraph only clips to the item's rectangle, not its actual visible pixels.

There are two approaches you ca take:

1 - try to accomplish the desired result via the Canvas element.

2 - use a ShaderEffect to which you pass a ShaderEffectSource texture with the gradient and a rounded rectangle, then in the actual shader use the rgb from the first source (the gradient) and the alpha from the second (the rounded rectangle) to manually clip.

3 - if you are going to be using ShaderEffect you can easily skip using a gradient as a source, and look up how to implement a gradient at an arbitrary angle in GLSL, and only use the rounded rectangle source for the alpha, even though the "rounded" part can just as well be implemented in the shader.

Upvotes: 0

Related Questions