一、效果图


二、效果图拆解
效果图上的表盘外圈分为三个同心圆环,每个圆环的颜色不一样,造就出一种表盘突出的错觉。内部刻度线分为长刻度线和短刻度线,两种刻度线的绘制方法一样,都是两个等腰梯形合并成的复杂图形。再往圆心是表盘数字,最中间的刻度线分为时分秒针,这三个指针都带有透明度,最短的是时针,稍微长点的是分针,最长的红色指针是分针,指针的绘制方法和小刻度线的绘制方法类似,只是尾部不是梯形,而是半圆。
三、绘制过程拆解
①首先绘制表盘的外圈(看上去有点像是凸出的部分),这里实际上是由三个同心圆环组成,由于色差欺骗眼睛。三个同心圆环的绘制过程相同,都是采用QPainterPath对象计算大圆和小圆之间的差集,然后绘制这个差集。
②内部的小刻度线看上去是一头大一头小,而且看上去还比较圆滑,其实也是被眼睛欺骗了,这个小刻度线放大之后的效果如下:

实际上就是由于两个等腰梯形合并在一起的,由于效果图上的点线距离太小,所以看上去就是圆滑的。这里长短刻度线绘制方法一样,长刻度线实际就是梯形的高度更长点而已。这里的刻度线都指向圆心,在绘图的时候没有采用旋转图形,而是采用旋转坐标系实现。
③中间的数字是采用QPainter的成员函数drawText实现,后面代码详解。
④绘制表盘指针,这里指针的绘制方式和刻度线的绘制方法相同,都是采用QPainterPath组装闭合绘图路径实现的,不一样的地方是,刻度线是由两个等腰梯形组成,而指针是由一个等腰梯形和一个半圆组成的。
⑤最后是添加定时器,定时获取系统当前时间,计算当前时间的时分秒对应只针的角度,刷新界面,将指针旋转对应的角度后绘制出来。
四、绘制前准备
这里时间表盘被分为12个区间,因为一个圆对应的角度是360°,所以每个区间对应的度数是30°,每两个小刻度之间的度数是6°(这个度数在后面绘制图形是用来旋转坐标系的)。
还有一个问题就是Qt的坐标系和常规的数学坐标系不一样,它是向右为x轴,向下为y轴,所以向右为正,向下为正。
五、详细绘制过程
①准备工作,先设置对话框窗口大小,设置窗口背景颜色等,代码如下所示:

//初始化变量
hour=0;
minute=0;
second=0;
//设置窗口大小
setFixedSize(600,600);
//去掉问号
Qt::WindowFlags flags= this->windowFlags();
setWindowFlags(flags&~Qt::WindowContextHelpButtonHint);
//背景设置成白色
QPalette bgpal=palette();
bgpal.setColor(QPalette::Background,QColor(255,255,255));
setPalette(bgpal);

这里已经定义成员变量并初始化时分秒,都是double类型,为什么是double类型,下文有答案。
设置完成之后的窗口运行出来一片空白,这里就补贴效果图了。
②重载窗口的绘图函数,初始化QPainter对象,将绘图中心移动到窗口中心,设置画笔画刷等属性,代码如下所示:

//初始化画图对象
QPainter painter(this);
//绘图坐标移动到中心
int width=this->width();
int height=this->height();
painter.translate(width>>1,height>>1);
int radius=((width>height)?height:width)/2-30;
//启用反锯齿
painter.setRenderHint(QPainter::Antialiasing, true);
//取消画笔
painter.setPen(Qt::NoPen);

这一步里面初始化了一个变量radius,表盘的半径。
③绘制表盘的外圆环,这里采用的是QPainterPath计算差集,原理如下,一个大圆的路径-一个小圆的路径=一个同心圆环,绘制这个圆环即可。代码如下所示:
调用函数:

DrawCircularRing1(painter,radius,radius-4);

实现函数:

