Qt Quick提供了两种阴影效果:
下面是我设计的示例效果。
首先是 DropShadow :
图1 阴影效果
然后是内阴影效果:
图2 内阴影效果
如图1所示,界面被分为三部分。
最上面的是源图像。
源图像下面(即中间)是一个列表,你可以点击 DropShadow 和 InnerShadow 两个子项,切换不同的阴影效果。每种阴影效果都对应一个 qml 文档,当你点击这些子项时,对应的 qml 文档动态加载。
这个示例界面框架其实与“Qt Quick里的图形效果——颜色(Color)”是一致的,只是我把 ListView 从原来的竖向改为了横向。对应的 DropShadowExample.qml 内容如下:
import QtQuick 2.2 import QtQuick.Controls 1.2 Rectangle { id: example; signal back(); anchors.fill: parent; Text { id: origLabel; x: 10; y: 4; font.pointSize: 20; text: "Original Image"; } Button { anchors.right: parent.right; anchors.top: parent.top; anchors.margins: 4; text: "Back"; onClicked: example.back(); } Image { id: origImage; width: 240; height: 240; anchors.left: parent.left; anchors.top: origLabel.bottom; anchors.margins: 4; source: "butterfly.png"; sourceSize: Qt.size(240, 240); smooth: true; } Rectangle{ anchors.left: parent.left; anchors.leftMargin: 4; anchors.right: parent.right; anchors.rightMargin: 4; anchors.top: origImage.bottom; height: 2; border.width: 1; border.color: "darkgray"; } Text { id: effectsLabel; anchors.top: origImage.bottom; anchors.margins: 4; anchors.left: parent.left; font.pointSize: 20; font.bold: true; text: "Shadow Effects:"; color: "blue"; } Rectangle { id: shadowEffects; anchors.left: effectsLabel.right; anchors.leftMargin: 4; anchors.top: effectsLabel.top; anchors.right: parent.right; anchors.rightMargin: 4; height: 40; color: "gray"; ListView { anchors.fill: parent; clip: true; focus: true; orientation: ListView.Horizontal; spacing: 20; delegate: Text { id: wrapper; height: 40; verticalAlignment: Text.AlignVCenter; text: name; font.pointSize: 18; Keys.onEnterPressed: { event.accepted = true; effectControl.source = example; } Keys.onReturnPressed: { event.accepted = true; effectControl.source = example; } MouseArea { anchors.fill: parent; onClicked: { wrapper.ListView.view.currentIndex = index; effectControl.source = example; } } } highlight: Rectangle { height: parent.height; color: "lightblue"; } model: shadowsModel; } } Loader { id: effectControl; anchors.top: shadowEffects.bottom; anchors.left: parent.left; anchors.bottom: parent.bottom; anchors.right: parent.right; anchors.margins: 4; source: "DropShadowEx.qml"; } ListModel { id: shadowsModel; ListElement { name: "DropShadow"; example: "DropShadowEx.qml"; } ListElement { name: "InnerShadow"; example: "InnerShadowEx.qml"; } } }
阴影效果对应的 DropShadowEx.qml 内容如下:
import QtQuick 2.2 import QtGraphicalEffects 1.0 import QtQuick.Controls 1.2 Rectangle { anchors.fill: parent; Image { id: opImage; x: 4; y: 4; width: 250; height: 250; source: "butterfly.png"; sourceSize: Qt.size(250, 250); smooth: true; visible: false; } DropShadow { id: dropshadow; anchors.fill: opImage; source: opImage; } Rectangle { anchors.left: opImage.right; anchors.top: opImage.top; anchors.right: parent.right; anchors.bottom: parent.bottom; anchors.margins: 2; color: "lightsteelblue"; CheckBox { id: fast; anchors.top: parent.top; anchors.topMargin: 4; anchors.left: parent.left; anchors.leftMargin: 4; checked: false; text: "fast"; } CheckBox { id: transparentBorder; anchors.left: fast.right; anchors.leftMargin: 8; anchors.top: fast.top; checked: false; text: "transparentBorder"; } Text { id: colorLabel; anchors.left: fast.left; anchors.top: fast.bottom; anchors.topMargin: 8; text: "shadow color:"; } ColorPicker { id: shadowColor; anchors.left: colorLabel.right; anchors.leftMargin: 4; anchors.top: colorLabel.top; width: 90; height: 28; color: "#ff000000"; } Text { id: sampleLabel; anchors.left: fast.left; anchors.top: shadowColor.bottom; anchors.topMargin: 8; text: "samples:"; } Slider { id: sampleSlider; anchors.left: sampleLabel.right; anchors.leftMargin: 4; anchors.top: sampleLabel.top; minimumValue: 0; maximumValue: 32; value: 0.0; width: 160; height: 30; stepSize: 1.0; } Text { id: spreadLabel; anchors.left: fast.left; anchors.top: sampleSlider.bottom; anchors.topMargin: 8; text: "spread:"; } Slider { id: spreadSlider; anchors.left: spreadLabel.right; anchors.leftMargin: 4; anchors.top: spreadLabel.top; value: 0.5; width: 160; height: 30; } Text { id: radiusLabel; anchors.left: fast.left; anchors.top: spreadSlider.bottom; anchors.topMargin: 8; text: "radius:"; } Rectangle { id: radiusArea; anchors.left: radiusLabel.right; anchors.leftMargin: 4; anchors.top: radiusLabel.top; height: 30; width: 160; color: "lightgray"; border.width: 1; border.color: "darkgray"; TextInput { anchors.fill: parent; anchors.margins: 2; id: radiusEdit; font.pointSize: 18; text: "0.0"; validator: DoubleValidator{bottom: 0;} } } Text { id: voffLabel; anchors.left: fast.left; anchors.top: radiusArea.bottom; anchors.topMargin: 8; text: "verticalOffset:"; } Rectangle { id: voffArea; anchors.left: voffLabel.right; anchors.leftMargin: 4; anchors.top: voffLabel.top; height: 30; width: 160; color: "lightgray"; border.width: 1; border.color: "darkgray"; TextInput { anchors.fill: parent; anchors.margins: 2; id: voffEdit; font.pointSize: 18; text: "0.0"; validator: DoubleValidator{} } } Text { id: hoffLabel; anchors.left: fast.left; anchors.top: voffArea.bottom; anchors.topMargin: 8; text: "horizontalOffset:"; } Rectangle { id: hoffArea; anchors.left: hoffLabel.right; anchors.leftMargin: 4; anchors.top: hoffLabel.top; height: 30; width: 160; color: "lightgray"; border.width: 1; border.color: "darkgray"; TextInput { anchors.fill: parent; anchors.margins: 2; id: hoffEdit; font.pointSize: 18; text: "0.0"; validator: DoubleValidator{} } } Button { id: applyBtn; anchors.left: parent.left; anchors.leftMargin: 4; anchors.top: hoffArea.bottom; anchors.topMargin: 12; text: "Apply"; onClicked: { dropshadow.color = shadowColor.color; dropshadow.fast = fast.checked; dropshadow.transparentBorder = transparentBorder.checked; dropshadow.samples = sampleSlider.value; dropshadow.radius = parseFloat(radiusEdit.text); dropshadow.verticalOffset = voffEdit.text; dropshadow.horizontalOffset = hoffEdit.text; dropshadow.spread = spreadSlider.value; } } } }
未提及的属性都比较简单,想 cached 、 fast 、 transparentBorder 等,之前的文章也提到过。
内阴影效果对应的 InnerShadowEx.qml 内容如下:
import QtQuick 2.2 import QtGraphicalEffects 1.0 import QtQuick.Controls 1.2 Rectangle { anchors.fill: parent; Image { id: opImage; x: 4; y: 4; width: 250; height: 250; source: "butterfly.png"; sourceSize: Qt.size(250, 250); smooth: true; visible: false; } InnerShadow { id: innershadow; anchors.fill: opImage; source: opImage; } Rectangle { anchors.left: opImage.right; anchors.top: opImage.top; anchors.right: parent.right; anchors.bottom: parent.bottom; anchors.margins: 2; color: "lightsteelblue"; CheckBox { id: fast; anchors.top: parent.top; anchors.topMargin: 4; anchors.left: parent.left; anchors.leftMargin: 4; checked: false; text: "fast"; } Text { id: colorLabel; anchors.left: fast.left; anchors.top: fast.bottom; anchors.topMargin: 8; text: "shadow color:"; } ColorPicker { id: shadowColor; anchors.left: colorLabel.right; anchors.leftMargin: 4; anchors.top: colorLabel.top; width: 90; height: 28; color: "#ff000000"; } Text { id: sampleLabel; anchors.left: fast.left; anchors.top: shadowColor.bottom; anchors.topMargin: 8; text: "samples:"; } Slider { id: sampleSlider; anchors.left: sampleLabel.right; anchors.leftMargin: 4; anchors.top: sampleLabel.top; minimumValue: 0; maximumValue: 32; value: 0.0; width: 160; height: 30; stepSize: 1.0; } Text { id: spreadLabel; anchors.left: fast.left; anchors.top: sampleSlider.bottom; anchors.topMargin: 8; text: "spread:"; } Slider { id: spreadSlider; anchors.left: spreadLabel.right; anchors.leftMargin: 4; anchors.top: spreadLabel.top; value: 0.5; width: 160; height: 30; } Text { id: radiusLabel; anchors.left: fast.left; anchors.top: spreadSlider.bottom; anchors.topMargin: 8; text: "radius:"; } Rectangle { id: radiusArea; anchors.left: radiusLabel.right; anchors.leftMargin: 4; anchors.top: radiusLabel.top; height: 30; width: 160; color: "lightgray"; border.width: 1; border.color: "darkgray"; TextInput { anchors.fill: parent; anchors.margins: 2; id: radiusEdit; font.pointSize: 18; text: "0.0"; validator: DoubleValidator{bottom: 0;} } } Text { id: voffLabel; anchors.left: fast.left; anchors.top: radiusArea.bottom; anchors.topMargin: 8; text: "verticalOffset:"; } Rectangle { id: voffArea; anchors.left: voffLabel.right; anchors.leftMargin: 4; anchors.top: voffLabel.top; height: 30; width: 160; color: "lightgray"; border.width: 1; border.color: "darkgray"; TextInput { anchors.fill: parent; anchors.margins: 2; id: voffEdit; font.pointSize: 18; text: "0.0"; validator: DoubleValidator{} } } Text { id: hoffLabel; anchors.left: fast.left; anchors.top: voffArea.bottom; anchors.topMargin: 8; text: "verticalOffset:"; } Rectangle { id: hoffArea; anchors.left: hoffLabel.right; anchors.leftMargin: 4; anchors.top: hoffLabel.top; height: 30; width: 160; color: "lightgray"; border.width: 1; border.color: "darkgray"; TextInput { anchors.fill: parent; anchors.margins: 2; id: hoffEdit; font.pointSize: 18; text: "0.0"; validator: DoubleValidator{} } } Button { id: applyBtn; anchors.left: parent.left; anchors.leftMargin: 4; anchors.top: hoffArea.bottom; anchors.topMargin: 12; text: "Apply"; onClicked: { innershadow.color = shadowColor.color; innershadow.fast = fast.checked; innershadow.samples = sampleSlider.value; innershadow.radius = parseFloat(radiusEdit.text); innershadow.verticalOffset = voffEdit.text; innershadow.horizontalOffset = hoffEdit.text; innershadow.spread = spreadSlider.value; } } } }
InnerShadow 比 DropShadow 少了一个 transparentBorder 属性,其他基本一致,偷个懒,也不说了。
回顾一下: