Here is one way to do it:
// TB.qml
MouseArea {
width: txt.contentWidth + 20
height: txt.contentHeight + 10
property alias text: txt.text
property alias color: sh.color
ShaderEffect {
id: sh
anchors.fill: parent
property color color: "red"
property var source : ShaderEffectSource {
sourceRect: Qt.rect(0, 0, sh.width, sh.height)
sourceItem: Item {
width: sh.width
height: sh.height
Text {
id: txt
anchors.centerIn: parent
font.bold: true
font.pointSize: 30
text: "test"
}
}
}
fragmentShader:
"varying highp vec2 qt_TexCoord0;
uniform highp vec4 color;
uniform sampler2D source;
void main() {
gl_FragColor = color * (1.0 - texture2D(source, qt_TexCoord0).w);
}"
}
}
Using it:
TB {
text: "HELLO WORLD!!!"
color: "red"
onClicked: console.log("hi world")
}
Result:
The button is red, the text is grey from the grey background, and it will accurately show anything that's beneath the button.
Obviously, the button is rudimentary, but the example outta be enough to get you going and implement something according to your needs.
The key element here is the custom shader, which is a very basic one - it colorizes every fragment and applies the mask as alpha. Obviously, you can use ShaderEffectSource
to turn any QML Item to a texture, and replace the ShaderEffectSource
with another sampler 2D
and mix the two textures in any way you want, cut using the alpha channel, or any of the RGB if you are using a grayscale mask. And unlike the rather limited OpacityMask
element, this will actually cut through and show anything that is underneath as it is supposed to.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…