【问题标题】:QML Inner Shadow effectQML 内阴影效果
【发布时间】:2015-06-13 14:02:27
【问题描述】:

我想在QML 中创建一个带有内阴影的矩形,类似于Photoshop 所做的:

QMLInnerShadow 但我无法达到这个效果。我得到的最接近的是这个

import QtQuick 2.0
import QtGraphicalEffects 1.0

Item {
    id: root
    width: 300
    height: 300

    Rectangle {
        id: myRectangle
        anchors.centerIn: parent
        width: 100
        height: 100
        color: "grey"
    }

    InnerShadow {
        anchors.fill: root
        cached: true
        horizontalOffset: 0
        verticalOffset: 0
        radius: 16
        samples: 32
        color: "#b0000000"
        smooth: true
        source: root
    }
}

这是我从this 帖子中得到的一个想法。但是,此示例仅在 root 的大小明显大于 myRectangle 时才有效,而我不希望这样。我需要例如一个200x10 正方形,其中阴影均匀分布在矩形的边缘。我尝试了InnerShadow 属性的各种值,但我什至无法达到我想要的效果。

这可以使用QML 实现吗?

【问题讨论】:

  • 看起来 QML 的内部阴影实现很蹩脚,我的猜测是“由图形设计背景为零的程序员完成”。您可以尝试使用自定义 GLSL 着色器来实现效果。
  • 您只需要两个像素的偏移量即可获得正确的内阴影,这不是“明显更大”但肯定很难看。将它与根的颜色结合起来不起作用?如果没有,着色器是你唯一的朋友。
  • 我用一张照片重复一遍,因为你没有回答我之前的建议。 something like this呢?
  • @BaCaRoZzo 您是如何实现这种效果的?我使用了horizontalOffset: 1; verticalOffset: 1,这就是我所取得的成果:i.imgur.com/ltPZT9r.png,这不如你的结果。可以出示一下代码吗?
  • 已编写解决方案。看看它是否符合您的需求。

标签: c++ qt qml qt-quick qtquick2


【解决方案1】:

“正确”的做法——需要引号——使用效果应该是这样的:

import QtQuick 2.0
import QtGraphicalEffects 1.0

Item {
   id: root
   width: 300
   height: 300

   Item {
       id: src
       anchors.fill: parent

       Rectangle {
           id: myRectangle
           anchors.centerIn: parent
           width: 100
           height: 100
           color: "grey"
       }
   }

   InnerShadow {
       anchors.fill: src
       cached: true
       horizontalOffset: 0
       verticalOffset: 0
       radius: 16
       samples: 32
       color: "#b0000000"
       smooth: true
       source: src
   }
}

如您所见,它与另一个问题中提出的解决方案略有不同。使用此代码,您仍然需要保留 2 个像素才能产生效果,从而产生白色边框(或任何背景颜色)。通过将root 更改为Rectangle,可以轻松解决此问题。

最终示例解决方案如下。显然,您可以提取 root 组件(和相关的子组件)并将其放在 Component 或不同的 .qml 文件中以供以后使用。

import QtQuick 2.4
import QtQuick.Window 2.2
import QtGraphicalEffects 1.0

Window {
    width: 200
    height: 20
    visible: true

    Rectangle {     // was Item
        id: root
        anchors.fill: parent
        color: "grey"


        Item {
            id: src
            anchors.fill: parent

            Rectangle {
                id: myRectangle
                anchors.centerIn: parent
                width: root.width - 2
                height: root.height - 2
                color: "lightgrey"
            }
        }

        InnerShadow {
            anchors.fill: src
            cached: true
            horizontalOffset: 0
            verticalOffset: 0
            radius: 16
            samples: 32
            color: "#b0000000"
            smooth: true
            source: src
        }
    }
}

最终代码示例的结果窗口:

【讨论】:

  • 似乎实现不合逻辑。如果源是 myRectangle,它不适用于偏移量 0,但如果添加偏移量,它会神秘地出现。所以你必须使用“代理”项目。如果您尝试做一些更复杂的事情,例如将其应用于“复合”项目,它看起来会变得越来越尴尬。
  • 从来没有说过我喜欢它...事实上我把臭名昭著的引号放在“正确”周围。原始代码被提议作为在邮件列表讨论中使用效果的方式。您可以在其他问题 cmets 中找到链接。实现必须是不合逻辑的以促进这种奇怪的用法。但是,你知道,尽管它不合逻辑,但我们仍然应该找到一种方法。 :)
  • 我更喜欢“预期行为”。这将是一个实施的情况,由知道如何使用 Photoshop 的人完成。不幸的是,在 Qt 中,开发被高度划分,导致 API 中出现许多不“完全与编程有关”的奇怪现象。
  • @BaCaRoZzo 是否不合逻辑,它有效。直到 Qt 人员修复 InnerShadow(因为我不认为当前的行为是正确的)我认为没有更好的解决方案。这个解决方案不应该让 Qt 人员或社区远离修复它......非常感谢!
