Qt Quick里的图形效果:阴影(Drop Shadow)

Posted maxiongying

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Qt Quick里的图形效果:阴影(Drop Shadow)相关的知识,希望对你有一定的参考价值。

Qt Quick提供了两种阴影效果:

  • DropShow,阴影。这个元素会根据源图像,产生一个彩色的、模糊的新图像,把这个新图像放在源图像后面,给人一种源图像从背景上凸出来的效果。
  • InnerShadow,内阴影。这个元素会根据源图像,产生一个彩色的、模糊的新图像,与 DropShadow不同的是,新图像会放在源图像里面。

效果

    下面是我设计的示例效果。

    首先是 DropShadow :

技术分享

                       图1 阴影效果

    然后是内阴影效果:

技术分享

                    图2 内阴影效果

源码分析

    如图1所示,界面被分为三部分。

    最上面的是源图像。

    源图像下面(即中间)是一个列表,你可以点击 DropShadow 和 InnerShadow 两个子项,切换不同的阴影效果。每种阴影效果都对应一个 qml 文档,当你点击这些子项时,对应的 qml 文档动态加载。

阴影示例界面

    这个示例界面框架其实与“Qt Quick里的图形效果——颜色(Color)”是一致的,只是我把 ListView 从原来的竖向改为了横向。对应的 DropShadowExample.qml 内容如下:

[javascript] view plain copy 技术分享技术分享
  1. import QtQuick 2.2  
  2. import QtQuick.Controls 1.2  
  3.   
  4. Rectangle {  
  5.     id: example;  
  6.     signal back();  
  7.     anchors.fill: parent;  
  8.   
  9.     Text {  
  10.         id: origLabel;  
  11.         x: 10;  
  12.         y: 4;  
  13.         font.pointSize: 20;  
  14.         text: "Original Image";  
  15.     }  
  16.   
  17.     Button {  
  18.         anchors.right: parent.right;  
  19.         anchors.top: parent.top;  
  20.         anchors.margins: 4;  
  21.         text: "Back";  
  22.         onClicked: example.back();  
  23.     }  
  24.   
  25.   
  26.     Image {  
  27.         id: origImage;  
  28.         width: 240;  
  29.         height: 240;  
  30.         anchors.left: parent.left;  
  31.         anchors.top: origLabel.bottom;  
  32.         anchors.margins: 4;  
  33.         source: "butterfly.png";  
  34.         sourceSize: Qt.size(240, 240);  
  35.         smooth: true;  
  36.     }  
  37.   
  38.     Rectangle{  
  39.         anchors.left: parent.left;  
  40.         anchors.leftMargin: 4;  
  41.         anchors.right: parent.right;  
  42.         anchors.rightMargin: 4;  
  43.         anchors.top: origImage.bottom;  
  44.         height: 2;  
  45.         border.width: 1;  
  46.         border.color: "darkgray";  
  47.     }  
  48.   
  49.     Text {  
  50.         id: effectsLabel;  
  51.         anchors.top: origImage.bottom;  
  52.         anchors.margins: 4;  
  53.         anchors.left: parent.left;  
  54.         font.pointSize: 20;  
  55.         font.bold: true;  
  56.         text: "Shadow Effects:";  
  57.         color: "blue";  
  58.     }  
  59.   
  60.     Rectangle {  
  61.         id: shadowEffects;  
  62.         anchors.left: effectsLabel.right;  
  63.         anchors.leftMargin: 4;  
  64.         anchors.top: effectsLabel.top;  
  65.         anchors.right: parent.right;  
  66.         anchors.rightMargin: 4;  
  67.         height: 40;  
  68.         color: "gray";  
  69.   
  70.         ListView {  
  71.             anchors.fill: parent;  
  72.             clip: true;  
  73.             focus: true;  
  74.             orientation: ListView.Horizontal;  
  75.             spacing: 20;  
  76.             delegate: Text {  
  77.                 id: wrapper;  
  78.                 height: 40;  
  79.                 verticalAlignment: Text.AlignVCenter;  
  80.                 text: name;  
  81.                 font.pointSize: 18;  
  82.                 Keys.onEnterPressed: {  
  83.                     event.accepted = true;  
  84.                     effectControl.source = example;  
  85.                 }  
  86.   
  87.                 Keys.onReturnPressed: {  
  88.                     event.accepted = true;  
  89.                     effectControl.source = example;  
  90.                 }  
  91.   
  92.                 MouseArea {  
  93.                     anchors.fill: parent;  
  94.                     onClicked: {  
  95.                         wrapper.ListView.view.currentIndex = index;  
  96.                         effectControl.source = example;  
  97.                     }  
  98.                 }  
  99.             }  
  100.             highlight: Rectangle {  
  101.                 height: parent.height;  
  102.                 color: "lightblue";  
  103.             }  
  104.   
  105.             model: shadowsModel;  
  106.         }  
  107.     }  
  108.   
  109.     Loader {  
  110.         id: effectControl;  
  111.         anchors.top: shadowEffects.bottom;  
  112.         anchors.left: parent.left;  
  113.         anchors.bottom: parent.bottom;  
  114.         anchors.right: parent.right;  
  115.         anchors.margins: 4;  
  116.         source: "DropShadowEx.qml";  
  117.     }  
  118.   
  119.     ListModel {  
  120.         id: shadowsModel;  
  121.         ListElement {  
  122.             name: "DropShadow";  
  123.             example: "DropShadowEx.qml";  
  124.         }  
  125.         ListElement {  
  126.             name: "InnerShadow";  
  127.             example: "InnerShadowEx.qml";  
  128.         }  
  129.     }  
  130. }  


    DropShawExample.qml 会被“Qt Quick里的图形效果(Graphical Effects)”里介绍过的 main.qml 动态加载。

