日志

Qt自定义控件之仪表盘2--QPaint绘制仪表盘

 来源    2020-08-01    0  

0、前言

    前面一篇文章写道了仪表盘的特点,实现了一个贴图的仪表盘,属于低配版本的仪表盘。
    主要是有任何改动时候就需要重新设计图片,不能适配不同控件大小,即使让它自由拉伸,但仪表盘放大缩小时候显示效果会变差。这篇文章设计了一个自己绘制的仪表盘,有背景表盘,刻度线、刻度值,指针,以及动态运行效果。

1、demo顶层设计

    设计2个控件,1个widget提升为Mydial仪表盘控件,一个滑动条控件,来测试仪表盘指针旋转效果用。

代码调用,绑定滑动条信号到仪表盘的槽函数即可。
#include "widget.h"
#include "ui_frmwidget.h"
#include <QDebug>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    connect(ui->horizontalSlider, &QSlider::valueChanged, ui->dial, &MyDial::valueChanged);
}

Widget::~Widget()
{
    delete ui;
}

2、绘制仪表盘

绘制背景图,绘制表盘圆圈。

void MyDial::drawBg(QPainter *painter)
{
    int r = radius;
    painter->save();
    painter->setPen(Qt::NoPen);
    painter->setBrush(QColor(172, 172, 172));
    painter->drawEllipse(-r, -r, r * 2, r * 2);

    r =  radius * 0.9;
    painter->setBrush(QColor(40, 40, 40));
    painter->setPen(Qt::NoPen);
    painter->drawEllipse(-r, -r, r * 2, r * 2);
    painter->restore();
}

绘制刻度线,模仿手表表盘逢5个数值后刻度使用加粗长线表示。

刻度画图有2中典型做法。

方法1:每次旋转后,计算坐标角度,然后使用sin和cos得到2个坐标点,绘制这2个点之间连接线。

方法2:每次坐标轴旋转固定角度,那么x轴就和刻度线垂直了,x为0;y轴和刻度线重合,只计算y轴上的距离就是坐标点,省去了计算三角函数的工作量。

void MyDial::drawDial(QPainter *painter)
{
    int r = radius*0.85;
    double lineWidth = 1;
    painter->save();

    painter->rotate(Angle);
    /*
    为什么旋转?
    如果不旋转画笔的坐标轴,那么每次画的时候需要按照角度来重新计算,x=r*cos,y=r*sin. 计算复杂
    但是如果旋转坐标轴,那么首次旋转angle角度,则y轴和第一条斜线重合,x=0,只需要计算y。
    画100条线,就是分100份来表示进度。每次旋转的角度=360-(起始角度*2--分左右)/100
    */
    double rotate = (double)(360 - (Angle * 2)) / 100;

    for (int i = 0; i <= 100; i++) {
        QColor color = QColor(84, 84, 84);
        if(i>80) color = QColor(250, 0, 0);
        if((i % 10) == 0)
        {
            painter->setPen(QPen(color, 1.3*lineWidth));
            painter->drawLine(0, r, 0, r / 1.2);
        }
        else if((i % 2) == 0)
        {
            painter->setPen(QPen(color, 1*lineWidth));
            painter->drawLine(0, r, 0, r / 1.1);
        }
        painter->rotate(rotate);
    }

    painter->restore();
}

 绘制刻度值。逢5个点绘制一个刻度值,每次跳跃一个大刻度,计算出对应的坐标位置。但是数字长度和宽度会影响显示效果,所以要按照字体计算数字的长度和宽度,然后修正显示的起点位置。

void MyDial::drawScaleNum(QPainter *painter)
{
    painter->save();

    qDebug()<< "drawText";
    int r = (int)(radius*0.6);

    painter->setFont(QFont("Arial", 13));
    painter->setPen(QPen(QColor(255,255,255)));
    QFontMetricsF fm = QFontMetricsF(painter->font());

    int gap = (360-Angle*2) / 10;
    for(int i=0; i<=10; i+=1)
    {
        int angle = 90+Angle+gap*i;  //角度,10格子画一个刻度值

        float angleArc =( angle % 360) * 3.14 / 180; //转换为弧度
        int x = (r)*cos(angleArc);
        int y = (r)*sin(angleArc);

        QString speed = QString::number(i);
        int w = (int)fm.width(speed);
        int h = (int)fm.height();
        x = x - w/2;
        y = y + h/4;

        qDebug()<< "x:"<<x<<" y:"<<y;
        //painter->drawPoint(QPointF(x, y));
        painter->drawText(QPointF(x, y),speed);
    }
    painter->restore();
}

绘制指针。

绘制指针有2种典型方法:

方法1:按照旋转角度计算指针坐标点,主要是终点的坐标和角度。先把指针按照一条线来绘制,然后再圆心位置画垂直相交的线,得到2个点,用这2个点和指针终点构成一个三角形,绘制出指针形状。

