QT绘制简易表盘
1、简介
最近学习了一下QT,熟悉了一段时间后发现它的功能还是挺强大的,同时也比较方便用户上手去使用。现在就基于最近学习的内容,实现一个简易的带指针旋转功能的表盘。文中表盘的实现是基于QT的QPainter类中的绘图方法,同时外加QT的定时器设计完成的。效果上肯定没有贴图片那么美观,不过两者的设计思想是基本一样的,这里的设计方法可以提供给你一个不错的参考。
2、设计思路
在讲解设计思路前还是先来看下绘制的表盘所实现的效果吧!后面对实现效果进行一步步拆解来讲解,这样或许会更加直观,更便于理解。
我们先不去考虑指针旋转这一动态过程实现,可以将表盘分解析为3个组成部分,表盘的外形轮廓、指针和显示的当前速度的数值。外形轮廓由一个圆弧和一些指示刻度组成,它的绘制肯定要使用QT中的画圆弧的函数、画线函数还有显示文本函数。指针是一个不规则的多边形,它的绘制会用到QT中的绘制多边形的函数。显示当前速度值比较简单些,直接使用显示文本函数绘制。
有了静态部分的基础,现在开始考虑指针的动态旋转过程和旋转过程中的渐变效果是如何实现的。指针旋转的角度应该和当前的转速相互对应,当前转速改变时,会根据新的转速计算出当前指针位于什么角度的位置,然后可以调用QT的旋转角度函数让多边形指针旋转到这个位置。旋转的渐变效果其实是通过绘制扇形实现的,要绘制扇形的角度和指针旋转的角度是一样,由于绘制的扇形的内部的着色采用了颜色的线性内插,所以不同的角度显示的颜色程度不同,因此给人以渐变的效果。
转速的周期改变是在定时器中完成的,构造函数中初始化一个周期定时器,当定时器时间超时,根据当前转速的状态(上行还是下行),确定让转速自增1还是自减1。转速改变时,调用函数让界面进行重新绘制。
3、核心函数
所用到的绘制函数都是QPainter类中的方法, QPainter可以理解成是个画家,这个画家有很多种绘制图形的方法,它可以在所以继承QPaintDevice的类上进行绘制。
绘制多边形:
drawPolygon
QT中drawPolygon有很多重载版本,要传入的参数一般就是要指定绘制多边形的所有顶点位置。
绘制圆弧:
drawArc
同理,QT中也有很多drawArc的重载版本。它传入的参数比较特殊,QT中的绘制圆弧是在一个正方形中操作的,要传入的是正方形区域的大小,绘制圆弧的圆心默认是在传入正方形区域中心。除此之外还需要指定要绘制圆弧的起始角度和跨越的角度,它传入是值是实际角度*16。 当传入的角度值为正,表示逆时针绘制圆弧,角度值为负,表示顺时钟绘制圆弧。
绘制扇形:
drawPie
绘制扇形和绘制圆弧的参数类似,可参考绘制圆弧。
QPainter坐标转换:
translate
如执行painter.translate(100, 100),后续绘制的参考坐标变成了相对100, 100位置而言的。执行painter.drawLine(0, 0, 0, 20),实际绘制直线的两端点是(100, 100)和(100, 120)
旋转:
ratate
坐标转换和旋转过程可参考下图:
保存和恢复QPainter状态:
save
restore
save保存当前QPainter状态(即当前对QPainter的设置)到堆栈,restore恢复之前保存的状态。这两个方法在QPainter绘图中很有用,详细可参考后面代码。
4、代码实现
先从定时器函数函数来看,当构造函数中设置的定时器超时,会产生定时器事件,timerEvent被自动调用
void Widget::timerEvent(QTimerEvent *e)
{
int timerId = e->timerId(); if(this->time_id == timerId) {
if(this->status == 0) {
this->speed += 1;
if(this->speed >= 180)
this->status = 1;
}else {
this->speed -= 1;
if(this->speed <= 0)
this->status = 0; } this->update();
}
}
判断当前转速是处于上行还是下行状态,根据转速所处的状态修改转速。然后调用this->update(), 该函数会产生Widget类中的重绘事件,paintEvent函数被执行。
painteEvent函数内容如下:
void Widget::paintEvent(QPaintEvent *event)
{
qreal angle; angle = (qreal)270 / (180-1); QPainter painter(this); painter.translate(width()/2, height()/2); drawFrame(&painter, angle); //① drawPointer(&painter, angle); //② drawSpeed(&painter); //③
}
① 绘制仪表盘圆弧形状的外框
② 根据转速大小,计算当前指针所在的角度,然后绘制指针和产生渐变效果的扇形
③ 显示当前转速值
drawFrame函数
void Widget::drawFrame(QPainter *painter, qreal angle)
{
painter->save(); painter->setBrush(QBrush(QColor(0, 255, 0, 255), Qt::SolidPattern));
painter->drawArc(-200, -200, 400, 400, -135*16, -270*16); //① painter->restore(); for(int i = 0; i < 180; i++) { //②
painter->save(); painter->rotate(-225 + i * angle); if(i % 10 == 0) {
painter->drawLine(180, 0, 200, 0);
}else {
painter->drawLine(190, 0, 200, 0);
} painter->restore();
} painter->save(); for(int i = 0; i < 9; i++) { //③ int xTextPos = 180 * qCos((225 - i * 15)*3.14/180);
int yTextPos = -180 * qSin((225 - i * 15)*3.14/180);
painter->drawText(xTextPos+5, yTextPos+10, QString::number(i * 10));
painter->drawText(-xTextPos-25, yTextPos+10, QString::number((18 - i) * 10));
}
painter->drawText(-10, -165, "90"); painter->restore();
}
① 绘制表盘的外形圆弧
② 绘制圆弧上的刻度信息
③ 绘制表盘外形的刻度旁边的数值,这里利用了圆的对称性
drawPointer函数
void Widget::drawPointer(QPainter *painter, qreal angle)
{
QPoint point[4] = {
QPoint(0, 10),
QPoint(-10, 0),
QPoint(0, -170),
QPoint(10, 0),
}; painter->save(); QLinearGradient linear; //①
linear.setStart(-200, -200);
linear.setFinalStop(200, 200);
linear.setColorAt(0, QColor(0, 255, 255, 0));
linear.setColorAt(1, QColor(0, 255, 255, 255));
painter->setPen(Qt::NoPen);
painter->setBrush(linear);
painter->drawPie(-200, -200, 400, 400, 225 * 16, -(angle * this->speed) * 16); painter->restore(); painter->save(); painter->setBrush(QBrush(QColor(0, 0, 0, 255), Qt::SolidPattern));
painter->rotate(-135 + this->speed * angle);
painter->drawPolygon(point, 4); //② painter->restore();
}
① 根据当前速度计算扇形区域的大小,绘制渐变扇形
② 根据当前速度计算指针所要在的位置,旋转指针到该位置
drawSpeed函数
void Widget::drawSpeed(QPainter *painter)
{
painter->save(); painter->setPen(QColor("#0"));
// 绘制速度
QFont font("Times", 10, QFont::Bold);
font.setBold(true);
font.setPixelSize(66);
painter->setFont(font);
painter->drawText(-60, 100, 120, 92, Qt::AlignCenter, QString::number(speed));
painter->restore();
}
drawSpeed函数在指定位置,使用指定颜色字体,显示当前速度
5、小结
到此,模拟仪表盘的实现讲解完毕了,这也算对这几天QT的学习做了一个小小的总结。从使用过程中可以感受到使用QT进行图形界面的设计,软件编写上还是比较灵活的。QT的GUI功能非常很强大,它提供的接口函数很多,但想要都用好的确很难,平时还需要多看看QT官方文档中的解释和提供的demo。
完整代码


