2
votes

I have a simple Rectangle with rounded corners (radius), but want to apply a gradient for it's background color.

Rectangle {
    id: rect
    width: 200
    height: 200

    radius: 20

    LinearGradient {
        anchors.fill: parent
        start: Qt.point(0,parent.height/2)
        end: Qt.point(parent.width,parent.height/2)
        gradient: Gradient {
            GradientStop { position: 0.0; color: "red" }
            GradientStop { position: 1.0; color: "green" }
        }
    }
}

I am thinking an OpacityMask might help? I have tried using one to no avail, though. I am wondering if I am just missing something or if the solution is more complicated.

3
This code gets me a nice gradient with rounded corners, what's the problem exactly? - dtech
Oops, you are right. I trimmed my code in order to simplify it. I am using a LinearGradient wrapping the gradient because I want to have custom start and end points. I modified my original post to more accurately reflect what I am looking for. - brandon

3 Answers

1
votes

Well, an opacity mask should work, you will however have to hide the source for the rounded corners to become visible, otherwise they will show from the back...

  Rectangle {
    id: rect
    width: 200
    height: 200    
    // radius: 20 - redundant
    visible: false // hide it!!!

    LinearGradient {
      anchors.fill: parent
      start: Qt.point(0,parent.height/2)
      end: Qt.point(parent.width,parent.height/2)
      gradient: Gradient {
        GradientStop { position: 0.0; color: "red" }
        GradientStop { position: 1.0; color: "green" }
      }
    }
  }

  OpacityMask {
    anchors.fill: rect
    source: rect
    maskSource: Rectangle {
      width: 200
      height: 200
      radius: 20
    }
  }
3
votes

Qt Graphical Effects are powerful, but the power comes at a cost. It's best to stay with the Qt Quick core primitives whenever it's possible. Perhaps it's just the simplified test case, and the real life use case is something much more complicated, but the shown test case is doable with a simple and light rounded, rotated, and gradient filled Rectangle:

Rectangle {
    id: rect
    width: 200
    height: 200

    radius: 20
    rotation: -90

    gradient: Gradient {
        GradientStop { position: 0.0; color: "red" }
        GradientStop { position: 1.0; color: "green" }
    }
}

To back up the performance claims, let's take a look at some numbers measured with the QML bench benchmarking tool. We're benchmarking a solution that uses OpacityMask and LinearGradient against the above solution with a plain Rectangle and Gradient. The benchmarks were run with the latest Qt 5.10.1 release on an old and crappy MacBook Air (Intel Core i5-4260U, Intel HD 5000, macOS 10.13).

LinearGradient + OpacityMask

ID:          
OS:          macOS High Sierra (10.13)
QPA:         cocoa
GL_VENDOR:   Intel Inc.
GL_RENDERER: Intel HD Graphics 5000 OpenGL Engine
GL_VERSION:  2.1 INTEL-10.30.14
running: lineargradient_opacitymask.qml
    11 frames
    11 frames
    11 frames
    11 frames
    11 frames
    Average: 11  frames;; MedianAll=11; StdDev=0, CoV=0
All done...

Rectangle::gradient

ID:          
OS:          macOS High Sierra (10.13)
QPA:         cocoa
GL_VENDOR:   Intel Inc.
GL_RENDERER: Intel HD Graphics 5000 OpenGL Engine
GL_VERSION:  2.1 INTEL-10.30.14
running: rect_gradient.qml
    332 frames
    331 frames
    334 frames
    313 frames
    331 frames
    Average: 328.2  frames;; MedianAll=331; StdDev=8.58487, CoV=0.0261574
All done...
3
votes

Set the source property of your LinearGradient, it should solve this issue:

Rectangle {

    id: rect
    width: 200
    height: 200
    radius: 20

    LinearGradient {
        anchors.fill: parent
        source: rect
        start: Qt.point(0,parent.height/2)
        end: Qt.point(parent.width,parent.height/2)
        gradient: Gradient {
            GradientStop { position: 0.0; color: "red" }
            GradientStop { position: 1.0; color: "green" }
        }
    }
}