Qt Quick提供了兩種陰影效果:
- DropShow,陰影。這個元素會根據源圖像,産生一個彩色的、模糊的新圖像,把這個新圖像放在源圖像後面,給人一種源圖像從背景上凸出來的效果。
- InnerShadow,内陰影。這個元素會根據源圖像,産生一個彩色的、模糊的新圖像,與 DropShadow不同的是,新圖像會放在源圖像裡面。
效果
下面是我設計的示例效果。
首先是 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";
}
}
}
DropShawExample.qml 會被“ Qt Quick裡的圖形效果(Graphical Effects)”裡介紹過的 main.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;
}
}
}
}
代碼比較簡單,不細說了。我們看看 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 内容如下:
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 屬性,其他基本一緻,偷個懶,也不說了。
回顧一下: