目录
前言:
整体代码
widget.h
widget.cpp
效果演示
实现刻度文字正确排版
优化代码
达到效果
封装整理代码结构:
widget.h
widget.cpp
指针样式美化
优化后的指针API
效果演示
设置高速刻度为红色
优化刻度API
效果演示
速度显示优化
给内圈画上黑色
优化速度显示文本格式
调整绘画顺序
效果演示
实现内环发光圈:
内环发光效果API
插入位置
效果演示
实现外环发个圈
外环发光效果API
插入位置
实现效果
绘制汽车logo
绘制汽车logo的API
插入位置
实现效果
deBug及微调
bug1: restore()和 save() 没有配对使用
bug2:中间显示的速度不匹配
前言:
这个表盘在上一个项目"简易表盘"的基础上搭建,请先看上篇:
Qt绘图项目 - 简易表盘-CSDN博客
整体代码
widget.h
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();protected:void paintEvent(QPaintEvent *event);private:Ui::Widget *ui;QTimer *timer;int currentValue; //实现指针移动int mark = 0; // 控制指针的移动方向int startAbgle; // 设置起始角度double angle;void initCanvas(QPainter& painter);void drawMiddleCircle(QPainter& painter,int radius);void drawCurrentSpeed(QPainter& painter);void drawScale(QPainter& painter,int radius);void drawScaleText(QPainter& painter,int radius);void drawPointLine(QPainter &painter,int length);void drawSpeedPie(QPainter& painter,int radius);void startSpeed();void drawEllispseInnerBlack(QPainter& painter,int radius);void drawEllispseInnerBShine(QPainter& painter,int radius);void drawEllispseOutterBShine(QPainter& painter,int radius);void drawLogo(QPainter& painter,int radius);
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include "ui_widget.h"#include <QPainter>
#include <QTimer>
#include <QtMath>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);setFixedSize(800,600);startAbgle = 150; // 设置起始角度为150startSpeed();}Widget::~Widget()
{delete ui;
}void Widget::initCanvas(QPainter& painter)
{//设置抗锯齿painter.setRenderHints(QPainter::Antialiasing,true);//设置黑色的背景色painter.setBrush(Qt::black); // 设置 黑色的画刷painter.drawRect(rect());//坐标系,平移到中心QPoint cent(rect().width()/2,rect().height()*0.6); //自定义中心位置painter.translate(cent);}void Widget::drawMiddleCircle(QPainter &painter,int radius)
{//画小圆painter.setPen(QPen(Qt::white,4)); //设置白色的画笔painter.drawEllipse(QPoint(0,0),60,60);
}//画当前速度
void Widget::drawCurrentSpeed(QPainter &painter)
{painter.setPen(Qt::white);//显示当前速度值:QFont font("Arial",30);font.setBold(true);painter.setFont(font);painter.drawText(QRect(-60,-60,120,70),Qt::AlignCenter,QString::number(currentValue*4));QFont font2("Arial",13);font2.setBold(true);painter.setFont(font2);painter.drawText(QRect(-60,-60,120,160),Qt::AlignCenter,"Km/h");}// 画出当前刻度
void Widget::drawScale(QPainter &painter,int radius)
{//保存原点:painter.save(); // 三点钟方向//画刻度://1.算出一个刻度需要的角度 270 度分成 50份angle = 240*1.0/60; //需要先转为double类型,否则销售几乎部分会被吞掉造成误差//2.设置起始角度painter.rotate(startAbgle); // 从135度开始//设置字体样式:// painter.setFont(QFont("华文宋体",8));//3.分类讨论 画出所有刻度for(int i=0;i<=60;++i){//包括0- 一共有61根刻度线if(i>=40){ // 时速160 = 40*4 认定为高速painter.setPen(QPen(Qt::red,5)); //将高速速设定为红色}if(i%5 == 0){ // 被5 整除进一步细分表盘//画出一个长刻度painter.drawLine(radius-20,0,radius-3,0);}else{//画出一个长刻度painter.drawLine(radius-10,0,radius-3,0);}painter.rotate(angle);//选择angle的角度准备去画下一个刻度}painter.restore();
}// 写刻度文字
void Widget::drawScaleText(QPainter &painter, int radius)
{//设置字体:QFont font("Arial",13);font.setBold(true); // 设置粗体painter.setFont(font);int r = radius-43;for(int i=0;i<=60;++i){if(i%5 == 0){ // 每5格标记一个刻度//保存坐标系painter.save();//算出平移点 // 弧度 = 角度*3.1415/180int delX = qCos(qDegreesToRadians(210-angle*i))*r;//QT中sin、cos认的是弧度int delY = qSin(qDegreesToRadians(210-angle*i))*r;//qDegreesToRadians - 角度转弧度//平移坐标系painter.translate(QPoint(delX,-delY));//旋转坐标系:painter.rotate(-120+angle*i);//angle=4,30*4=120,实参是0,120//写上文字painter.drawText(-25,-25,50,30,Qt::AlignCenter,QString::number(i*4));//恢复坐标系painter.restore();}}}// 画指针
void Widget::drawPointLine(QPainter &painter,int length)
{//画指针 --> 线//先恢复到之前保存的原点:painter.save(); // 接着保存原点// 通过定时器去改变currentValue的值,去控制指针的移动// painter.drawLine(60,0,height()/2-20-38,0); // 58//指针样式美化:painter.setRenderHint(QPainter::Antialiasing,true);painter.setBrush(Qt::white);painter.setPen(Qt::NoPen);//painter.translate(rect().center());static const QPointF points[4] = {QPointF(0,0),QPointF(0,15.0),QPointF(220.0,1.1),QPointF(220.0,-1.1)};//给指针弧度偏移 --> 让指针转动起来painter.rotate(startAbgle+angle*currentValue); // 进行坐标系偏移painter.drawPolygon(points, 4);painter.restore();
}//画扇形
void Widget::drawSpeedPie(QPainter &painter, int radius)
{QRect rentangle(-radius,-radius,radius*2,radius*2);painter.setPen(Qt::NoPen);painter.setBrush(QColor(255,0,0,80));painter.drawPie(rentangle,(-startAbgle)*16,-angle*currentValue*16);
}void Widget::startSpeed()
{timer = new QTimer(this);currentValue = 0;connect(timer,&QTimer::timeout,[=](){if(mark == 0){currentValue++;if(currentValue >= 60)mark = 1;}else if(mark ==1){currentValue--;if(currentValue <= 0)mark = 0;}update(); // 触发绘图事件});timer->start(30);
}// ,给内圈画上黑色
void Widget::drawEllispseInnerBlack(QPainter &painter, int radius)
{painter.setBrush(Qt::black);painter.drawEllipse(QPoint(0,0),radius,radius);
}// 内环发光效果
void Widget::drawEllispseInnerBShine(QPainter &painter, int radius)
{// 径向 渐变实现QRadialGradient radialGradient(0,0,radius);radialGradient.setColorAt(0.0,QColor(255,0,0,200));radialGradient.setColorAt(1.0,QColor(0,0,0,100));painter.setBrush(radialGradient);painter.drawEllipse(QPoint(0,0),radius,radius);
}// 画外围发光圈
void Widget::drawEllispseOutterBShine(QPainter &painter, int radius)
{QRect rentangle(-radius,-radius,radius*2,radius*2);painter.setPen(Qt::NoPen);//渐变色处理外环光亮QRadialGradient radialGradient(0,0,radius);radialGradient.setColorAt(1,QColor(255,0,0,200));radialGradient.setColorAt(0.97,QColor(255,0,0,120));radialGradient.setColorAt(0.9,QColor(0,0,0,0));radialGradient.setColorAt(0,QColor(0,0,0,0));painter.setBrush(radialGradient);painter.drawPie(rentangle,(-150)*16,-angle*60*16);
}// 绘制汽车logo
void Widget::drawLogo(QPainter &painter, int radius)
{QRect rectangle(-65,radius*0.38,130,50);painter.drawPixmap(rectangle,QPixmap(":/C:/Users/31472/Desktop/Images/qi_che_biao_pan/lu_hua.png"));}void Widget::paintEvent(QPaintEvent *event)
{QPainter painter(this);int rad = height()/2;// 初始化画布initCanvas(painter);//不用画大圆了,用刻度尺去表出框架即可//painter.drawEllipse(QPoint(0,0),height()/2,height()/2);//画出中间的小圆drawMiddleCircle(painter,60);//画刻度drawScale(painter,rad);//写刻度文字:drawScaleText(painter,rad);// 画指针drawPointLine(painter,rad-58);//画扇形drawSpeedPie(painter,rad);//画渐变色发光内圈圆drawEllispseInnerBShine(painter,110);// 画黑色内圈drawEllispseInnerBlack(painter,80);//画出当前速度 -- 放正在画黑的下面,要设置在黑圈的图层下drawCurrentSpeed(painter);//画外环发光圈drawEllispseOutterBShine(painter,rad+15);//画汽车logodrawLogo(painter,rad);}
效果演示
实现刻度文字正确排版
移动坐标系,达到正确排版
优化代码
//刻度文字达到正确排版效果int r = height()/2-43;painter.restore();for(int i=0;i<=60;++i){if(i%5 == 0){ // 每5格标记一个刻度//保存坐标系painter.save();//算出平移点 // 弧度 = 角度*3.1415/180int delX = qCos(qDegreesToRadians(210-angle*i))*r;//QT中sin、cos认的是弧度int delY = qSin(qDegreesToRadians(210-angle*i))*r;//qDegreesToRadians - 角度转弧度//平移坐标系painter.translate(QPoint(delX,-delY));//旋转坐标系:painter.rotate(-120+angle*i);//angle=4,30*4=120,实参是0,120//写上文字painter.drawText(-25,-25,50,30,Qt::AlignCenter,QString::number(i*4));//恢复坐标系painter.restore();}}
达到效果
封装整理代码结构:
widget.h
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();protected:void paintEvent(QPaintEvent *event);private:Ui::Widget *ui;QTimer *timer;int currentValue; //实现指针移动int mark = 0; // 控制指针的移动方向int startAbgle; // 设置起始角度double angle;void initCanvas(QPainter& painter);void drawMiddleCircle(QPainter& painter,int radius);void drawCurrentSpeed(QPainter& painter);void drawScale(QPainter& painter,int radius);void drawScaleText(QPainter& painter,int radius);void drawPointLine(QPainter &painter,int length);void drawSpeedPie(QPainter& painter,int radius);void startSpeed();
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include "ui_widget.h"#include <QPainter>
#include <QTimer>
#include <QtMath>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);startAbgle = 150; // 设置起始角度为150startSpeed();}Widget::~Widget()
{delete ui;
}void Widget::initCanvas(QPainter& painter)
{//设置抗锯齿painter.setRenderHints(QPainter::Antialiasing,true);//设置黑色的背景色painter.setBrush(Qt::black); // 设置 黑色的画刷painter.drawRect(rect());//坐标系,平移到中心painter.translate(rect().center());}void Widget::drawMiddleCircle(QPainter &painter,int radius)
{//画小圆painter.setPen(QPen(Qt::white,4)); //设置白色的画笔painter.drawEllipse(QPoint(0,0),60,60);
}//画当前速度
void Widget::drawCurrentSpeed(QPainter &painter)
{//显示当前速度值:painter.setFont(QFont("华文宋体",15));painter.drawText(QRect(-60,-60,120,120),Qt::AlignCenter,QString::number(currentValue));}// 画出当前刻度
void Widget::drawScale(QPainter &painter,int radius)
{//保存原点:painter.save(); // 三点钟方向//画刻度://1.算出一个刻度需要的角度 270 度分成 50份angle = 240*1.0/60; //需要先转为double类型,否则销售几乎部分会被吞掉造成误差//2.设置起始角度painter.rotate(startAbgle); // 从135度开始//设置字体样式:// painter.setFont(QFont("华文宋体",8));//3.分类讨论 画出所有刻度for(int i=0;i<=60;++i){//包括0- 一共有61根刻度线if(i%5 == 0){ // 被5 整除进一步细分表盘//画出一个长刻度painter.drawLine(radius-20,0,radius-3,0);}else{//画出一个长刻度painter.drawLine(radius-10,0,radius-3,0);}painter.rotate(angle);//选择angle的角度准备去画下一个刻度}}// 写刻度文字
void Widget::drawScaleText(QPainter &painter, int radius)
{int r = radius-43;painter.restore();for(int i=0;i<=60;++i){if(i%5 == 0){ // 每5格标记一个刻度//保存坐标系painter.save();//算出平移点 // 弧度 = 角度*3.1415/180int delX = qCos(qDegreesToRadians(210-angle*i))*r;//QT中sin、cos认的是弧度int delY = qSin(qDegreesToRadians(210-angle*i))*r;//qDegreesToRadians - 角度转弧度//平移坐标系painter.translate(QPoint(delX,-delY));//旋转坐标系:painter.rotate(-120+angle*i);//angle=4,30*4=120,实参是0,120//写上文字painter.drawText(-25,-25,50,30,Qt::AlignCenter,QString::number(i*4));//恢复坐标系painter.restore();}}}// 画指针
void Widget::drawPointLine(QPainter &painter,int length)
{//画指针 --> 线//先恢复到之前保存的原点:painter.restore();painter.save(); // 接着保存原点// 通过定时器去改变currentValue的值,去控制指针的移动painter.rotate(startAbgle+angle*currentValue); // 进行坐标系偏移painter.drawLine(60,0,height()/2-20-38,0); // 58
}//画扇形
void Widget::drawSpeedPie(QPainter &painter, int radius)
{painter.restore();QRect rentangle(-radius,-radius,radius*2,radius*2);painter.setPen(Qt::NoPen);painter.setBrush(QColor(255,128,64,150));painter.drawPie(rentangle,(-startAbgle)*16,-angle*currentValue*16);
}void Widget::startSpeed()
{timer = new QTimer(this);currentValue = 0;connect(timer,&QTimer::timeout,[=](){if(mark == 0){currentValue++;if(currentValue >= 60)mark = 1;}else if(mark ==1){currentValue--;if(currentValue <= 0)mark = 0;}update(); // 触发绘图事件});timer->start(30);
}void Widget::paintEvent(QPaintEvent *event)
{QPainter painter(this);// 初始化画布initCanvas(painter);//不用画大圆了,用刻度尺去表出框架即可//painter.drawEllipse(QPoint(0,0),height()/2,height()/2);//画出中间的小圆drawMiddleCircle(painter,60);//画出当前速度drawCurrentSpeed(painter);//画刻度drawScale(painter,height()/2);//写刻度文字:drawScaleText(painter,height()/2);// 画指针drawPointLine(painter,height()/2-58);//画扇形drawSpeedPie(painter,height()/2);}
指针样式美化
优化后的指针API
// 画指针
void Widget::drawPointLine(QPainter &painter,int length)
{//画指针 --> 线//先恢复到之前保存的原点:painter.restore();painter.save(); // 接着保存原点// 通过定时器去改变currentValue的值,去控制指针的移动// painter.drawLine(60,0,height()/2-20-38,0); // 58//指针样式美化:painter.setRenderHint(QPainter::Antialiasing,true);painter.setBrush(Qt::white);painter.setPen(Qt::NoPen);//painter.translate(rect().center());static const QPointF points[4] = {QPointF(0,0),QPointF(0,15.0),QPointF(220.0,1.1),QPointF(220.0,-1.1)};//给指针弧度偏移 --> 让指针转动起来painter.rotate(startAbgle+angle*currentValue); // 进行坐标系偏移painter.drawPolygon(points, 4);}
效果演示
可以看到我们投票通过画多边形的方式对指针进行了美化
设置高速刻度为红色
优化刻度API
void Widget::drawScale(QPainter &painter,int radius)
{//保存原点:painter.save(); // 三点钟方向//画刻度://1.算出一个刻度需要的角度 270 度分成 50份angle = 240*1.0/60; //需要先转为double类型,否则销售几乎部分会被吞掉造成误差//2.设置起始角度painter.rotate(startAbgle); // 从135度开始//设置字体样式:// painter.setFont(QFont("华文宋体",8));//3.分类讨论 画出所有刻度for(int i=0;i<=60;++i){//包括0- 一共有61根刻度线if(i>=40){ // 时速160 = 40*4 认定为高速painter.setPen(QPen(Qt::red,5)); //将高速速设定为红色}if(i%5 == 0){ // 被5 整除进一步细分表盘//画出一个长刻度painter.drawLine(radius-20,0,radius-3,0);}else{//画出一个长刻度painter.drawLine(radius-10,0,radius-3,0);}painter.rotate(angle);//选择angle的角度准备去画下一个刻度}}
效果演示
//注意我这里设置了字体格式:
QFont font("Arial",13);font.setBold(true); // 设置粗体painter.setFont(font);
速度显示优化
给内圈画上黑色
void Widget::drawEllispseInnerBlack(QPainter &painter, int radius)
{painter.setBrush(Qt::black);painter.drawEllipse(QPoint(0,0),radius,radius);
}
优化速度显示文本格式
//画当前速度
void Widget::drawCurrentSpeed(QPainter &painter)
{painter.setPen(Qt::white);//显示当前速度值:QFont font("Arial",30);font.setBold(true);painter.setFont(font);painter.drawText(QRect(-60,-60,120,70),Qt::AlignCenter,QString::number(currentValue));QFont font2("Arial",13);font2.setBold(true);painter.setFont(font2);painter.drawText(QRect(-60,-60,120,160),Qt::AlignCenter,"Km/h");}
调整绘画顺序
void Widget::paintEvent(QPaintEvent *event)
{QPainter painter(this);// 初始化画布initCanvas(painter);//不用画大圆了,用刻度尺去表出框架即可//painter.drawEllipse(QPoint(0,0),height()/2,height()/2);//画出中间的小圆drawMiddleCircle(painter,60);//画刻度drawScale(painter,height()/2);//写刻度文字:drawScaleText(painter,height()/2);// 画指针drawPointLine(painter,height()/2-58);//画扇形drawSpeedPie(painter,height()/2);// 画黑色内圈drawEllispseInnerBlack(painter,80);//画出当前速度 -- 放正在画黑的下面,要设置在黑圈的图层下drawCurrentSpeed(painter);}
效果演示
实现内环发光圈:
内环发光效果API
void Widget::drawEllispseInnerBShine(QPainter &painter, int radius)
{// 径向 渐变实现QRadialGradient radialGradient(0,0,radius);radialGradient.setColorAt(0.0,QColor(255,0,0,200));radialGradient.setColorAt(1.0,QColor(0,0,0,100));painter.setBrush(radialGradient);painter.drawEllipse(QPoint(0,0),radius,radius);
}
插入位置
效果演示
实现外环发个圈
外环发光效果API
// 画外围发光圈
void Widget::drawEllispseOutterBShine(QPainter &painter, int radius)
{painter.restore();QRect rentangle(-radius,-radius,radius*2,radius*2);painter.setPen(Qt::NoPen);//渐变色处理外环光亮QRadialGradient radialGradient(0,0,radius);radialGradient.setColorAt(1,QColor(255,0,0,200));radialGradient.setColorAt(0.97,QColor(255,0,0,120));radialGradient.setColorAt(0.9,QColor(0,0,0,0));radialGradient.setColorAt(0,QColor(0,0,0,0));painter.setBrush(radialGradient);painter.drawPie(rentangle,(-150)*16,-angle*60*16);
}
插入位置
实现效果
绘制汽车logo
绘制汽车logo的API
//需要先添加资源文件
void Widget::drawLogo(QPainter &painter, int radius)
{QRect rectangle(-65,radius*0.38,130,50);painter.drawPixmap(rectangle,QPixmap(":/C:/Users/31472/Desktop/Images/qi_che_biao_pan/lu_hua.png"));}
插入位置
实现效果
deBug及微调
bug1: restore()和 save() 没有配对使用
处理手段: 把多余的restore()去掉
bug2:中间显示的速度不匹配
处理:
这样修改后得到的速度就是实际值