Qtpainter练手项目:仪表盘相关的坐标变换与绘图

项目概述

本项目实现了一个动态速度表盘,使用Qt的QPainter进行绘制。表盘具有以下特点:

  • 动态变化的速度指针(0-240 km/h范围)
  • 渐变色彩的表盘背景
  • 精确的刻度显示和数值标注
  • 红色警告区域(高速区域)
  • 中央显示当前速度值和单位

github仓库地址:https://github.com/1024freedom/Qt_dashboard

作为练习写的,还有很多值得优化的地方,欢迎交流学习

在这里插入图片描述

核心技术点解析

1. 坐标系变换基础

在Qt绘图中,坐标系变换是实现复杂图形绘制的关键。本项目大量使用了坐标系平移和旋转:

painter.translate(rect().center()); // 将原点移动到窗口中心
painter.rotate(135); // 旋转坐标系135度

2. 刻度值坐标变换详解

刻度值的坐标变换是本项目最复杂的部分,涉及到三角函数和坐标系变换:

// 计算每个刻度之间的角度
double angle = 270.0 / 60.0;

// 循环绘制60个刻度
for (int i = 0; i <= 60; i++) {
    if (i % 5 == 0) { // 每5个刻度绘制一个数值
        // 计算当前刻度相对于零点的角度(取模45度)
        angle_move = fmod(angle * i, 45.0);
        
        // 使用三角函数计算圆周上的坐标
        x = cos(angle_move) * r;
        y = sin(angle_move) * r;
        
        // 计算到原点的距离(用于平移坐标系)
        targetX = sqrt(x * x + y * y);
        
        // 保存当前坐标系状态
        painter.save();
        
        // 将坐标系平移到刻度位置
        painter.translate(targetX, 0);
        
        // 旋转文本使其与圆周切线方向一致
        painter.rotate(90);
        
        // 绘制刻度数值
        painter.drawText(-10, 4, QString::number(i * 4));
        
        // 恢复坐标系状态
        painter.restore();
        
        // 绘制主刻度线
        painter.drawLine(height() / 2 - 15, 0, height() / 2 - 1, 0);
    } else {
        // 绘制次刻度线
        painter.drawLine(height() / 2 - 6, 0, height() / 2 - 1, 0);
    }
    
    // 旋转坐标系为下一个刻度做准备
    painter.rotate(angle);
}

坐标变换原理

  1. 首先将坐标系旋转135度,使0刻度位于左下方
  2. 对于每个主刻度,计算其在圆周上的位置
  3. 以仪表盘中心为坐标原点,水平向右为x轴正方向建立平面直角坐标系,通过三角函数来获取目标刻度位置的坐标(注意传统的直角坐标系与qt坐标系的区别)
  4. 通过translate()将坐标系移动到刻度位置
  5. 旋转文本使其与圆周切线方向一致
  6. 绘制文本后恢复坐标系状态

3. 渐变效果实现

项目中使用径向渐变创建了表盘的立体效果:

// 表盘外部光圈渐变
QRadialGradient radialGradient0(0, 0, height() / 2 + 25);
radialGradient0.setColorAt(0.85, QColor(Qt::black));
radialGradient0.setColorAt(1.0, QColor(Qt::red));

// 表盘背景渐变
QRadialGradient radialGradient(0, 0, height() / 2);
radialGradient.setColorAt(0.0, QColor(Qt::gray));
radialGradient.setColorAt(1.0, QColor(Qt::black));

4. 指针动态效果

指针的动态旋转通过定时器控制:

// 定时器控制速度值变化
connect(timer, &QTimer::timeout, this, [ = ]() {
    if (flag) {
        currentValue--;
        if (currentValue <= 0) flag = false;
    } else {
        currentValue++;
        if (currentValue >= 60) flag = true;
    }
    update(); // 触发重绘
});

// 绘制指针时应用旋转
painter.rotate(135 + currentValue * angle);

5. 扇形绘制技巧

使用drawPie()方法绘制速度表盘的扇形区域:

painter.drawPie(QRect(-r / 2 + 60, -r / 2 + 60, r - 120, r - 120), 
                (-135) * 16, -angle * currentValue * 16);

参数说明

  • 第一个参数定义扇形的外接矩形
  • 第二个参数是起始角度(注意qt以1/16度作为基本单位)
  • 第三个参数是扇形跨度角度

完整代码结构

项目的主要绘制逻辑分布在以下几个方法中:

  1. initCanvas() - 初始化画布和表盘背景
  2. drawMiddleCircle() - 绘制中央小圆
  3. drawGradation() - 绘制刻度和数值
  4. drawPointer() - 绘制指针
  5. draw_Pie() - 绘制扇形区域
  6. drawEllipseInnerBlack()drawEllipseInnerShine() - 绘制中央区域效果
  7. drawMiddleValue() - 绘制中央数值显示

开发小技巧与注意事项

  1. 状态保存与恢复:使用save()restore()管理坐标系状态,避免变换累积
  2. 抗锯齿渲染:使用setRenderHint(QPainter::Antialiasing, true)提高绘制质量
  3. 性能优化:在paintEvent中避免频繁创建和销毁对象
  4. 坐标系统一:所有绘图操作基于以窗口中心为原点的坐标系

还有很多需要优化的地方 欢迎交流学习!

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