方法2:先在圆心绘制一个三角形,然后使用旋转角度方式让其转到对应位置即可,免去了计算坐标和三角函数。

void MyDial::drawIndicator(QPainter *painter)
{
    painter->save();
    QPolygon pts;
    int r = radius*0.6;
    pts.setPoints(3, -2, 0, 2, 0, 0, r);
    double degRotate =Angle +  (360.0 - Angle - Angle) / 100 * percent;

    //画指针
    painter->rotate(degRotate);
    QRadialGradient haloGradient(0, 0, 60, 0, 0);  //辐射渐变,内部填充颜色
    haloGradient.setColorAt(0, QColor(100, 100, 100));
    haloGradient.setColorAt(1, QColor(250, 50, 50)); //red
    painter->setPen(QColor(250, 150, 150)); // 边框颜色
    painter->setBrush(haloGradient);
    painter->drawConvexPolygon(pts);
    painter->restore();

    // 画中心圆圈
    QRadialGradient radial(0, 0, 14);  //渐变
    radial.setColorAt(0.0, QColor(100, 100, 100));
    radial.setColorAt(1.0, QColor(250, 50, 50));
    painter->setPen(Qt::NoPen);  //填满没有边界
    painter->setBrush(radial);
    painter->drawEllipse(-7, -7, 14, 14);

    painter->restore();
}

绘制动态速度值,动态数值。这一步比较简单,就是在垂直方向绘制一行文本即可。

void MyDial::drawText(QPainter *painter)
{
   painter->save();

   painter->setFont(QFont("Arial", 10));
   painter->setPen(QPen(QColor(255,255,255)));
   QFontMetricsF fm = QFontMetricsF(painter->font());
   QString speed = QString::number(percent) + " km/h";
   int w = (int)fm.width(speed);
   int h = (int)fm.height();
   painter->drawText(QPointF(-w/2, (int)(0.5*radius)),speed);
   painter->restore();
}

通过滑动条触发valueChanged。

void MyDial::valueChanged(int value)
{
    this->percent = value;
    update();
}

进一步触发重绘动作。

void MyDial::paintEvent(QPaintEvent *)
{
    int width = this->width();
    int height = this->height();

    //绘制准备工作,启用反锯齿,平移坐标轴中心,等比例缩放
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.translate(width / 2, height / 2);

    int side = qMin(width, height);
    painter.scale(side / 200.0, side / 200.0);

    //绘制最外框圆形背景
    drawBg(&painter);
     //绘制刻度
     drawDial(&painter);
     //绘制刻度数值
     drawScaleNum(&painter);
     //绘制指针
     drawIndicator(&painter);
     //绘制表盘上文本当前值
     drawText(&painter);
}

 3、作品效果展示

 4、参考文档

1、Qt编写自定义控件1-汽车仪表盘

https://www.cnblogs.com/feiyangqingyun/p/10739099.html

2、Qt总结之八:绘制仪表盘

https://blog.csdn.net/Aidam_Bo/article/details/85266798

 3、Qt自定义控件 -- 仪表盘01

https://blog.csdn.net/pingis58/article/details/82150237

尊重技术文章,转载请注明!

Qt自定义控件之仪表盘2--QPaint绘制仪表盘

https://www.cnblogs.com/pingwen/p/13416933.html

