如何将不透明蒙版应用于QML项目?

时间:2016-10-06 18:53:48

标签: qt qml qtquick2 qt-quick qtquickcontrols

我想要的外观和感觉是拥有一个纯色按钮,文字就像" Hello World"文本完全透明,背景通过按钮显示。

换句话说,将文本作为按钮元素上的透明蒙版。

4 个答案:

答案 0 :(得分:5)

这是一种方法:

<a href="javascript:;" onclick="ReplaceImage();">Load More</a>

使用它:

// 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);
           }"
  }
}

结果:

enter image description here

按钮为红色,灰色背景中的文字为灰色,并且会准确显示按钮下方的任何内容。

显然,这个按钮很简陋,但是这个例子足以让你根据自己的需要去实现一些东西。

这里的关键元素是自定义着色器,它是一个非常基本的着色器 - 它将每个片段着色并将蒙版应用为alpha。显然,您可以使用 TB { text: "HELLO WORLD!!!" color: "red" onClicked: console.log("hi world") } 将任何QML项目转换为纹理,并将ShaderEffectSource替换为另一个ShaderEffectSource并以您想要的任何方式混合两个纹理,使用Alpha通道剪切,如果您使用的是灰度蒙版,则为任何RGB。与相当有限的sampler 2D元素不同,这实际上会切断并显示其下方的任何内容。

答案 1 :(得分:3)

你想要的是可以倒置的OpacityMask。 这是计划在未来的Qt版本中发布的(可能是5.7.1?),事实上你已经可以看一下它:https://github.com/qt/qtgraphicaleffects/blob/5.7.1/src/effects/OpacityMask.qml

与此同时,您可以将代码复制到名为MyOpacityMask.qml或其他名称的文件中,并以Qt Quick Controls 2中的Button使用它:

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 for OpacityMask

中提及过

答案 2 :(得分:1)

我认为这是OpacityMask的用途。

下面的示例似乎说明了您正在寻找的效果。背景为红色Rectangle。前景是纯蓝色Rectangle。一个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实际上是计算切入层。还添加了一个动画,通过随时间变化显示计算出的剪切。

答案 3 :(得分: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;
                }
            "
    }
}