//保存绘图对象
painter.save();
//计算大小圆路径
QPainterPath outRing;
QPainterPath inRing;
outRing.moveTo(0,0);
inRing.moveTo(0,0);
outRing.addEllipse(-radius1,-radius1, 2*radius1,2*radius1);
inRing.addEllipse(-radius2,-radius2,2*radius2,2*radius2);
outRing.closeSubpath();
//设置画刷
painter.setBrush(QColor(200,200,200));
//大圆减去小圆得到圆环
painter.drawPath(outRing.subtracted(inRing));
//恢复绘图对象
painter.restore();

效果图如下所示:

③其他两个还原的实现方法相同,只是半径和颜色不同,代码如下:
调用函数:

DrawCircularRing2(painter,radius-4,radius-20);

实现函数如下:

//保存绘图对象
painter.save();
//计算大小圆路径
QPainterPath outRing;
QPainterPath inRing;
outRing.moveTo(0,0);
inRing.moveTo(0,0);
outRing.addEllipse(-radius1,-radius1, 2*radius1,2*radius1);
inRing.addEllipse(-radius2,-radius2,2*radius2,2*radius2);
outRing.closeSubpath();
//设置画刷
painter.setBrush(QColor(235,235,235));
//大圆减去小圆得到圆环
painter.drawPath(outRing.subtracted(inRing));
//恢复绘图对象
painter.restore();

调用函数:

DrawCircularRing3(painter,radius-20,radius-25);

实现函数如下:

//保存绘图对象
painter.save();
//计算大小圆路径
QPainterPath outRing;
QPainterPath inRing;
outRing.moveTo(0,0);
inRing.moveTo(0,0);
outRing.addEllipse(-radius1,-radius1, 2*radius1,2*radius1);
inRing.addEllipse(-radius2,-radius2,2*radius2,2*radius2);
outRing.closeSubpath();
//设置画刷
painter.setBrush(QColor(180,180,180));
//大圆减去小圆得到圆环
painter.drawPath(outRing.subtracted(inRing));
//恢复绘图对象
painter.restore();

效果图如下所示:

④绘制刻度线,这里直接给出代码,具体的绘制思路很简单,就是先组装好要绘制的路径(两个等腰梯形合并成一个图形),然后将绘图坐标系移动到对应点上,然后旋转对应的角度,最后绘制这个图形记录,如果需要了解具体绘制过程,可以参考我的另一篇文章:Qt自绘汽车仪表盘里面的子弹头绘制过程,写的非常详细,这里不再赘述。代码如下所示:
调用函数:

DrawScaleLine(painter,radius-35);

实现函数:

//设置画刷
painter.setBrush(QColor(100,100,100));
//组装点的路径图
QPainterPath pointPath1;
pointPath1.moveTo(-2,-2);
pointPath1.lineTo(-1,-4);
pointPath1.lineTo(1,-4);
pointPath1.lineTo(2,-2);
pointPath1.lineTo(1,8);
pointPath1.lineTo(-1,8);
QPainterPath pointPath2;
pointPath2.moveTo(-2,-2);
pointPath2.lineTo(-1,-4);
pointPath2.lineTo(1,-4);
pointPath2.lineTo(2,-2);
pointPath2.lineTo(1,20);
pointPath2.lineTo(-1,20);
//绘制25个刻度
for(int i=0;i<60;++i){QPointF point(0,0);painter.save();//计算并移动绘图对象中心点point.setX(radius*qCos(((90-i*6)*M_PI)/180));point.setY(radius*qSin(((90-i*6)*M_PI)/180));//计算并移动绘图对象的中心点painter.translate(point.x(),-point.y());//计算并选择绘图对象坐标painter.rotate(i*6);//绘制路径if(i%5){painter.drawPath(pointPath1);}else{painter.drawPath(pointPath2);}painter.restore();
}

效果图如下所示:

⑤绘制表盘数字,这个就很简单了,因为数字不需要旋转,具体绘制代码如下所示:
调用代码:

DrawDialNumber(painter,radius-70);

实现代码:

