Search code examples
c++qtqmlqt-quickqtquick2

QML Inner Shadow effect


I want to create a rectangle with inner shadow in QML, something similar with what Photoshop does:

enter image description here

QML has InnerShadow but I'm unable to achieve this effect. The closest I got was this

import QtQuick 2.0
import QtGraphicalEffects 1.0

Item {
    id: root
    width: 300
    height: 300

    Rectangle {
        id: myRectangle
        anchors.centerIn: parent
        width: 100
        height: 100
        color: "grey"
    }

    InnerShadow {
        anchors.fill: root
        cached: true
        horizontalOffset: 0
        verticalOffset: 0
        radius: 16
        samples: 32
        color: "#b0000000"
        smooth: true
        source: root
    }
}

which is an idea I got from this post. However this example only works if root has a significantly bigger size than myRectangle and I don't want that. I need e.g. a 200x10 square in which shadow is uniformly spread across the edges of the rectangle. I tried all kinds of values for the InnerShadow properties but I couldn't get even close to the effect I want.

Can this be achieved using QML?


Solution

  • The "correct" approach - quotation marks needed - to use the effect should be this one:

    import QtQuick 2.0
    import QtGraphicalEffects 1.0
    
    Item {
       id: root
       width: 300
       height: 300
    
       Item {
           id: src
           anchors.fill: parent
    
           Rectangle {
               id: myRectangle
               anchors.centerIn: parent
               width: 100
               height: 100
               color: "grey"
           }
       }
    
       InnerShadow {
           anchors.fill: src
           cached: true
           horizontalOffset: 0
           verticalOffset: 0
           radius: 16
           samples: 32
           color: "#b0000000"
           smooth: true
           source: src
       }
    }
    

    As you can see it is slightly different from the propose solution in the other question. Using this code you still need to left 2 pixels, to have the effect, which results in a white border (or whatever is the background color). The issue can be easily solved by changing the root to be a Rectangle.

    Final example solution follows. Clearly you can extract the root component (and related children) and place it in a Component or a different .qml file for later usage.

    import QtQuick 2.4
    import QtQuick.Window 2.2
    import QtGraphicalEffects 1.0
    
    Window {
        width: 200
        height: 20
        visible: true
    
        Rectangle {     // was Item
            id: root
            anchors.fill: parent
            color: "grey"
    
    
            Item {
                id: src
                anchors.fill: parent
    
                Rectangle {
                    id: myRectangle
                    anchors.centerIn: parent
                    width: root.width - 2
                    height: root.height - 2
                    color: "lightgrey"
                }
            }
    
            InnerShadow {
                anchors.fill: src
                cached: true
                horizontalOffset: 0
                verticalOffset: 0
                radius: 16
                samples: 32
                color: "#b0000000"
                smooth: true
                source: src
            }
        }
    }
    

    The resulting window for the final code example:

    enter image description here