阴影效果

    阴影效果对应的 DropShadowEx.qml 内容如下:

[javascript] view plain copy 技术分享技术分享
  1. import QtQuick 2.2  
  2. import QtGraphicalEffects 1.0  
  3. import QtQuick.Controls 1.2  
  4.   
  5. Rectangle {  
  6.     anchors.fill: parent;  
  7.     Image {  
  8.         id: opImage;  
  9.         x: 4;  
  10.         y: 4;  
  11.         width: 250;  
  12.         height: 250;  
  13.         source: "butterfly.png";  
  14.         sourceSize: Qt.size(250, 250);  
  15.         smooth: true;  
  16.         visible: false;  
  17.     }  
  18.   
  19.     DropShadow {  
  20.         id: dropshadow;  
  21.         anchors.fill: opImage;  
  22.         source: opImage;  
  23.     }  
  24.   
  25.     Rectangle {  
  26.         anchors.left: opImage.right;  
  27.         anchors.top: opImage.top;  
  28.         anchors.right: parent.right;  
  29.         anchors.bottom: parent.bottom;  
  30.         anchors.margins: 2;  
  31.         color: "lightsteelblue";  
  32.   
  33.         CheckBox {  
  34.             id: fast;  
  35.             anchors.top: parent.top;  
  36.             anchors.topMargin: 4;  
  37.             anchors.left: parent.left;  
  38.             anchors.leftMargin: 4;  
  39.             checked: false;  
  40.             text: "fast";  
  41.         }  
  42.         CheckBox {  
  43.             id: transparentBorder;  
  44.             anchors.left: fast.right;  
  45.             anchors.leftMargin: 8;  
  46.             anchors.top: fast.top;  
  47.             checked: false;  
  48.             text: "transparentBorder";  
  49.         }  
  50.   
  51.         Text {  
  52.             id: colorLabel;  
  53.             anchors.left: fast.left;  
  54.             anchors.top: fast.bottom;  
  55.             anchors.topMargin: 8;  
  56.             text: "shadow color:";  
  57.         }  
  58.   
  59.         ColorPicker {  
  60.             id: shadowColor;  
  61.             anchors.left: colorLabel.right;  
  62.             anchors.leftMargin: 4;  
  63.             anchors.top: colorLabel.top;  
  64.             width: 90;  
  65.             height: 28;  
  66.             color: "#ff000000";  
  67.         }  
  68.   
  69.         Text {  
  70.             id: sampleLabel;  
  71.             anchors.left: fast.left;  
  72.             anchors.top: shadowColor.bottom;  
  73.             anchors.topMargin: 8;  
  74.             text: "samples:";  
  75.         }  
  76.   
  77.         Slider {  
  78.             id: sampleSlider;  
  79.             anchors.left: sampleLabel.right;  
  80.             anchors.leftMargin: 4;  
  81.             anchors.top: sampleLabel.top;  
  82.             minimumValue: 0;  
  83.             maximumValue: 32;  
  84.             value: 0.0;  
  85.             width: 160;  
  86.             height: 30;  
  87.             stepSize: 1.0;  
  88.         }  
  89.   
  90.         Text {  
  91.             id: spreadLabel;  
  92.             anchors.left: fast.left;  
  93.             anchors.top: sampleSlider.bottom;  
  94.             anchors.topMargin: 8;  
  95.             text: "spread:";  
  96.         }  
  97.   
  98.         Slider {  
  99.             id: spreadSlider;  
  100.             anchors.left: spreadLabel.right;  
  101.             anchors.leftMargin: 4;  
  102.             anchors.top: spreadLabel.top;  
  103.             value: 0.5;  
  104.             width: 160;  
  105.             height: 30;  
  106.         }  
  107.   
  108.         Text {  
  109.             id: radiusLabel;  
  110.             anchors.left: fast.left;  
  111.             anchors.top: spreadSlider.bottom;  
  112.             anchors.topMargin: 8;  
  113.             text: "radius:";  
  114.         }  
  115.   
  116.         Rectangle {  
  117.             id: radiusArea;  
  118.             anchors.left: radiusLabel.right;  
  119.             anchors.leftMargin: 4;  
  120.             anchors.top: radiusLabel.top;  
  121.             height: 30;  
  122.             width: 160;  
  123.             color: "lightgray";  
  124.             border.width: 1;  
  125.             border.color: "darkgray";  
  126.             TextInput {  
  127.                 anchors.fill: parent;  
  128.                 anchors.margins: 2;  
  129.                 id: radiusEdit;  
  130.                 font.pointSize: 18;  
  131.                 text: "0.0";  
  132.                 validator: DoubleValidator{bottom: 0;}  
  133.             }  
  134.         }  
  135.   
  136.   
  137.         Text {  
  138.             id: voffLabel;  
  139.             anchors.left: fast.left;  
  140.             anchors.top: radiusArea.bottom;  
  141.             anchors.topMargin: 8;  
  142.             text: "verticalOffset:";  
  143.         }  
  144.   
  145.         Rectangle {  
  146.             id: voffArea;  
  147.             anchors.left: voffLabel.right;  
  148.             anchors.leftMargin: 4;  
  149.             anchors.top: voffLabel.top;  
  150.             height: 30;  
  151.             width: 160;  
  152.             color: "lightgray";  
  153.             border.width: 1;  
  154.             border.color: "darkgray";  
  155.             TextInput {  
  156.                 anchors.fill: parent;  
  157.                 anchors.margins: 2;  
  158.                 id: voffEdit;  
  159.                 font.pointSize: 18;  
  160.                 text: "0.0";  
  161.                 validator: DoubleValidator{}  
  162.             }  
  163.         }  
  164.   
  165.   
  166.         Text {  
  167.             id: hoffLabel;  
  168.             anchors.left: fast.left;  
  169.             anchors.top: voffArea.bottom;  
  170.             anchors.topMargin: 8;  
  171.             text: "horizontalOffset:";  
  172.         }  
  173.   
  174.         Rectangle {  
  175.             id: hoffArea;  
  176.             anchors.left: hoffLabel.right;  
  177.             anchors.leftMargin: 4;  
  178.             anchors.top: hoffLabel.top;  
  179.             height: 30;  
  180.             width: 160;  
  181.             color: "lightgray";  
  182.             border.width: 1;  
  183.             border.color: "darkgray";  
  184.             TextInput {  
  185.                 anchors.fill: parent;  
  186.                 anchors.margins: 2;  
  187.                 id: hoffEdit;  
  188.                 font.pointSize: 18;  
  189.                 text: "0.0";  
  190.                 validator: DoubleValidator{}  
  191.             }  
  192.         }  
  193.   
  194.         Button {  
  195.             id: applyBtn;  
  196.             anchors.left: parent.left;  
  197.             anchors.leftMargin: 4;  
  198.             anchors.top: hoffArea.bottom;  
  199.             anchors.topMargin: 12;  
  200.             text: "Apply";  
  201.             onClicked: {  
  202.                 dropshadow.color = shadowColor.color;  
  203.                 dropshadow.fast = fast.checked;  
  204.                 dropshadow.transparentBorder = transparentBorder.checked;  
  205.                 dropshadow.samples = sampleSlider.value;  
  206.                 dropshadow.radius = parseFloat(radiusEdit.text);  
  207.                 dropshadow.verticalOffset = voffEdit.text;  
  208.                 dropshadow.horizontalOffset = hoffEdit.text;  
  209.                 dropshadow.spread = spreadSlider.value;  
  210.             }  
  211.         }  
  212.     }  
  213. }  


    代码比较简单,不细说了。我们看看 DropShadow 元素的各个属性都什么含义吧。

  • source,variant类型,指向源Item
  • horizontalOffset 与verticalOffset,real类型,指定阴影相对于源Item的水平和垂直偏移量,默认为 0 
  • radius,real类型,设置阴影的柔和程度,值越大,阴影的边缘就会显得越柔和
  • sample,int类型,指定生成阴影时阴影的每个像素由多少个采样点产生,采样点越多阴影效果越好,不过也越慢。一般可以把这个值设置为 radius的2倍。
  • spread,real类型,指定如何强化阴影接近源 Item 边缘的部分,取值范围为 0.0 -- 1.0 ,默认为 0.5

    未提及的属性都比较简单,想 cached 、 fast 、 transparentBorder 等,之前的文章也提到过。

