运行结果:
widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include<QPainter>
#include<QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
m_wgt_mileage =new QWidget(this);
m_minSpeed=0;
m_maxSpeed=3000;
m_startAngle=150;
m_refSize=200;
m_radius=100;
m_curSpeed=0;
m_endAngle=30;
m_anglePerVel =5;
}
Widget::~Widget()
{
delete ui;
}
void Widget::paintEvent(QPaintEvent */*event*/)
{
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing); //设置反走样
float scale = qMin(width(),height());
//设置缩放比例和原点的先后顺序很重要
painter.scale(scale/(m_refSize*4),scale/(m_refSize*4));
painter.translate(m_refSize,m_refSize); //设置坐标原点
// painter.translate(m_refSize,m_refSize);
drawFrame(painter); //绘制边框
drawDividing(painter);//绘制刻度
drawNumberIndicator(painter);//绘制指示数字
drawNumberSpeed(painter);//显示数字速度
drawIndicator(painter);//绘制速度指针
m_wgt_mileage->setGeometry((width() - m_wgt_mileage->width()) / 2 + 30,height() - m_wgt_mileage->height() - 60,m_wgt_mileage->width(),m_wgt_mileage->height());
}
//绘制边框
void Widget::drawFrame(QPainter &painter)
{
painter.save(); //保存原点位置
painter.setPen(Qt::NoPen);//确保没有边框线----填满,不留边界线
QLinearGradient lg1(-m_radius,-m_radius,m_radius,m_radius);//线性渐变 渐变区域
lg1.setColorAt(0,Qt::blue); //0是停止点,用于渐变
lg1.setColorAt(1,Qt::green);
lg1.setSpread(QGradient::ReflectSpread);//渐变样式(颜色传播样式)
painter.setBrush(lg1); //画笔填充物
painter.drawEllipse(-m_radius,-m_radius,m_refSize,m_refSize);//画笔绘画,绘制一个椭圆------>画完会回到原点
//-------------画个小圆----------------//
painter.setBrush(Qt::black);
painter.drawEllipse(QPoint(0,0),90,90);//画出小圆半径
painter.restore();
}
//绘制刻度(主要用了 Qpainter::rotate)
void Widget::drawDividing(QPainter &painter)
{
painter.save();
painter.rotate(m_startAngle);//将坐标系顺时针旋转150°,到达起始位置
QPen pen(Qt::white);
painter.setPen(pen);
painter.drawLine(88,0,80,0);
int step = (m_maxSpeed - m_minSpeed) / 50; //每一个线条之间距离5
double angleStep = (360.0 - (m_startAngle - m_endAngle)) / step; //坐标系每走一步旋转的角度 360 - (开始角度 - 结束角度)/每次转的间隔
m_anglePerVel = angleStep;
for (int i = m_minSpeed; i <= m_maxSpeed; i += 50)
{
if (i >= 0){ //绘制红色
pen.setColor(Qt::red);
painter.setPen(pen);
}
if (i % 250 == 0){//粗线
pen.setWidth(2);
painter.setPen(pen);
painter.drawLine(88,0,75,0);
}else if (i % 250 == 0){//中等
pen.setWidth(1);
painter.setPen(pen);
painter.drawLine(88,0,80,0);
}else if (i % 50 == 0){ //短线
pen.setWidth(0);
painter.setPen(pen);
painter.drawLine(83,0,80,0);
}
painter.rotate(angleStep); //在之前的基础上原点坐标旋转angleStep度
}
painter.restore();
}
/**
圆点坐标:(x0,y0)
半径:r
角度:a0
则圆上任一点为:(x1,y1)
x1 = x0 + r * cos(ao * 3.14 /180 )
y1 = y0 + r * sin(ao * 3.14 /180 )
*/
//绘制数字指示
void Widget::drawNumberIndicator(QPainter &painter)
{
painter.save();//(100,100)
painter.setPen(Qt::red);
double x,y;
QFontMetricsF fm(this->font());//获取字体
painter.setFont(QFont("Arial",3));//改变显示字体、字号
painter.setPen(Qt::white);
int anglestart = 150;
int step = (m_maxSpeed - m_minSpeed)/250;
double angleStep = (360.0 - (m_startAngle - m_endAngle)) / step;
for (int i = 0; i <= 12; i++)//每隔250Km设置一个数字
{
double textWidth = fontMetrics().width("1");
double textHeight = fontMetrics().height();
qDebug()<<textWidth<<","<<textHeight;
x =0+75* cos((anglestart *3.14)/180) -textWidth/2;
y =0+75* sin((anglestart *3.14)/180)+textHeight/2;
QString value = QString::number(i*250);//设置显示数字
painter.drawText(x,y,value);
// painter.drawPoint(x,y);
anglestart+=(angleStep*1);
}
painter.restore();
}
//显示KM/H
///
/// painter::drawText
///
void Widget::drawNumberSpeed(QPainter &painter)
{
painter.save();
painter.setPen(Qt::white);
QString speed = QString("%1 km/h").arg(m_curSpeed*50);
QFontMetricsF fm(this->font());
qreal w = fm.size(Qt::TextSingleLine,speed).width(); //TextSingleLine 忽略换行符,返回给定文本中字符的大小(以像素为单位)
painter.drawText(-w/2,-20,speed); //本来想文字在0,-20,但是这样的话文字站了从头到尾巴占了(0~w,20)
painter.restore();
}
void Widget::drawIndicator(QPainter &painter)
{
painter.save();
//绘制指针
double curAngle = m_startAngle + m_curSpeed * m_anglePerVel;
painter.rotate(curAngle); //旋转坐标系
QRadialGradient haloGradient(0, 0, 60, 0, 0); //辐射渐变
haloGradient.setColorAt(0, QColor(60,60,60));
haloGradient.setColorAt(1, QColor(160,160,160)); //灰
painter.setPen(Qt::white); //定义线条文本颜色 设置线条的颜色
painter.setBrush(haloGradient);//刷子定义形状如何填满 填充后的颜色
static const QPointF points[3] = {
QPointF(0.0, 4),
QPointF(0.0, -4),
QPointF(68.0, 0),
};
painter.drawPolygon(points,3); //绘制多边形
painter.restore();
painter.save();
//绘制旋转中心
QRadialGradient rg(0,0,10);
rg.setColorAt(0.0,Qt::darkGray);
rg.setColorAt(0.5,Qt::white);
rg.setColorAt(1.0,Qt::darkGray);
painter.setPen(Qt::NoPen);
painter.setBrush(rg);
painter.drawEllipse(QPoint(0,0),10,10);
painter.restore();
}
void Widget::on_pushButton_clicked()
{
update();
if((m_curSpeed*50) == m_maxSpeed)
m_curSpeed=0;
else {
m_curSpeed++;
}
}
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
void drawFrame(QPainter &painter);
void drawNumberIndicator(QPainter &painter);
void drawDividing(QPainter &painter);
void drawNumberSpeed(QPainter &painter);
void drawIndicator(QPainter &painter);
protected:
void paintEvent(QPaintEvent *);
private slots:
void on_pushButton_clicked();
private:
Ui::Widget *ui;
QWidget *m_wgt_mileage;
qreal m_radius;
int m_minSpeed;
int m_maxSpeed;
int m_refSize;
int m_startAngle;
int m_anglePerVel;
int m_endAngle;
int m_curSpeed;
};
#endif // WIDGET_H
main.cpp
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
untitle.pro
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++11
# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp \
widget.cpp
HEADERS += \
widget.h
FORMS += \
widget.ui
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target