如何在QML中绘制带可变同心层的环形扇形靶标?
实现可调节同心层数的靶标扇形图形
需求说明
- 绘制类似靶标的图形,由12个扇形分割的同心圆组成
- 同心层数支持通过SpinBox在2-10范围内调整
- 整体尺寸固定,各层间距计算公式:
外圆半径 ÷ 层数 - 保留原Repeater循环单个扇形组件的结构,在单个扇形内绘制多条弧实现同心层
修改后的完整代码
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 property int concentricLayers: 5 // 默认5层,范围2-10 Rectangle { anchors.centerIn: parent width: 600 height: 600 Repeater { model: sectors CircleSector { anchors.fill: parent anchors.margins: 10 sectors: window.sectors sector: index concentricLayers: window.concentricLayers highlightSector: spinBoxSector.value } } } RowLayout { anchors.bottom: parent.bottom anchors.horizontalCenter: parent.horizontalCenter spacing: 20 Frame { SpinBox { id: spinBoxSector Layout.fillWidth: true from: 0 to: sectors - 1 value: 1 wrap: true stepSize: 1 label.text: "选中扇形" } } Frame { SpinBox { id: spinBoxLayers Layout.fillWidth: true from: 2 to: 10 value: window.concentricLayers stepSize: 1 label.text: "同心层数" onValueChanged: window.concentricLayers = value } } } }
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 int concentricLayers: 5 property int highlightSector: 0 property real fromAngle: sector * (360 / sectors) property real toAngle: (sector + 1) * (360 / sectors) property real centerX: width / 2 property real centerY: height / 2 // 外层半径(减去margins后的实际半径) property real outerRadius: centerX - anchors.margins Repeater { model: concentricLayers ShapePath { id: layerPath // 计算当前层的内外半径:第index层(从0开始)的内层半径是outerRadius - (index+1)*layerSpacing property real layerSpacing: outerRadius / concentricLayers property real innerRadius: outerRadius - (index + 1) * layerSpacing property real currentOuterRadius: outerRadius - index * layerSpacing // 根据扇形是否选中、层数奇偶设置填充色 fillColor: (sector == highlightSector) ? (index % 2 == 0 ? "#ff9933" : "#ffcc80") : (index % 2 == 0 ? "#f0f8ff" : "#e6f2ff") strokeColor: "grey" strokeWidth: 1 startX: centerX; startY: centerY // 绘制到内层弧的起始点 PathLine { x: centerX + innerRadius * Math.cos(fromAngle * Math.PI / 180) y: centerY + innerRadius * Math.sin(fromAngle * Math.PI / 180) } // 内层弧 PathArc { radiusX: innerRadius; radiusY: innerRadius x: centerX + innerRadius * Math.cos(toAngle * Math.PI / 180) y: centerY + innerRadius * Math.sin(toAngle * Math.PI / 180) useLargeArc: false sweepDirection: PathArc.Clockwise } // 绘制到外层弧的结束点 PathLine { x: centerX + currentOuterRadius * Math.cos(toAngle * Math.PI / 180) y: centerY + currentOuterRadius * Math.sin(toAngle * Math.PI / 180) } // 外层弧 PathArc { radiusX: currentOuterRadius; radiusY: currentOuterRadius x: centerX + currentOuterRadius * Math.cos(fromAngle * Math.PI / 180) y: centerY + currentOuterRadius * Math.sin(fromAngle * Math.PI / 180) useLargeArc: false sweepDirection: PathArc.Counterclockwise } // 回到中心闭合路径 PathLine { x: centerX; y: centerY } } } }
关键改动说明
- 新增层数控制:在main.qml中添加了控制同心层数的SpinBox,绑定到
window.concentricLayers属性,限制范围2-10 - 扇形内多层弧实现:在CircleSector中用Repeater循环生成对应层数的ShapePath,每层对应一个环形扇形段
- 半径计算:根据外层半径和层数计算每层间距
layerSpacing = outerRadius / concentricLayers,再计算每层的内外半径,确保各层间距均匀 - 颜色逻辑:选中的扇形使用橙色系交替色,未选中的使用浅蓝系交替色,区分层次和选中状态
- 路径闭合:每层ShapePath通过"中心→内层起始点→内层弧→外层结束点→外层弧→中心"的路径,绘制闭合的环形扇形
内容的提问来源于stack exchange,提问作者ephemera
相关产品推荐
相关产品推荐