【解决方案2】:

InnerShadow 元素就像 QML 中的大多数 Graphics Effects 元素一样,是一个 GLSL 着色器,它找到边缘的方式是寻找透明和非透明之间的过渡。如果您将过滤器应用于完全实体的图形元素,它将找不到任何边缘,因此也没有阴影。这与 Photoshop 滤镜的工作方式完全相同,它还通过扫描从透明到不透明的边缘来找到边缘(如您提供的示例中所示)。它可以将图形区域的边缘视为隐式边缘,但这会极大地限制可用性。这是InnerShadow 的来源。根据快速属性,它再次使用FastInnerShadowGaussianInnerShadow

如果您想要一个可以添加到现有元素的实现,而不必关心透明和非透明边缘之间的过渡,您可以使用这个:

Rectangle {
    id: myRectangle
    anchors.centerIn: parent
    width: 300
    height: 300
    color: "#AAAAAA"
}
Item {
    id: _innerShadow
    property var shadowSource: myRectangle
    property var color: "#B0000000"
    anchors.fill: shadowSource
    Item {
        id: _shadowMarker
        //width: source.width+1; height: source.height+1
        anchors.fill: parent;
        anchors.margins: -10
        ColorOverlay {
            anchors.fill: _shadowMarker;
            anchors.margins: 10
            source: _innerShadow.shadowSource
            color: "#00000000"
        }
        visible: false
    }
    InnerShadow {
        anchors.fill: _shadowMarker
        cached: true
        horizontalOffset: 0
        verticalOffset: 0
        radius: 16
        samples: 32
        color: _innerShadow.color
        smooth: true
        source: _shadowMarker
    }
}

【讨论】:

    【解决方案3】:

    这是我的解决方案

    GoodInnerShadow.qml

    ///
    /// Same as InnerShadow QML type, with the following differences
    ///
    /// InnerShadow requires transparent space to be surrounding the 
    /// item that you want to make an inner shadow for. GoodInnerShadow
    /// does not require this.
    ///
    /// InnerShadow draws the source with the shadow. GoodInnerShadow 
    /// draws just the shadow
    ///
    import QtQuick 2.15
    import QtGraphicalEffects 1.0
    
    Item {
        id: root
    
        anchors.centerIn: source
        width: source.width
        height: source.height
        required property var source
        property color color: "#50ffffff"
        property double radius: 12
        property double spread: .8
    
        Item{
            id: sourceMaskWithPadding
            visible: false
    
            anchors.centerIn: parent
            width: root.source.width + shadowOfInverse.samples * 2
            height: root.source.height + shadowOfInverse.samples * 2
            OpacityMask {
                id: sourceMask
                anchors.centerIn: parent
                width: root.source.width
                height: root.source.height
                maskSource: root.source
                source: root.source
            }
        }
        
        Rectangle {
            id: coloredRect
            visible: false
    
            color: root.color
            anchors.fill: sourceMaskWithPadding
        }
    
        OpacityMask {
            id: sourceInverse
            visible: false
    
            anchors.fill: coloredRect
            source: coloredRect
            maskSource: sourceMaskWithPadding
            invert: true
        }
    
        DropShadow {
            id: shadowOfInverse
            visible: false
            
            anchors.fill: sourceInverse
            source: sourceInverse
            radius: root.radius
            samples: radius * 2 + 1
            color: root.color
            spread: root.spread
        }
        
        OpacityMask {
            id: sourceInnerShadow
            anchors.fill: sourceMaskWithPadding
            maskSource: sourceMaskWithPadding
            source: shadowOfInverse
        }
    
    }
    
    

    示例用法

    import QtQuick 2.15
    
    Item {
        width: 400
        height: 300
    
        Rectangle {
            id: myRect
            anchors.centerIn: parent
            width: 300
            height: 100
            color: "lightgray"
        }
    
        GoodInnerShadow {
            source: myRect
            color: "#aa000000"
            spread: .5
            radius: 16
        }
    }
    
    

    结果

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-06-01
      • 2011-05-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-14
      相关资源
      最近更新 更多