Qt Quick裡的圖形效果:陰影(Drop Shadow),quickdrop
Qt Quick提供了兩種陰影製作效果:
- DropShow,陰影。這個元素會根據源映像,產生一個彩色的、模糊的新映像,把這個新映像放在源映像後面,給人一種源映像從背景上凸出來的效果。
- InnerShadow,內陰影。這個元素會根據源映像,產生一個彩色的、模糊的新映像,與 DropShadow不同的是,新映像會放在源映像裡面。
效果
下面是我設計的樣本效果。
首先是 DropShadow :
圖1 陰影製作效果
然後是內陰影製作效果:
圖2 內陰影製作效果
源碼分析
1所示,介面被分為三部分。
最上面的是源映像。
源映像下面(即中間)是一個列表,你可以點擊 DropShadow 和 InnerShadow 兩個子項,切換不同的陰影製作效果。每種陰影製作效果都對應一個 qml 文檔,當你點擊這些子項時,對應的 qml 文檔動態載入。
陰影樣本介面
這個樣本介面架構其實與“Qt Quick裡的圖形效果——顏色(Color)”是一致的,只是我把 ListView 從原來的豎向改為了橫向。對應的 DropShadowExample.qml 內容如下:
import QtQuick 2.2import QtQuick.Controls 1.2Rectangle { 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.2import QtGraphicalEffects 1.0import QtQuick.Controls 1.2Rectangle { 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.2import QtGraphicalEffects 1.0import QtQuick.Controls 1.2Rectangle { 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 屬性,其他基本一致,偷個懶,也不說了。
回顧一下:
- Qt Quick裡的圖形效果——漸層(Gradient)
- Qt Quick裡的圖形效果——顏色(Color)
- Qt Quick裡的圖形效果——混合(Blend)
- Qt Quick裡的圖形效果(Graphical Effects)
- Qt Quick專欄