zoukankan      html  css  js  c++  java
  • 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 在CODE上查看代码片派生到我的代码片
    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.          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. 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 在CODE上查看代码片派生到我的代码片
    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.          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.              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.              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.              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.              160;  
    123.             color: "lightgray";  
    124.             border. 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.              160;  
    152.             color: "lightgray";  
    153.             border. 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.              160;  
    181.             color: "lightgray";  
    182.             border. 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 在CODE上查看代码片派生到我的代码片
    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.          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.              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.              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.              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.              160;  
    115.             color: "lightgray";  
    116.             border. 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.              160;  
    144.             color: "lightgray";  
    145.             border. 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.              160;  
    173.             color: "lightgray";  
    174.             border. 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.                 innershadow.color = shadowColor.color;  
    195.                 innershadow.fast = fast.checked;  
    196.                 innershadow.samples = sampleSlider.value;  
    197.                 innershadow.radius = parseFloat(radiusEdit.text);  
    198.                 innershadow.verticalOffset = voffEdit.text;  
    199.                 innershadow.horizontalOffset = hoffEdit.text;  
    200.                 innershadow.spread = spreadSlider.value;  
    201.             }  
    202.         }  
    203.     }  
    204. }  


        源码比较简单,不说了。

        InnerShadow 比 DropShadow 少了一个 transparentBorder 属性,其他基本一致,偷个懒,也不说了。

        回顾一下:

  • 相关阅读:
    表单元素
    Form表单、四种常见的POST请求提交数据方式、MIME
    html table
    jsop
    如何成为一名优秀的前端工程师
    CSS代码检查工具推荐:CSS Lint
    前端CSS规范整理
    使用渐进式 JPEG 来提升用户体验
    移动前端系列——移动页面性能优化(转)
    HTML5页面资源预加载(Link prefetch)功能加速页面加载速度
  • 原文地址:https://www.cnblogs.com/senior-engineer/p/5628807.html
Copyright © 2011-2022 走看看