簡體   English   中英

如何在 Qml 中用斜線創建進度條?

[英]How to create a Progress Bar in Qml with slant lines?

在此處輸入圖像描述

你好,

我正在尋找一些解決方案來在 qml 中創建具有斜線的進度條。

我沒有任何片段可以在這里分享,因為我不知道該怎么做。

誰能指導一下??

不確定Fusion 樣式 ProgressBar做了類似的事情,它有移動的斜線。

以下是調整后的代碼以顯示確定條的行,僅使用公共 API:

import QtQuick
import QtQuick.Controls

ApplicationWindow {
    width: 640
    height: 480
    visible: true

    ProgressBar {
        id: control
        value: 0.5

        contentItem: Item {
            implicitWidth: 120
            implicitHeight: 24

            Rectangle {
                height: parent.height
                width: control.position * parent.width

                radius: 2
                border.color: "steelblue"
                gradient: Gradient {
                    GradientStop {
                        position: 0
                        color: Qt.lighter("steelblue", 1.2)
                    }
                    GradientStop {
                        position: 1
                        color: Qt.darker("steelblue", 1.2)
                    }
                }
            }

            Item {
                x: 1
                y: 1
                width: parent.width - 2
                height: parent.height - 2
                clip: true

                Image {
                    width: Math.ceil(parent.width / implicitWidth + 1) * implicitWidth
                    height: parent.height

                    mirror: control.mirrored
                    fillMode: Image.TileHorizontally
                    source: "qrc:/qt-project.org/imports/QtQuick/Controls/Fusion/images/progressmask.png"
                    opacity: 0.25

                    NumberAnimation on x {
                        running: control.visible
                        from: -31 // progressmask.png width
                        to: 0
                        loops: Animation.Infinite
                        duration: 750
                    }
                }
            }
        }
    }
}

如果您不想要 animation,只需刪除 NumberAnimation。

請注意,由於此示例使用來自 Fusion 樣式的圖像(為方便起見),因此它必須以 Fusion 樣式運行。

如果您想以其他樣式運行它,請將圖像的 URL 替換為其他樣式,並確保您使用的是非原生樣式

注意: macOS 和 Windows styles 不適合定制。 相反,建議始終將自定義控件基於所有平台上可用的單一樣式,例如基本樣式、融合樣式、想象樣式、材質樣式、通用樣式。 通過這樣做,您可以保證無論應用程序使用哪種樣式運行,它看起來總是一樣的。 例如:

我將分階段解決問題。 這反映了我 go 如何自己解決 QML 問題。 第一個目標是創建一個 200x32 的 ProgressBar 並將其設置為 25% 的進度。 首先,我從自定義 ProgressBar 的空白矩形開始:

ProgressBar {
  implicitWidth: 200
  implicitHeight: 32
  contentItem: Rectangle {
    border.color: "black"
  }
}

進度條空白矩形

接下來,我決定制作一條 32x32 SVG 的對角線,並以 4 個像素間隔重復這條線,覆蓋整個寬度(即 200 / 4 === 50)。

ProgressBar {
  implicitWidth: 200
  implicitHeight: 32
  contentItem: Rectangle {
    border.color: "black"
    Repeater {
      model: 200 / 4
      Image {
        x: index * 4
        y: 0
        source: `data:image/svg+xml;utf8,
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
        <path fill="none" stroke="black" d="M 0 0 L 32 32" />
        </svg>`
      }
    }
  }
}

進度條-try-slant-1

我觀察到上述兩個問題:

  1. 左邊的三角形間隙
  2. 右邊的過沖

為了解決這些問題,(1)將線條向左移動 32 像素以覆蓋間隙,(2)我將線條擴展為(200 + 32)/ 4 === 58,(3)使用剪輯裁剪干凈我的矩形之外的對角線。

ProgressBar {
  implicitWidth: 200
  implicitHeight: 32
  contentItem: Rectangle {
    border.color: "black"
    clip: true
    Repeater {
      model: (200 + 32) / 4
      Image {
        x: index * 4 - 32
        y: 0
        source: `data:image/svg+xml;utf8,
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
        <path fill="none" stroke="black" d="M 0 0 L 32 32" />
        </svg>`
      }
    }
  }
}

進度條清潔傾斜

接下來,我想代表 25%。 我通過繪制一個覆蓋右側斜線的 75% 白色矩形來做到這一點。

ProgressBar {
  implicitWidth: 200
  implicitHeight: 32
  value: 0.25
  contentItem: Rectangle {
    border.color: "black"
    clip: true
    Repeater {
      model: (200 + 32) / 4
      Image {
        x: index * 4 - 32
        y: 0
        source: `data:image/svg+xml;utf8,
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
        <path fill="none" stroke="black" d="M 0 0 L 32 32" />
        </svg>`
      }
    }
    Rectangle {
      anchors.top: parent.top
      anchors.right: parent.right
      anchors.bottom: parent.bottom
      implicitWidth: parent.width * 0.75
      implicitHeight: parent.height
      border.color: "black"
      color: "white"
    }
  }
}

進度條-25-%

最后,我們嘗試概括我們的解決方案:

ProgressBar {
  id: progressBar
  implicitWidth: 200
  implicitHeight: 32
  contentItem: Rectangle {
    border.color: "black"
    clip: true
    Repeater {
      model: (parent.width + parent.height) / 4
      Image {
        x: index * 4 - parent.height
        y: 0
        source: `data:image/svg+xml;utf8,
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${parent.height} ${parent.height}">
        <path fill="none" stroke="black" d="M 0 0 L ${parent.height} ${parent.height}" />
        </svg>`
      }
    }
    Rectangle {
      anchors.top: parent.top
      anchors.right: parent.right
      anchors.bottom: parent.bottom
      implicitWidth: parent.width * (1 - parent.parent.value)
      implicitHeight: parent.height
      border.color: "black"
      color: "white"
    }
  }
}