painter.setPen(QColor(100,100,100));
QFont font;
font.setFamily("SimHei");
font.setPointSize(16);
painter.setFont(font);
//绘制13个小点
for(int i=0;i<12;++i){QPointF point(0,0);painter.save();//计算并移动绘图对象中心点point.setX(radius*qCos(((60-i*30)*M_PI)/180));point.setY(radius*qSin(((60-i*30)*M_PI)/180));//计算并移动绘图对象的中心点painter.translate(point.x(),-point.y());//绘制路径painter.drawText(-15, -15, 30, 30,Qt::AlignCenter,QString::number(i+1));painter.restore();
}

效果图如下所示:

⑥绘制时针、分针、秒针。具体代码如下所示:
调用函数:

DrawHourPointer(painter,radius-150);

实现函数:

painter.setPen(Qt::NoPen);
//组装点的路径图
QPainterPath pointPath;
pointPath.moveTo(10,0);
pointPath.lineTo(1,-radius);
pointPath.lineTo(-1,-radius);
pointPath.lineTo(-10,0);
pointPath.arcTo(-10,0,20,20,180,180);
painter.save();
//计算并选择绘图对象坐标
painter.rotate(hour*30);
//设置画刷
painter.setBrush(QColor(0,0,0,200));
//绘制路径
painter.drawPath(pointPath);
painter.restore();

调用函数:

DrawMinutePointer(painter,radius-120);

实现函数:

//组装点的路径图
QPainterPath pointPath;
pointPath.moveTo(10,0);
pointPath.lineTo(1,-radius);
pointPath.lineTo(-1,-radius);
pointPath.lineTo(-10,0);
pointPath.arcTo(-10,0,20,20,180,180);
painter.save();
//计算并选择绘图对象坐标
painter.rotate(minute*6);
//设置画刷
painter.setBrush(QColor(0,0,0,200));
//绘制路径
painter.drawPath(pointPath);
painter.restore();

调用函数:

DrawSecondPointer(painter,radius-100);

实现函数:

//组装点的路径图
QPainterPath pointPath;
pointPath.moveTo(10,0);
pointPath.lineTo(1,-radius);
pointPath.lineTo(-1,-radius);
pointPath.lineTo(-10,0);
pointPath.arcTo(-10,0,20,20,180,180);
QPainterPath inRing;
inRing.addEllipse(-5,-5,10,10);
painter.save();
//计算并选择绘图对象坐标
painter.rotate(second*6);
//设置画刷
painter.setBrush(QColor(255,0,0,200));
//绘制路径
painter.drawPath(pointPath.subtracted(inRing));
painter.restore();

效果图如下:

此时三个指针重叠在一起的。为了让它出来就分开,所以需要在构造函数中,获取一下当前时间,并执行一次绘制,代码如下:

//执行一次绘图
QTime curr_time =QTime::currentTime();
second=curr_time.second();
minute=curr_time.minute()+second/60;
hour=curr_time.hour()+minute/60;

效果图如下:

⑦最后一步,为了让时间动起来,所以在界面上添加定时器,代码如下所示:

//设置定时器
startTimer(1000);

实现代码:

void Clock1::timerEvent(QTimerEvent*)
{QTime curr_time=QTime::currentTime();second=curr_time.second();minute=curr_time.minute()+second/60;hour=curr_time.hour()+minute/60;update();
}

到此,效果就和效果图中一样了,完美收工。
六、最后总结
①上面描述的是绘制的整个过程,可以根据自身需要设置不同的颜色值,在表盘上以数字方式打印当前时间等,实现不同的效果。

七、代码获取
从Git下载,地址为:https://github.com/youyicc/Clock1.git

