Skip to content
正常

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→角度映射——让针能静态指到一个值,并补底部数字读数。

AwesomeQt v0.3.0-2-gbbb418e · bbb418e · 2026-07-12