進度條結果

我們做了一些假設:

  • 進度條是 200x32
  • 顏色是帶有黑色輪廓和黑色對角線的白色條
  • 右邊的欄是白色的
  • 使用了 SVG 圖像

為了進一步概括,我們可以考慮(1)用更有效的等效物替換 SVG 圖像,(2)允許顏色可配置。

又一個解決方案。

在此處輸入圖像描述

ProgressBar {
    id: control

    property color contentItemColor: "white"
    property color backgroundColor: "yellow"
    property color borderColor: "red"
    property int borderWidth: 1
    property color stripColor: "green"
    property int stripGap: 10
    property int stripWidth: 2
    property color indicatorColor: "red"
    property int indicatorWidth: 2
    property int indicatorRadius: 0
    property int indicatorExtend: 0

    value: 0.5
    width: 600
    height: 80

    background: Rectangle {
        color: control.backgroundColor
        border.width: control.borderWidth
        border.color: control.borderColor

        Canvas {
            x: control.borderWidth
            y: control.borderWidth
            width: control.width - (2 * control.borderWidth)
            height: control.height - (2 * control.borderWidth)

            onPaint: {
                var ctx = getContext("2d");
                ctx.strokeStyle = control.stripColor
                ctx.lineWidth = control.stripWidth
                ctx.lineCap = "square"

                var p1, p2

                let n = Math.ceil((control.width + control.height) / (control.stripGap)) + 1

                for (let i = 0; i != n; ++i) {
                    let p = i * control.stripGap
                    p1 = Qt.vector2d(p - control.height, 0)
                    p2 = Qt.vector2d(p, control.height)

                    ctx.beginPath()
                    ctx.moveTo(p1.x, p1.y)
                    ctx.lineTo(p2.x, p2.y)
                    ctx.closePath()
                    ctx.stroke()
                }
            }
        }
    }

    contentItem: Item {
        Rectangle {
            anchors.fill: parent
            anchors.margins: control.borderWidth
            anchors.leftMargin: Math.max(control.borderWidth,
                                         control.visualPosition * control.width)

            color: control.contentItemColor
        }

        Rectangle {
            x: control.visualPosition * control.width - (control.indicatorWidth / 2)
            y: -control.indicatorExtend
            width: control.indicatorWidth
            height: control.height + (2 * control.indicatorExtend)
            color: control.indicatorColor
            radius: control.indicatorRadius
            visible: control.visualPosition > 0.0 && control.visualPosition < 1.0
        }
    }
}

我建議使用ShaderEffect來創建更有效的結果。
所以,當其他人都實現了自己的代碼時,我也做了。
結果如下所示。

斜線.qml

// SlantLines.qml
import QtQuick 2.12

ShaderEffect {
    id: effect
    property real seed: 0 // To animate the lines' x axis.
    property real num: width / 6 // The number of lines changes with width and may even be fixed.
    property color color: '#000' // Color of lines (background is transparent)
    property vector2d ratio: {
        const max = Math.max(width, height);
        return Qt.vector2d(width/max, height/max);
    }

    fragmentShader: "
        uniform lowp float qt_Opacity;
        uniform lowp float seed;
        uniform lowp float num;
        uniform highp vec2 ratio;
        uniform highp vec4 color;
        varying highp vec2 qt_TexCoord0;
        void main() {
            vec2 uv = qt_TexCoord0*ratio/ ratio.x;
            // Slope can be changed by multiplying 'y' by any number.
            uv.x -= uv.y + seed/num; 
            vec2 grid = fract(uv * vec2(num,1.));
            // You may also change the line width from 0.0 to 1.0. (change 0.5)
            gl_FragColor = color * smoothstep(0.0,ratio.x*1e-1,grid.x - 0.5) * qt_Opacity;
        }"
}

預習

它是如何工作的一個例子。

板條線預覽
component SlantLinesColumn: Column {
    property real xSeed: 0
    spacing: 5
    Repeater {
        model: 12
        SlantLines {
            height: 10
            width: (index + 1) * 20
            color: Qt.hsva(index/13,1,1,1)
            seed: xSeed
        }
    }
}

SlantLinesColumn { }
SlantLinesColumn {
    y: 190
    Timer {
        running: true; repeat: true
        interval: 50 // Almost 30Hz.
        onTriggered: parent.xSeed -= 0.1
    }
}

進度條

SlantLines也可以嵌入到進度條中。
此模板可從Qt 源代碼中獲得。

import QtQuick 2.15
import QtQuick.Templates 2.15  as T

T.ProgressBar {
    id: control
    implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset, implicitContentWidth + leftPadding + rightPadding)
    implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset, implicitContentHeight + topPadding + bottomPadding)
    
    property int orientation: Qt.Vertical
    readonly property bool vertical: orientation == Qt.Vertical
    
    contentItem: Item {
        SlantLines {
            y: control.vertical ? parent.height - height : 0
            width: !control.vertical && !control.indeterminate ? 
                        parent.width * control.position : parent.width 
            height: control.vertical && !control.indeterminate ? 
                        parent.height * control.position : parent.height
            color: control.palette.dark
            
            Timer {
                running: control.visible && control.indeterminate
                repeat: true; interval: 50
                onTriggered: parent.seed -= 0.1
            }
        }
    }

    background: Rectangle {
        implicitWidth: !control.vertical ? 200 : 18
        implicitHeight: control.vertical ? 200 : 18
        color: control.palette.midlight            
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM