简体   繁体   English

一种在 QML 中绘制同心圆扇区的方法?

[英]A way to draw a concentric circles' sector in QML?

I need to draw something like a target, a bunch of concentric circles split into 12 or so sectors (pizza slices).我需要画一些像目标一样的东西,一堆同心圆分成 12 个左右的扇区(披萨片)。 So the number of "layers" inside the outer circle can change anywhere from 2 to 10, the size of the whole target should remain the same, and the distance between inner circles should be equal (bascially OuterCircleRadius / NumberOfLayers)所以外圈内的“层”数可以在 2 到 10 之间变化,整个目标的大小应该保持不变,内圈之间的距离应该相等(基本上是 OuterCircleRadius / NumberOfLayers)

So far I came up with a code that basically draws a single segment of a circle, then, by putting a Repeater in the main file I get a full circle, split into 12 sectors, which is what I need.到目前为止,我想出了一个基本上绘制圆的单个部分的代码,然后通过在主文件中放置一个 Repeater,我得到一个完整的圆,分成 12 个扇区,这就是我需要的。 Now I need to find a way to add a number of concentric circles inside the outer one.现在我需要找到一种方法来在外圈内添加多个同心圆。 The problem is that the number of concentric circles is not constant, and is set by user.问题是同心圆的数量不是恒定的,是由用户设置的。 So the "target" should change when a different number of layers is chosen (for example with a SpinBox). So the "target" should change when a different number of layers is chosen (for example with a SpinBox). So far my idea is to draw a few additional arcs inside of a single sector so I can keep the Repeater.到目前为止,我的想法是在单个扇区内绘制一些额外的弧线,这样我就可以保留 Repeater。 My code below.我的代码如下。

// main.qml

import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Layouts
import QtQuick.Controls

Window {
   width: 600
   height: 600
   visible: true
   id: window
   property int sectors: 12
   Rectangle {
       anchors.centerIn: parent
       width: 600
       height: 600
       Repeater {
           model: sectors
           CircleSector {
               anchors.fill: parent
               anchors.margins: 10
               sectors: window.sectors
               sector: index
               fillColor: index == spinBox.value ? "orange" : "aliceblue"
           }
       }
   }
   Frame {
           SpinBox {
               id: spinBox
               Layout.fillWidth: true
               from: 0
               to: sectors - 1
               value: 1
               wrap: true
               stepSize: 1
           }
   }
}

// CircleSector.qml

import QtQuick 2.12
import QtQuick.Shapes 1.12

Shape {
    id: circleSector
    antialiasing: true
    property int sectors: 12
    property int sector: 0
    property real from: sector * (360 / sectors)
    property real to: (sector + 1) * (360 / sectors)
    property real centerX: width / 2
    property real centerY: height / 2
    property alias fillColor: shapePath.fillColor
    property alias strokeColor: shapePath.strokeColor
    property real fromX: centerX + centerX * Math.cos(from * Math.PI / 180)
    property real fromY: centerY + centerY * Math.sin(from * Math.PI / 180)
    property real toX: centerX + centerX * Math.cos(to * Math.PI / 180)
    property real toY: centerY + centerY * Math.sin(to * Math.PI / 180)
    containsMode: Shape.FillContains
    ShapePath{
        id: shapePath
        fillColor: "aliceblue"
        strokeColor: "grey"
        startX: centerX; startY: centerY
        PathLine { x: fromX; y: fromY }
        PathArc{
            radiusX: centerX; radiusY: centerY
            x: toX; y: toY
        }
        PathLine{ x: centerX; y: centerY }
    }
}

Depending on what you want to do with your polar coordinate system you could use PolarChartView .根据您要对极坐标系执行的操作,您可以使用PolarChartView With that you can also easily plot data on it.有了它,您还可以轻松地获取 plot 数据。

import QtQuick
import QtQuick.Controls
import QtCharts

Window {
    width: 640
    height: 480
    visible: true
    title: qsTr("Hello World")

    PolarChartView {
        anchors.fill: parent
        legend.visible: false
        antialiasing: true

        ValueAxis {
            id: axisAngular
            min: 0
            max: 1
            labelsVisible: false
            lineVisible: false
            tickCount: axisAngularSpinBox.value
        }

        ValueAxis {
            id: axisRadial
            min: 0
            max: 1
            labelsVisible: false
            lineVisible: false
            tickCount: axisRadialSpinBox.value
        }

        SplineSeries {
            id: series
            axisAngular: axisAngular
            axisRadial: axisRadial
            pointsVisible: true
        }
    }

    Column {
        SpinBox {
            id: axisAngularSpinBox
            value: 9
        }

        SpinBox {
            id: axisRadialSpinBox
            value: 10
        }
    }
}

在此处输入图像描述

You could use this Canvas solution.您可以使用此Canvas解决方案。 It isn't pretty, but it hopefully does what you want.它不漂亮,但它希望做你想要的。

import QtQuick
import QtQuick.Controls

ApplicationWindow {
    id: root
    title: "Polar Coordinates Canvas"
    width: 640
    height: 480
    visible: true
    color: "white"

    property int numCircles: circlesSpinBox.value
    property int numSegments: segmentsSpinBox.value

    Canvas {
        id: canvas
        anchors.centerIn: parent
        width: 400
        height: canvas.width
        onPaint: {
            var ctx = getContext("2d")

            ctx.fillStyle = 'white'
            ctx.fillRect(0, 0, canvas.width, canvas.height);

            const centerX = canvas.width / 2
            const centerY = canvas.height / 2
            const radius = canvas.width / 2

            const circleDistance = (canvas.width / 2) / root.numCircles

            for (let i = 1; i <= root.numCircles; ++i) {
                let r = i * circleDistance
                ctx.beginPath()
                ctx.arc(centerX, centerY, r, 0, 2 * Math.PI, false)
                ctx.lineWidth = 1
                ctx.strokeStyle = 'black'
                ctx.stroke()
            }

            if (root.numSegments < 2)
                return

            const segmentAngle = 360 / root.numSegments

            if (root.numSegments % 2 === 0) { // even
                for (let s = 0; s < (root.numSegments / 2); ++s) {
                    let a =  s * segmentAngle

                    ctx.beginPath()

                    let x = centerX + radius * Math.cos(a * (Math.PI / 180))
                    let y = centerY + radius * Math.sin(a * (Math.PI / 180))

                    ctx.moveTo(x, y)

                    x = centerX + radius * Math.cos((a + 180) * (Math.PI / 180))
                    y = centerY + radius * Math.sin((a + 180) * (Math.PI / 180))

                    ctx.lineTo(x, y)
                    ctx.lineWidth = 1
                    ctx.strokeStyle = 'black'
                    ctx.stroke()
                }
            } else { // odd
                for (let s = 0; s < root.numSegments; ++s) {
                    let a =  s * segmentAngle

                    ctx.beginPath()

                    let x = centerX + radius * Math.cos(a * (Math.PI / 180))
                    let y = centerY + radius * Math.sin(a * (Math.PI / 180))

                    ctx.moveTo(x, y)
                    ctx.lineTo(centerX, centerY)
                    ctx.lineWidth = 1
                    ctx.strokeStyle = 'black'
                    ctx.stroke()
                }
            }
        }
    }

    Column {
        SpinBox {
            id: circlesSpinBox
            value: 3
            onValueChanged: canvas.requestPaint()
        }

        SpinBox {
            id: segmentsSpinBox
            value: 7
            onValueChanged: canvas.requestPaint()
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM