2016-10-06 40 views
4

我试图去寻找的外观和感觉是有一个纯色按钮,其上的文本就像“Hello World”,文本是完全透明的,背景通过按钮显示。如何将不透明度蒙版应用于QML项目?

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

+0

这是一个完全自定义按钮控制?或者你使用Qt Quick Controls还是类似的? – peppe

+0

Qt快速控制1或2? – GrecKo

回答

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真的计算过层切割。还添加了一个动画,以显示随时间变化的计算切分。

+0

你真的测试过吗?它看起来不会产生所需的结果,再加上你错过了黑色周围的“”。 – dtech

+0

是的,我在'qmlscene'中运行它,当然是从'5.8.0-beta'中运行,但是它应该在5.7中运行。至于缺失的引号,修正它......有趣的是,'qmlscene'没有抱怨。 – Tim

+0

它不会为我产生预期的结果。有一个巨大的蓝色矩形,里面有一个巨大的模糊红色测试,但实际的背景不会播种。 – dtech

5

下面是做到这一点的一种方法:

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

结果:

enter image description here

按钮是红色的,文字是灰色的灰色背景,它会准确显示按钮下方的任何内容。

显然,该按钮是基本的,但这个例子不足以让你按照你的需要去实现某些东西。

这里的关键元素是自定义着色器,它是一个非常基本的着色器 - 它将每个片段着色并将掩码应用为alpha。显然,您可以使用ShaderEffectSource将任何QML项目转换为纹理,并将ShaderEffectSource替换为另一个sampler 2D,并以任何您想要的方式混合使用这两种纹理,使用Alpha通道进行剪切,或者在使用灰度时使用任何RGB面具。而且不同于相当有限的OpacityMask元素,它实际上会切入并显示任何在其下面的东西,因为它应该是。

+0

不错的解决方案:) – Tim

3

你想要的是一个OpacityMask可以倒置。 这在未来的Qt释放计划(5.7.1也许?),实际上你已经可以看看它:https://github.com/qt/qtgraphicaleffects/blob/5.7.1/src/effects/OpacityMask.qml

同时,你可以在一个名为MyOpacityMask.qml文件或其他东西,并使用代码复制这种方式从Qt Quick的一个Button控制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 for 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; 
       } 
      " 
    } 
} 
相关问题