Qt自绘时钟表盘-1相关推荐

  1. Qt实现动态时钟表盘的设计

    目录 头文件 源代码 运行结果 头文件 #ifndef MYWIDGET_H #define MYWIDGET_H#include <QWidget>#include <QPaint ...

  2. 手绘时钟的设计与实现

    手绘时钟的设计与实现 功能要求:不依赖于任何图片素材,完全基于HTML5画布API绘制时钟,并实现每秒更新的动态效果. 实现效果图: 一.界面设计 1.画布的创建 1)使用<canvas> ...

  3. [Web]Canvas手绘时钟

    这是一个手绘时钟的案例,是不是很可爱呢! <!DOCTYPE html> <html lang="en"> <head><meta cha ...

  4. QT实现绘制箱须图(盒须图)

    QT实现绘制箱须图 项目简介 项目技术 项目展示 主要源码片段解析 项目简介 显示了如何创建箱须图. 显示了如何从文件中读取非连续数据,对其进行排列并查找箱须图的中位数. 项目技术 qt5.12,Qt ...

  5. java实现时钟表盘教程方法

    本文实例为大家分享了java实现时钟表盘的具体代码,供大家参考,具体内容如下 设计并实现一个模拟时钟功能的应用程序.程序中应显示时针.分针和秒针,并同时以数字形式显示当前时间. 实现结果: 源代码如下 ...

  6. SkiaSharp 之 WPF 自绘时钟(案例版)

    SkiaSharp是一个跨平台2D图形API,用于.NET平台,基于Google's Skia Graphics库(skia.org网站). 它提供了一个全面的2D API,可以跨移动.服务器和桌面模 ...

  7. LVGL库实现的简单实时时钟表盘示例代码

    LVGL库实现的简单实时时钟表盘示例代码: #include "lvgl.h" #include <time.h>static lv_obj_t * screen; s ...

  8. Qt学习笔记-自绘时钟

    运行截图如下(时针,分针,秒针都可以动的哦): 代码如下: Widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget>name ...

  9. 使用Qt创建一个时钟

    如何用Qt制作时钟呢?下面一起来看一下吧: 首先来看一下成品图 我在网上找的好看的照片作为背景,用画板画表盘和各个指针,看起来效果挺不错. 主要代码 2.1.设置画家函数 2.2.背景部分 //添加背 ...

  10. Qt中标绘功能的实现方法对比

    使用Qt开发桌面程序,经常会有标绘的需求,一般有以下几点: 新建:圆.矩形.椭圆.文字标注,插入图像等: 编辑:指对已标绘内容的属性编辑修改功能: 删除:指对已标绘内容的删除功能: 浏览:指提供对已标 ...

最新文章

  1. python迭代器生成器装饰器
  2. 微软提出VLMo:用“模态混合专家”进行统一的视觉语言预训练!即将开源!
  3. SDOI2019R1游记
  4. python读写csv与数据库性能_使用python将csv文件写入SQL Server数据库
  5. 2015年1月微信上线原创声明功能:智能添加原创标识 转载自动注明出处
  6. 数据库接口实验--php实现--
  7. PR短视频转场预设 60个摇晃抖动效果过渡合集
  8. mysql em_Python在主体Emai中发送MySQL查询
  9. 穿山甲android对接错误码40029,空Android项目集成Cocos、穿山甲。Lua调用网络接口。...
  10. 大数据与人工智能论文作业
  11. 针对RK3328平台搭建支持KVM的Linux环境
  12. iOS 新特性实现 3DTouch 开发
  13. 二维数组与稀疏矩阵的转换
  14. 第一章 新科技革命引发产业革命
  15. 终于又可以用WLW了.
  16. 斗罗大陆CSS_204687
  17. 重学C++笔记之(十三)友元、异常和其他
  18. Python_Task09:文件与文件系统
  19. 魅族flashfire_高通平台所有黑砖(不开机)手机通用救砖方法
  20. Html-移动端与响应式

热门文章

  1. saas系统和php mysql的区别_saas模式与传统软件的区别
  2. win7旗舰版激活教程
  3. 发送短信工具类(亿美短信平台接口)
  4. ModBus那些傻傻分不清
  5. GET、POST、PUT、DELETE等用法
  6. 【软考系统架构设计师】2014年下系统架构师案例分析历年真题
  7. python正则表达式匹配数字或者逗号_将数字与正则表达式相匹配-只有数字和逗号...
  8. SGX Enable
  9. Intel SGX开发者参考书(三)—— 使用Intel SGX SDK工具(二)
  10. 特教学校计算机课,特教学校引入编程课 为听障孩子打开智能之门