#include "widget.h" #include <QPainter>
#include <QBrush>
#include <QLabel>
#include <QTimerEvent>
#include <QLinearGradient>
#include <QFont> #include <QtMath> Widget::Widget(QWidget *parent)
: QWidget(parent)
{
resize(800, 480);
setWindowTitle("模拟仪表盘"); this->speed = 0;
this->status = 0; this->time_id = this->startTimer(50);
} Widget::~Widget()
{
} void Widget::paintEvent(QPaintEvent *event)
{
qreal angle; angle = (qreal)270 / (180-1); QPainter painter(this); painter.translate(width()/2, height()/2); drawFrame(&painter, angle); drawPointer(&painter, angle); drawSpeed(&painter);
} void Widget::drawFrame(QPainter *painter, qreal angle)
{
painter->save(); painter->setBrush(QBrush(QColor(0, 255, 0, 255), Qt::SolidPattern));
painter->drawArc(-200, -200, 400, 400, -135*16, -270*16); painter->restore(); for(int i = 0; i < 180; i++) {
painter->save(); painter->rotate(-225 + i * angle); if(i % 10 == 0) {
painter->drawLine(180, 0, 200, 0);
}else {
painter->drawLine(190, 0, 200, 0);
} painter->restore();
} painter->save(); for(int i = 0; i < 9; i++) { int xTextPos = 180 * qCos((225 - i * 15)*3.14/180);
int yTextPos = -180 * qSin((225 - i * 15)*3.14/180);
painter->drawText(xTextPos+5, yTextPos+10, QString::number(i * 10));
painter->drawText(-xTextPos-25, yTextPos+10, QString::number((18 - i) * 10));
}
painter->drawText(-10, -165, "90"); painter->restore();
} void Widget::drawPointer(QPainter *painter, qreal angle)
{
QPoint point[4] = {
QPoint(0, 10),
QPoint(-10, 0),
QPoint(0, -170),
QPoint(10, 0),
}; painter->save(); QLinearGradient linear;
linear.setStart(-200, -200);
linear.setFinalStop(200, 200);
linear.setColorAt(0, QColor(0, 255, 255, 0));
linear.setColorAt(1, QColor(0, 255, 255, 255));
painter->setPen(Qt::NoPen);
painter->setBrush(linear);
painter->drawPie(-200, -200, 400, 400, 225 * 16, -(angle * this->speed) * 16); painter->restore(); painter->save(); painter->setBrush(QBrush(QColor(0, 0, 0, 255), Qt::SolidPattern));
painter->rotate(-135 + this->speed * angle);
painter->drawPolygon(point, 4); painter->restore();
} void Widget::drawSpeed(QPainter *painter)
{
painter->save(); painter->setPen(QColor("#0"));
// 绘制速度
QFont font("Times", 10, QFont::Bold);
font.setBold(true);
font.setPixelSize(66);
painter->setFont(font);
painter->drawText(-60, 100, 120, 92, Qt::AlignCenter, QString::number(speed));
painter->restore();
} void Widget::timerEvent(QTimerEvent *e)
{
int timerId = e->timerId(); if(this->time_id == timerId) {
if(this->status == 0) {
this->speed += 1;
if(this->speed >= 180)
this->status = 1;
}else {
this->speed -= 1;
if(this->speed <= 0)
this->status = 0; } this->update();
}
}
widget.cpp


