0.前言
之前用 Qt Widgets 的 QOpenGLWidget 類配合着色器寫了下環形進度條(https://blog.csdn.net/gongjianbo1992/article/details/106043023),現在用 QML 的 ShaderEffect 重新寫下,用的 Qt 默認的 OpenGL 版本,貌似是 OpenGL ES2.0 。
ShaderEffect 是 QML 中用來對 Item 做着色器效果的組件,允許直接在 QML 中編寫諸如陰影,模糊,着色和頁面捲曲之類的效果。傳遞參數時,只需要將 ShaderEffect 的 property 聲明在 shader 中,該組件也預定了一些屬性,詳情參考文檔:https://doc.qt.io/qt-5/qml-qtquick-shadereffect.html
(也可以參照 QML Book 進行使用 http://qmlbook.github.io/ )
1.實現思路
圓環我是通過計算距離圓心的距離來渲染的圓環:
void main() {
float len = abs(sqrt(thePos.x*thePos.x+thePos.y*thePos.y));
float alpha = 1.0-smoothstep(0.15,0.20,abs(len-0.75));
gl_FragColor = vec4(0.4,0.1,0.6,alpha);
}
圓環的抗鋸齒我使用的 smoothstep 函數:
(這裏還沒有去做斜線部分的抗鋸齒)
修改值時的動畫效果用的 QML 的屬性行爲(https://blog.csdn.net/gongjianbo1992/article/details/102135779)。
2.實現代碼
實現效果圖片:
實現代碼:
//main.qml
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12
Window {
id: root
visible: true
width: 640
height: 480
title: qsTr("龔建波 1992")
//進度條
MyProgressBar{
id: progress
width: root.width>root.height?root.height/2:root.width/2
height: progress.width
anchors.centerIn: parent
}
Row{
x:10
y:10
spacing: 10
//數字框
SpinBox{
id: spin
from: 0
to: 100
value: 45
editable: true
}
//按鈕
Button{
id: btn
text: "set data"
onClicked: {
progress.value=spin.value
}
}
}
Component.onCompleted: {
//初始值
progress.value=spin.value
}
}
import QtQuick 2.12
//自定義的環形進度條組件
//沒設置OpenGL版本,可能默認時OpenGL ES2.0吧
ShaderEffect{
id: control
property double min: 0
property double max: 100
property double value: 0
// 給着色器的
property real aValue: (value-min)/(max-min)
// 修改值後觸發動畫效果
Behavior on aValue{
NumberAnimation{
duration: 1000
}
}
// 上面的文字
Text{
anchors.centerIn: parent
color: "black"
font.pixelSize: 20
text: Number(aValue*100).toFixed(2)+" %"
}
//mat4 qt_Matrix組合的轉換矩陣,從根項到此ShaderEffect的矩陣與正交投影的乘積
//vec4 qt_Vertex頂點位置,左上角頂點的位置爲(0,0),右下角頂點的位置爲(width,height)
//vec2 qt_MultiTexCoord0紋理座標,左上角座標爲(0,0),右下角座標爲(1,1)
//thePos用來指定位置,標準化設備座標
//aSmoothWidth用來指定smoothstep的寬度
vertexShader: "
uniform mat4 qt_Matrix;
attribute vec4 qt_Vertex;
attribute vec2 qt_MultiTexCoord0;
varying vec2 thePos;
varying float aSmoothWidth;
uniform float width;
void main() {
thePos = vec2(qt_MultiTexCoord0.x*2.0-1.0,-qt_MultiTexCoord0.y*2.0+1.0);
aSmoothWidth = 3.0/float(width);
gl_Position = qt_Matrix * qt_Vertex;
}"
//float qt_Opacity從根項到此ShaderEffect的不透明度的乘積。
//es2裏字面量也得寫成和運算變量一樣的類型,如浮點數
//myatan2把角度歸一化爲[0,1]
fragmentShader: "
#define PI 3.14159265
varying vec2 thePos;
varying float aSmoothWidth;
uniform float qt_Opacity;
uniform float aValue;
float myatan2(float y,float x)
{
float ret_val=0.0;
if(x!=0.0){
ret_val=atan(y,x);
if(ret_val<0.0){
ret_val+=2.0*PI;
}
}
return ret_val/(2.0*PI);
}
void main() {
float len = abs(sqrt(pow(thePos.x,2.0)+pow(thePos.y,2.0)));
float alpha = 1.0-smoothstep(0.15,0.15+aSmoothWidth,abs(len-0.75));
float angle = myatan2(thePos.y,thePos.x);
if(angle<aValue){
gl_FragColor = vec4(1.0,0.1,(1.0-angle),alpha);
}else{
gl_FragColor = vec4(0.4,0.1,0.6,alpha);
}
}"
}