How to apply opacity mask to a QML element?

The look I'm trying to use is a solid color button and the text on it is like "Hello World" where the text is completely transparent and the background is displayed through the button.

In other words, the presence of text as a transparency mask for the button element.

+4
source share
4 answers

Here is one way to do this:

// 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:

enter image description here

The button is red, the text is gray on a gray background, and it will accurately show everything that is under the button.

, , outta , - .

, : . , ShaderEffectSource, QML ShaderEffectSource sampler 2D , - RGB . OpacityMask, , , .

+5

, OpacityMask, . Qt (5.7.1, ?), : https://github.com/qt/qtgraphicaleffects/blob/5.7.1/src/effects/OpacityMask.qml

MyOpacityMask.qml - Button Qt Quick Controls 2:

Button {
    id: button
    text: "Yolo"
    background.visible: false
    contentItem.visible: false
    contentItem.anchors.fill: button //can be avoided at the cost of creating another Item and ShaderEffectSource
    MyOpacityMask {
        anchors.fill: parent
        invert: true
        source: button.background
        maskSource: button.contentItem
    }
}

Opposite OpacityMask

+3

, OpacityMask .

, , , . - Rectangle. - Rectangle. A Text , . OpacityMask Text , .

import QtQuick 2.7
import QtGraphicalEffects 1.0

Rectangle {
    width: 500
    height: 500

    Rectangle {
        id: background
        anchors.fill: parent

        Rectangle {
            id: left
            anchors.top: parent.top
            anchors.bottom: parent.bottom
            anchors.left: parent.left
            width: parent.width / 2
            color: "red"

            ColorAnimation on color {
                from: "red"
                to: "green"
                duration: 5000
                loops: Animation.Infinite
            }
        }

        Rectangle {
            id: right 
            anchors.top: parent.top
            anchors.bottom: parent.bottom
            anchors.right: parent.right
            width: parent.width / 2
            color: "red"
        }
    }

    Rectangle {
        id: foreground
        anchors.fill: parent
        color: "blue"
    }

    Text {
        id: txt
        anchors.centerIn: parent
        text: "Test"
        font.pointSize: 60
        color: "black"
    }

    OpacityMask {
        anchors.fill: txt
        source: background
        maskSource: txt
    }
}

: , , OpacityMask . ​​, .

+1

, layer, , OpacityMask.
, qml, QtQuick.Controls :)

result

Image {
    id: bk
    source: "http://l7.alamy.com/zooms/7b6f221aadd44ffab6a87c234065b266/sheikh-lotfollah-mosque-at-naqhsh-e-jahan-square-in-isfahan-iran-interior-g07fw2.jpg"
}

Button {
    id: button
    anchors.centerIn: bk
    width: 210; height: 72
    visible: true
    opacity: 0.0
    layer.enabled: true
    layer.smooth: true
    onClicked: console.log("Clicked")
}

Rectangle {
    id: _mask
    anchors.fill: button
    color: "transparent"
    visible: true
    Text {
        font { pointSize: 20; bold: true }
        anchors.centerIn: parent
        text: "Hello World!"
    }

    layer.enabled: true
    layer.samplerName: "maskSource"
    layer.effect: ShaderEffect {
        property variant source: button
        fragmentShader: "
                varying highp vec2 qt_TexCoord0;
                uniform highp float qt_Opacity;
                uniform lowp sampler2D source;
                uniform lowp sampler2D maskSource;
                void main(void) {
                    gl_FragColor = texture2D(source, qt_TexCoord0.st) * (1.0-texture2D(maskSource, qt_TexCoord0.st).a) * qt_Opacity;
                }
            "
    }
}
+1

Source: https://habr.com/ru/post/1656979/


All Articles