相关文章
Qt自定义控件大全(一)云台仪表盘控件
日志做过安防视频监控的同学都清楚,在视频监控系统软件上都可以看到一个云台控制区域,可以对球机进行下下左右等八个方位的运动控制,还可以进行复位,一般都是美工作图好,然后贴图的形式加入到软件中,好处是程序简单 ...
C# GDI绘制仪表盘(纯代码实现)
日志首先来个金属仪表盘图 金属仪表盘.车载仪表盘 源代码下载 纯代码实现GDI绘制仪表盘,效果在代码下面. public partial class HalfDashboardUc : UserContr ...
qt – 根据样式表伪状态值绘制自定义QWidget
问答我有一个自定义QWidget(实际上,派生自QAbstractButton),我必须实现自己的paintEvent.如何使用样式表信息? 例如,假设某人定义了以下适用于(直接或通过继承)的样式表到我的 ...
1
c – 从Qt中的多个线程绘制
问答我正在Qt中编写一个程序,它运行10个工作线程来计算空间中物体的轨迹.他们还必须画出物体的路径.我有一个"Body"类派生QGraphicsEllipseItem,它有一个QPai ...
1
Qt编程 基于QWT的曲线绘制及图例显示操作——有样点的实现功能
日志  在<QWT在QtCreator中的安装与使用>一文中,我们完成了QWT的安装,这篇文章我们讲讲基础曲线的绘制功能.      首先,我们新建一个Qt应用程序,然后一路默认即可.这时,你 ...
2
QT下过多点的曲线绘制
日志绘制过多点的曲线意义重大.但通过试验,QT的PainterPath不是很如意.当多段曲线围成一个区域时,PainterPath内并不包含该区域的所有面积,只包含曲线和其弦构成的面积. 为了解决这一问题 ...
1
Android自定义控件7--自定义开关--绘制界面内容
日志本文实现全自定义控件--自定义开关 本文地址:https://www.cnblogs.com/wuyudong/p/5922316.html,转载请注明源地址. 自定义开关 (View),本文完成下面 ...
qt自定义控件
日志一,首先新建一个lib工程, 例如:spprogressbar spprogressbar.pro CONFIG += plugin debug_and_release TARGET = $$qtLi ...
QT自定义控件系列(二) --- Loading加载动画控件
日志本系列主要使用Qt painter来实现一些基础控件.主要是对平时自行编写的一些自定义控件的总结. 为了简洁.低耦合,我们尽量不使用图片,qrc,ui等文件,而只使用c++的.h和.cpp文件. 由于 ...
Qt自定义控件系列(一) --- 圆形进度条
日志本系列主要使用Qt painter来实现一些基础控件.主要是对平时自行编写的一些自定义控件的总结. 为了简洁.低耦合,我们尽量不使用图片,qrc,ui等文件,而只使用c++的.h和.cpp文件. 由于 ...
2
Qt之图形(简笔画-绘制卡通蚂蚁)
日志简述 关于简笔画的介绍很多,有动物.水果.蔬菜.交通工具等,通常会对绘制一步步进行拆分.组合.然后绘制为我们想要的结果. 下面来介绍另外的一个种类:昆虫类-卡通蚂蚁. 绘制 效果 具体的效果如下所示, ...
Qt之图形(简笔画-绘制漂亮的西瓜)
日志简述 Summer is coming-我们呢,为大家准备了丰盛的佳果-西瓜,清爽解渴,甘味多汁. 一笔一划学简笔画,分分钟让你掌握一门新技能,下面我们来绘制一个"盛夏之王"-西瓜 ...
Qt编写自定义控件54-时钟仪表盘
日志一.前言 这个控件没有太多的应用场景,主要就是练手,论美观的话比不上之前发过的一个图片时钟控件,所以此控件也是作为一个基础的绘制demo出现在Qt源码中,我们可以在Qt的安装目录下找到一个时钟控件的绘 ...
Qt编写自定义控件51-可输入仪表盘
日志一.前言 这个控件是近期定制的控件,还是比较实用的控件之一,用户主要是提了三点需求,一点是切换焦点的时候控件放大突出显示,一点是可直接输入或者编辑值,还有一点是支持上下键及翻页键和鼠标滚轮来动态修改值 ...
1
Qt编写自定义控件50-迷你仪表盘
日志一.前言 这个控件取名叫迷你仪表盘,是以为该控件可以缩小到很小很小的区域显示,非常适合小面积区域展示仪表数据使用,还可以手动触摸调节进度,是我个人觉得最漂亮小巧的一个控件.初次看到类似的控件是在一个音 ...
Qt编写自定义控件49-飞机仪表盘
日志一.前言 飞行仪表是测定和表示飞机数据的工具,飞机中必不可少的一部分,飞行员根据飞行仪表表示的数据才能正确地做出判断.一般飞机仪表包括高度表+空速表+垂直速率表+姿态仪+航向指示表+转弯协调表. 这次 ...
1
Qt编写自定义控件44-天气仪表盘
日志一.前言 天气仪表盘控件是所有控件中唯一一个使用了svg矢量图的控件,各种天气图标采用的矢量图,颜色变换采用动态载入svg的内容更改生成的,其实也可以采用图形字体来做,本次控件为了熟悉下svg在Qt中 ...
1
Qt编写自定义控件31-面板仪表盘控件
日志一.前言 在Qt自定义控件中,仪表盘控件是数量最多的,写仪表盘都写到快要吐血,可能是因为各种工业控制领域用的比较多吧,而且仪表盘又是比较生动直观的,这次看到百度的echart中有这个控件,所以也来模仿 ...
1
Qt编写自定义控件21-圆弧仪表盘
日志一.前言 圆弧仪表盘在整个自定义控件大全中也稍微遇到了技术难点,比如背景透明,如果采用以前画圆形画扇形的方式绘制,肯定很难形成背景透明,需要用到切割,最后换了一种绘制方法,采用绘制圆弧的方式,即使用d ...
Qt编写自定义控件15-百分比仪表盘
日志前言 百分比仪表盘,主要的应用场景是展示销售完成率.产品合格率等,也可以作为一个进度百分比展示,可以独立设置对应的标题文字,标题文字的颜色和整体的颜色都可以单独设置,建议设置成统一的风格,这样会显得更 ...
1