Step 1:画静态表盘(背景弧 + 主/次刻度)
← 手册首页 · 下一步 Step 2 指针与映射 →
目标
屏幕上出现一个开口朝下的弧形表盘:一段浅灰粗弧从左下顺时针扫到右下(270°),弧上铺 11 条主刻度(深灰粗线 + 数字标签),主刻度之间还有更短的次刻度。这步先不画指针、不做动画,专注把两套角度体系跑通——这是整件成品最容易绊人的地方,单独拎出来练。
提示(按顺序)
先把角度约定定下来(这套约定整个控件都用,写进 .cpp 顶部注释别忘):
- 屏幕角 β(cos/sin + rotate 用):3 点钟为 0°、顺时针为正——和 QPainter 在 y 朝下屏幕坐标系的旋转方向一致
- 表盘弧开口朝下:v=0 在 135°(左下 7:30)、v=max 在 45°(右下 4:30,= 135+270 取模)、mid 在 270°(顶部)
- 第 i 条主刻度(共 11 条,i=0..10)对应角度
ang = 135 + (i/10) * 270
画背景弧——这是第一个坑。QPainter::drawArc 的角度是 1/16°、0°=3 点钟、正值逆时针,和我们的屏幕角 β(顺时针为正)差一个 y 翻转。直接把 β 塞进去会把弧画反方向。正确做法:
p.drawArc(rect, 起始角*16, 扫角*16)- 起始角 = 225(正是 β=135°「左下」在 drawArc 约定下的读数),扫角 = -270(负扫角 = 顺时针铺开,抵消 drawArc 默认的逆时针)
画主刻度——用屏幕角 β + 三角函数算端点,不走 drawArc(β 顺时针为正,cos/sin 在 y 朝下屏幕直接对):
rad = ang * π / 180- 外端点
outer = (cx + tick_outer*cos(rad), cy + tick_outer*sin(rad)) - 内端点同理、半径换
tick_major_inner p.drawLine(inner, outer)画粗线- 数字标签:往内再缩一点画
QString::number(i * max/10),用QFontMetrics居中
画次刻度——每两个主刻度间 5 等分(插 4 条细短线),内端比主刻度更短,画笔细(1px)。
几何兜底:半径全部 std::max(1.0, ...),side = std::max(1, std::min(width(), height()))——控件被布局压极小时防控制行为未定义。
关键认知——为什么要分两套角度
很多人栽在这一步:以为「反正都是角度,drawArc 直接传」——结果弧逆时针铺、刻度顺时针铺,开口朝向反着。根因是 drawArc 的角度定义(正值逆时针、1/16°)和屏幕角 β(顺时针为正)不是一套东西,差一个 y 翻转。所以成品里刻度/指针端点一律用 β + 三角函数算,只有那段粗背景弧单独走 drawArc、并用负扫角修正方向。把这两套的边界在心里画清,后面就不会反复。
检查点
- 跑出来是开口朝下的一段浅灰粗弧,左下端到右下端正好 270°
- 11 条主刻度均匀铺在弧上,每条下面有数字(0/22/44/.../220,假设 maxValue=220)
- 主刻度间夹着更短的次刻度
- 缩放窗口:弧和刻度整体跟着比例缩,方向不变(不变形)
对了进下一步。如果弧方向画反、或刻度铺到弧外,翻 troubleshooting 的「弧方向画反」。
QPainter / 坐标系不熟?先读 QPainter 绘图基础、坐标变换、自定义控件绘制入门。
对照答案
- 角度约定常量 + 注释:
src/speed_meter.cpp:23-36 - 背景弧 drawArc(负扫角顺时针):
src/speed_meter.cpp:197-208 - 主刻度 + 数字标签(三角函数算端点,小尺寸自动隐藏):
src/speed_meter.cpp:223-248 - 次刻度(主刻度间 5 等分):
src/speed_meter.cpp:250-264 - 几何 clamp 兜底:
src/speed_meter.cpp:188-195
下一步:Step 2 加指针 + value→角度映射——让针能静态指到一个值,并补底部数字读数。