内阴影

    内阴影效果对应的 InnerShadowEx.qml 内容如下:

[javascript] view plain copy 技术分享技术分享
  1. import QtQuick 2.2  
  2. import QtGraphicalEffects 1.0  
  3. import QtQuick.Controls 1.2  
  4.   
  5. Rectangle {  
  6.     anchors.fill: parent;  
  7.     Image {  
  8.         id: opImage;  
  9.         x: 4;  
  10.         y: 4;  
  11.         width: 250;  
  12.         height: 250;  
  13.         source: "butterfly.png";  
  14.         sourceSize: Qt.size(250, 250);  
  15.         smooth: true;  
  16.         visible: false;  
  17.     }  
  18.   
  19.     InnerShadow {  
  20.         id: innershadow;  
  21.         anchors.fill: opImage;  
  22.         source: opImage;  
  23.     }  
  24.   
  25.     Rectangle {  
  26.         anchors.left: opImage.right;  
  27.         anchors.top: opImage.top;  
  28.         anchors.right: parent.right;  
  29.         anchors.bottom: parent.bottom;  
  30.         anchors.margins: 2;  
  31.         color: "lightsteelblue";  
  32.   
  33.         CheckBox {  
  34.             id: fast;  
  35.             anchors.top: parent.top;  
  36.             anchors.topMargin: 4;  
  37.             anchors.left: parent.left;  
  38.             anchors.leftMargin: 4;  
  39.             checked: false;  
  40.             text: "fast";  
  41.         }  
  42.   
  43.         Text {  
  44.             id: colorLabel;  
  45.             anchors.left: fast.left;  
  46.             anchors.top: fast.bottom;  
  47.             anchors.topMargin: 8;  
  48.             text: "shadow color:";  
  49.         }  
  50.   
  51.         ColorPicker {  
  52.             id: shadowColor;  
  53.             anchors.left: colorLabel.right;  
  54.             anchors.leftMargin: 4;  
  55.             anchors.top: colorLabel.top;  
  56.             width: 90;  
  57.             height: 28;  
  58.             color: "#ff000000";  
  59.         }  
  60.   
  61.         Text {  
  62.             id: sampleLabel;  
  63.             anchors.left: fast.left;  
  64.             anchors.top: shadowColor.bottom;  
  65.             anchors.topMargin: 8;  
  66.             text: "samples:";  
  67.         }  
  68.   
  69.         Slider {  
  70.             id: sampleSlider;  
  71.             anchors.left: sampleLabel.right;  
  72.             anchors.leftMargin: 4;  
  73.             anchors.top: sampleLabel.top;  
  74.             minimumValue: 0;  
  75.             maximumValue: 32;  
  76.             value: 0.0;  
  77.             width: 160;  
  78.             height: 30;  
  79.             stepSize: 1.0;  
  80.         }  
  81.   
  82.         Text {  
  83.             id: spreadLabel;  
  84.             anchors.left: fast.left;  
  85.             anchors.top: sampleSlider.bottom;  
  86.             anchors.topMargin: 8;  
  87.             text: "spread:";  
  88.         }  
  89.   
  90.         Slider {  
  91.             id: spreadSlider;  
  92.             anchors.left: spreadLabel.right;  
  93.             anchors.leftMargin: 4;  
  94.             anchors.top: spreadLabel.top;  
  95.             value: 0.5;  
  96.             width: 160;  
  97.             height: 30;  
  98.         }  
  99.   
  100.         Text {  
  101.             id: radiusLabel;  
  102.             anchors.left: fast.left;  
  103.             anchors.top: spreadSlider.bottom;  
  104.             anchors.topMargin: 8;  
  105.             text: "radius:";  
  106.         }  
  107.   
  108.         Rectangle {  
  109.             id: radiusArea;  
  110.             anchors.left: radiusLabel.right;  
  111.             anchors.leftMargin: 4;  
  112.             anchors.top: radiusLabel.top;  
  113.             height: 30;  
  114.             width: 160;  
  115.             color: "lightgray";  
  116.             border.width: 1;  
  117.             border.color: "darkgray";  
  118.             TextInput {  
  119.                 anchors.fill: parent;  
  120.                 anchors.margins: 2;  
  121.                 id: radiusEdit;  
  122.                 font.pointSize: 18;  
  123.                 text: "0.0";  
  124.                 validator: DoubleValidator{bottom: 0;}  
  125.             }  
  126.         }  
  127.   
  128.   
  129.         Text {  
  130.             id: voffLabel;  
  131.             anchors.left: fast.left;  
  132.             anchors.top: radiusArea.bottom;  
  133.             anchors.topMargin: 8;  
  134.             text: "verticalOffset:";  
  135.         }  
  136.   
  137.         Rectangle {  
  138.             id: voffArea;  
  139.             anchors.left: voffLabel.right;  
  140.             anchors.leftMargin: 4;  
  141.             anchors.top: voffLabel.top;  
  142.             height: 30;  
  143.             width: 160;  
  144.             color: "lightgray";  
  145.             border.width: 1;  
  146.             border.color: "darkgray";  
  147.             TextInput {  
  148.                 anchors.fill: parent;  
  149.                 anchors.margins: 2;  
  150.                 id: voffEdit;  
  151.                 font.pointSize: 18;  
  152.                 text: "0.0";  
  153.                 validator: DoubleValidator{}  
  154.             }  
  155.         }  
  156.   
  157.   
  158.         Text {  
  159.             id: hoffLabel;  
  160.             anchors.left: fast.left;  
  161.             anchors.top: voffArea.bottom;  
  162.             anchors.topMargin: 8;  
  163.             text: "verticalOffset:";  
  164.         }  
  165.   
  166.         Rectangle {  
  167.             id: hoffArea;  
  168.             anchors.left: hoffLabel.right;  
  169.             anchors.leftMargin: 4;  
  170.             anchors.top: hoffLabel.top;  
  171.             height: 30;  
  172.             width: 160;  
  173.             color: "lightgray";  
  174.             border.width: 1;  
  175.             border.color: "darkgray";  
  176.             TextInput {  
  177.                 anchors.fill: parent;  
  178.                 anchors.margins: 2;  
  179.                 id: hoffEdit;  
  180.                 font.pointSize: 18;  
  181.                 text: "0.0";  
  182.                 validator: DoubleValidator{}  
  183.             }  
  184.         }  
  185.   
  186.         Button {  
  187.             id: applyBtn;  
  188.             anchors.left: parent.left;  
  189.             anchors.leftMargin: 4;  
  190.             anchors.top: hoffArea.bottom;  
  191.             anchors.topMargin: 12;  
  192.             text: "Apply";  
  193.             onClicked: {  
  194.              &nbs

以上是关于Qt Quick里的图形效果:阴影(Drop Shadow)的主要内容,如果未能解决你的问题,请参考以下文章

组织孩子的 Qt Quick2 自定义控件

SwiftUI4.0在iOS 16中新添加的inner和drop阴影效果

SwiftUI4.0在iOS 16中新添加的inner和drop阴影效果

CSS 奇技淫巧 | 妙用 drop-shadow 实现线条光影效果

Java 为 PPT 中的图形添加阴影效果

Qt Quick