QML使用ShaderEffect繪製環形進度條

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);
                }
            }"
}

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章