【问题标题】:How to apply opacity mask to a QML item?如何将不透明蒙版应用于 QML 项目?
【发布时间】:2016-10-06 18:53:48
【问题描述】:

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

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

【问题讨论】:

  • 这是一个完全自定义的按钮控件吗?或者您使用的是 Qt Quick Controls 还是类似的?
  • Qt 快速控制 1 或 2 ?

标签: qt qml qtquick2 qt-quick qtquickcontrols


【解决方案1】:

这是一种方法:

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

使用它:

  TB {
    text: "HELLO WORLD!!!"
    color: "red"
    onClicked: console.log("hi world")
  }

结果:

按钮是红色的,文本是灰色背景中的灰色,它将准确地显示按钮下方的任何内容。

显然,该按钮是初级的,但该示例足以让您开始并根据您的需要实现某些东西。

这里的关键元素是自定义着色器,这是一个非常基本的着色器 - 它为每个片段着色并将蒙版应用为 alpha。显然,您可以使用 ShaderEffectSource 将任何 QML 项目转换为纹理,并将 ShaderEffectSource 替换为另一个 sampler 2D 并以您想要的任何方式混合这两个纹理,使用 alpha 通道或任何 RGB 通道进行剪切如果您使用的是灰度蒙版。与相当有限的 OpacityMask 元素不同,它实际上会切开并显示下面的任何内容。

【讨论】:

    【解决方案2】:

    您可以使用layer 附加属性来实现这一点,如下所示,而不使用OpacityMask
    你也没有任何限制,你可以使用任何 qml 项目,使用任何QtQuick.Controls 并像往常一样设置样式:)

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

    【讨论】:

      【解决方案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之前已经提到过

      【讨论】:

        【解决方案4】:

        我认为这就是OpacityMask 的用途。

        下面的示例似乎说明了您正在寻找的效果。背景是纯红色Rectangle。前景是纯蓝色RectangleText 对象,黑色文本位于蓝色前景之上。 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 确实是计算穿透层。还添加了一个动画来显示计算出的剪辑随时间变化。

        【讨论】:

        • 你实际测试过吗?它看起来不会产生所需的结果,而且您​​缺少 black 周围的“”。
        • 是的,我在qmlscene 中运行它,诚然来自5.8.0-beta,但在5.7 中应该没问题。至于缺少的引号,已修复...有趣的是,qmlscene 没有抱怨。
        • 它不会为我产生预期的结果。有一个巨大的蓝色矩形,里面有一个巨大的模糊的红色测试,但实际的背景并没有穿透。
        • 我为掩码修复了anchors.flll 的目标。现在,您将在蓝色前景的中心看到红色的小文本。由于文字是红色的,说明背景已经透了。
        • 它仍然不起作用 - 我得到一个带有红色文本的蓝色矩形,但我的背景实际上是灰色的。文字不透明,是红色的。
        猜你喜欢
        • 2022-11-15
        • 1970-01-01
        • 1970-01-01
        • 2011-12-17
        • 2018-11-26
        • 2016-07-11
        • 2011-06-02
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多