Search code examples
qmlopacity

How does opacity work in QML?


I don't understand the behavior of opacity in the following code!

import QtQuick 2.4

Rectangle {
    id: root
    width: 640; height: 480

    Rectangle {
        id: wrapper
        width: 600; height:440
        anchors.centerIn: parent
        color: "black"
        opacity: 0.5

        Rectangle {
            id: belowcover
            width: cover.width / 2
            height: cover.height / 2
            anchors.centerIn: parent
            color: "green"
            z: 1
        }

        Rectangle {
            id: cover
            width: root.width / 2
            height: root.height / 2
            anchors.centerIn: parent
            color: "red"
            z: 1
        }

        Rectangle {
            id: seen
            width: 100; height: 100
            radius: width
            color: "blue"
            z: -1
        }
    }
}

The wrapper has opacity of 0.5 so that I could see through it in order to see the circle seen. But both cover and belowcover have opacity of 1, and as belowcover is smaller than cover, it should not be seen (or rather I expect it not to be seen, or am I missing something?). But both cover and belowcover are seen. I want only the circle to be seen through wrapper, and belowcover is to remain hidden below cover. How can I do this? I have observed that setting the z of cover higher than that of belowcover does not make the latter hidden.

Edit: I have observed that when opacity of parent is set to less than 1, the children objects become less opaque, even though their opacity remains at 1, as seen when printed to console. I don't understand why.


Solution

  • The reason why a child having opacity of 1 yet appearing to have transparency when its parent has opacity less than 1 is: opacity goes along the same line as other properties like x, y, etc. Thus, even though child has opacity of 1, it is relative to that of the parent. So if parent has opacity 0.5, and child has opacity of 1, then absolute opacity value of child is actually 0.5. Another child with opacity of 0.5 actually has opacity of 0.5x0.5=0.25. This is analogous to x value of child being 0, when absolute x may not be 0. This design preserves consistency throughout the API.

    There are several work-arounds. The one I prefer most is to use semi-transparent colors for the parent. Try setting the color of wrapper to color: "#88000000". You can no longer see the green rectangle belowcover. To see that, you have to set the opacity of cover to some value less than 1, which means cover is opaque. That is how I actually solved my problem.

    However, if the parent is an image, then this can't be applied. Then you have to resort to some other techniques. For example:

    1. Using layer. Set layer.enabled: true for parent.
    2. By changing the parent when immediate parent has opacity less than 1.
    3. Many other techniques are listed here.