#ifndef WIDGET_H
#define WIDGET_H #include <QWidget> class Widget : public QWidget
{
Q_OBJECT public:
Widget(QWidget *parent = nullptr);
~Widget(); void paintEvent(QPaintEvent *event);
void timerEvent(QTimerEvent *e); private:
void drawFrame(QPainter *painter, qreal angle);
void drawPointer(QPainter *painter, qreal angle);
void drawSpeed(QPainter *painter); int speed;
int time_id;
int status; };
#endif // WIDGET_H
widegt.h


#include "widget.h" #include <QApplication> int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
main.cpp
QT绘制简易表盘的更多相关文章
- QT绘制饼图
QT版本:QT5.6.1 QT绘制饼图,出问题的代码如下 void DrawPieDialog::paintEvent(QPaintEvent *event) { float startAngle=0 ...
- Qt 学习之路 2(24):Qt 绘制系统简介
Qt 学习之路 2(24):Qt 绘制系统简介 豆子 2012年10月30日 Qt 学习之路 2 77条评论 Qt 的绘图系统允许使用相同的 API 在屏幕和其它打印设备上进行绘制.整个绘图系统基于Q ...
- Qt项目简易开发原理及常见问题解决
一.资源下载地址 https://www.aliyundrive.com/s/jBU2wBS8poH 本项目路径:项目->免费->QtDev 注释:为了方便qt全功能开发,QtDev中包含 ...
- Qt QBarSeries简易柱状图教程
博客园最强Qt QBarSeries简易柱状图教程 前情提要 每个人的绘图需求不同,此篇教程也是根据需求来改的.我的需求大概如下所示. 通过信号槽的方式接收signals来刷新柱状图,所以每次触发信号 ...
- canvas绘制简易时钟
时钟绘制的非常简易,但该有的都有了. 效果图如下, <!DOCTYPE html> <html> <head lang="en"> <me ...
- Qt绘制异形窗体
异形窗体即不规则窗体,一般采用png图片,一般绘制异形窗体分两步: 1.设置遮罩区 2.绘制图片 使用png图片的透明部分作为遮罩区,然后绘制图片,这样我们就看到一个只绘制了非透明部分的图形,废话 ...
- Qt 学习之路 :Qt 绘制系统简介
Qt 的绘图系统允许使用相同的 API 在屏幕和其它打印设备上进行绘制.整个绘图系统基于QPainter,QPainterDevice和QPaintEngine三个类. QPainter用来执行绘制的 ...
- qt绘制设备
# -*- coding: utf-8 -*- # python:2.x __author__ = 'Administrator' from PyQt4.QtGui import * from Py ...
- QT绘制系统简介
#3个类:QPainter,QPainterDevice 和 QPaintEngine 三个类 #qpainter用于执行绘制操作 #QPainterDevice是一个二维空间抽象,允许qpainte ...
随机推荐
- 2- 计算机的组成以及VMware使用
计算机的组成: 硬件: 处理器(CPU):I3 I5 I7 运行内存RAM(存储数据) 容量(字节为单位) 主板(总线设备) 输入输出设备(显示屏,键盘,鼠标,触目屏) 外部存储设备(硬盘,U盘,TF ...
- Xposed框架中XSharePreference的使用
本文博客地址:https://blog.csdn.net/QQ1084283172/article/details/81194406 在Xposed框架的模块编写中,通常希望我们自己写的Android ...
- Python爬虫之使用正则表达式抓取数据
目录 匹配标签 匹配title标签 a标签 table标签 匹配标签里面的属性 匹配a标签里面的URL 匹配img标签里的 src 相关文章:Linux中的正则表达式 Python中的正则表达式 实例 ...
- CVE-2012-3569:VMware OVF Tool 格式化字符串漏洞调试分析
0x01 简介 VMware OVF Tool 是一个命令行实用程序,允许您从许多 VMware 产品导入和导出 OVF 包.在 2.1.0 - 2.1.3 之间的版本中存在格式化字符串漏洞,通过修改 ...
- 手动添加导入表修改EXE功能
目标: 改动PE导入表,手工给HelloWorld增加一个功能,就是启动的时候写入一条开机启动项,C:\cmd0000000000000000000000000000.exe 实现方法: 直接在注册相 ...
- svchost服务(DLL服务)
相比于exe服务,DLL服务只需要一个dll,而且运行是通过svchost.exe来运行的,同时安装和卸载的时候需要自己手动修改相关注册表.原理及其细节就不多说了,直接上代码吧(我写的这个是创建新组然 ...
- Linux系统调用表
Linux系统调用表 记录下来,免得到处找 32位 int 0x80 %eax Name Source %ebx %ecx %edx %esx %edi 1 sys_exit kernel/exit. ...
- thymeleaf-extras-springsecurity在Spring或SpringBoot中html页面命名空间
xmlns:sec="http://www.thymeleaf.org/extras/spring-security"
- 并发容器-CopyOnWriteArrayList
并发容器一览 图源:https://time.geekbang.org/column/article/90201?utm_term=pc_interstitial_938 CopyOnWriteArr ...
- MindSpore保存与加载模型
技术背景 近几年在机器学习和传统搜索算法的结合中,逐渐发展出了一种Search To Optimization的思维,旨在通过构造一个特定的机器学习模型,来替代传统算法中的搜索过程,进而加速经典图论等 ...