一、简介

QT编写的模拟时钟,demo里的时钟只有时针和分针,在其基础上添加了秒针,构成了一个完整的时钟。能对2D绘图中坐标系统、平移变换(translate)、比例变换(scale)、旋转变换(rotate)、扭曲变换(shear)及其save()和restore()来保存和恢复坐标系的状态。

二、效果图

(1)时钟运行,秒针随系统时间移动。如图1。

三、详解

1、定时器

Clock::Clock(QWidget *parent): QWidget(parent)
{QTimer *timer = new QTimer(this);   //声明一个定时器//update()会自动产生重绘消息,调用paintEvent()connect(timer, SIGNAL(timeout()), this, SLOT(update()));  //连接信号槽,定时器超时触发窗体更新timer->start(1000);   //启动定时器setWindowTitle(tr("My Clock"));  //设置窗体名称resize(300, 300);  //设置窗体大小
}

启动一个定时器,timer->start(1000);单位是ms,每一秒中update重绘一次窗口。

2、重绘事件

(1)先确定指针的颜色和形状大小。其坐标后面再确定。

void Clock::paintEvent(QPaintEvent *event)
{//下面三个数组用来定义表针的三个顶点,以便后面的填充static const QPoint hourHand[3] = {QPoint(3, 8),QPoint(-3, 8),QPoint(0, -40)};static const QPoint minuteHand[3] = {QPoint(3, 8),QPoint(-3, 8),QPoint(0, -70)};static const QPoint secondHand[3] = {QPoint(3, 8),QPoint(-3, 8),QPoint(0, -90)};//秒针//填充表针的颜色QColor hourColor(127, 0, 127);  //分针颜色(第四个表示不透明度)QColor minuteColor(0, 127, 127, 191);QColor secondColor(127, 127, 0, 127);//...
}

(2)qMin(width(), height());获取长宽的最小值,以确保绘制的时钟是圆形的,并使用painter.scale(side / 300.0, side / 300.0);来执行比例变换,实现缩放效果,比如窗口变成600,则600/300.0放大2倍。

painter.translate(width() / 2, height() / 2);将最标原点从(0, 0)移动到窗口中心则原来的原点最标就变成(-150, -150)。

坐标变换后具体的坐标如下图2:

{int side = qMin(width(), height());  //绘制的范围(宽、高中最小值)QTime time = QTime::currentTime();   //获取当前的时间QPainter painter(this);              //声明用来绘图用的painterpainter.setRenderHint(QPainter::Antialiasing);//绘制的图像反锯齿painter.translate(width() / 2, height() / 2);//重新定位坐标起始点,把坐标原点放到窗体的中央painter.scale(side / 300.0, side / 300.0);//设定画布的边界,用窗体宽高的最小值来计算时钟的大小,防止窗体拉伸导致的时钟变形以及显示不全
}
 
 

再看秒针的坐标(-3, 8)、(3, 8)、(0, 90)即确定了秒针的具体大小和位置。变换后的圆心在屏幕的中心。

(3)在坐标(-40, 30)处画出时间,随系统一秒更新一次。

{painter.setPen(Qt::red);   //填充时针,不需要边线所以NoPenQString timeStr= QTime::currentTime().toString();     //绘制当前的时间painter.drawText(-40,30,80,30,Qt::AlignHCenter | Qt::AlignTop, timeStr);
}
 
 

(4)根据当前的时间,计算时针的移动角度6.0 * (time.minute() + time.second() / 60.0,使用rotate进行最标旋转,比如最标旋转30度如下图3所示。

painter.drawConvexPolygon(minuteHand, 3); 画出时针的三角形,如图2所示。然后painter.restore();恢复坐标到图2,不恢复的话无法确定分针的角度。

在分别计算分针的角度6.0 * (time.minute() + time.second() / 60.0)和秒针的角度6.0 * time.second()。

{//...painter.setPen(Qt::NoPen);   //填充时针,不需要边线所以NoPenpainter.setBrush(hourColor);  //画刷颜色设定painter.save();  //保存painter的状态,保存的是当前的坐标状态,如果不保存,画完之后坐标以改变不方便画下一个painter.rotate(30.0 * ((time.hour() + time.minute() / 60.0))); //将painter(的”视角“)根据时间参数转移(30° * (小时 + 分钟 / 60))painter.drawConvexPolygon(hourHand, 3);  //填充时针的区域painter.restore();//后面的跟前面的类似,分别绘制了分针和秒针,及相应的刻度painter.setPen(Qt::NoPen);painter.setBrush(minuteColor);painter.save();painter.rotate(6.0 * (time.minute() + time.second() / 60.0));  //设旋转(角度 = 6° * (分钟 + 秒 / 60))painter.drawConvexPolygon(minuteHand, 3);  //填充分针部分painter.restore();painter.setPen(Qt::NoPen);painter.setBrush(secondColor);painter.save();painter.rotate(6.0 * time.second());  //设置旋转(6° * 秒)painter.drawConvexPolygon(secondHand, 3);  //设置填充painter.restore();//...
}
 

(5)每次旋转6度,绘制长4个像素的直线,正点先不绘制,因为正点是8个像素的直线。接着绘制正点刻度和数字。不用保存画图的坐标,绘制都是旋转了360,回到了原来的最标系统中。

{   //...painter.setPen(minuteColor);for (int j = 0; j < 60; ++j) {  //循环60次,绘制表盘(其实可以从1开始,到59,提高一点效率)if ((j % 5) != 0)           //判断是否能被5整除(能被5整除表示是正点刻度,暂不绘制)painter.drawLine(0, -92, 0, -96);  //不是正点刻度,绘制长4个像素的直线painter.rotate(6.0);   //循环60次,每次旋转6度,所以不用save和restore}painter.setPen(hourColor);    //下面画表示小时的刻度,此时要用到画笔(因为要划线)for (int i = 0; i < 12; ++i) {painter.drawLine(0, -88, 0, -96);     //写上刻度数字if (i == 0)  painter.drawText(-10,-88,20,20,Qt::AlignHCenter | Qt::AlignTop,QString::number(12));else  painter.drawText(-10,-88,20,20,Qt::AlignHCenter | Qt::AlignTop,QString::number(i));painter.rotate(30.0);}
}
 

(6)最后画上中心的小黑实心圆和外圈的空心圆,主要是计算下坐标。圆心分别为2和97。

{    //... painter.setPen(Qt::NoPen);painter.setBrush(secondColor);painter.save();painter.rotate(6.0 * time.second());  //设置旋转(6° * 秒)painter.drawConvexPolygon(secondHand, 3);  //设置填充painter.restore();painter.setBrush(Qt::black);painter.drawEllipse(QPoint(0,0),2,2);painter.setBrush(Qt::NoBrush);painter.setPen(Qt::black);painter.drawEllipse(QPoint(0,0),97,97);//...
}

四、总结

(1)时分秒也可以设置成四边形的,如

 static const QPoint hourHand[4]   ={QPoint(0,10),QPoint(-1,-30),QPoint(0,-60),QPoint(1,-30)};static const QPoint minuteHand[4] ={QPoint(0,10),QPoint(-1,-40),QPoint(0,-70),QPoint(1,-40)};static const QPoint secondHand[4] ={QPoint(0,10),QPoint(-1,-60),QPoint(0,-90),QPoint(1,-60)};QColor hourColor(255,0,0);QColor minuteColor(0,127,127);QColor secondColor(0,0,255);

运行效果如下图4:

(2)解析顺序不是按代码正常顺序,请参看源码。

(3)源码已经打包上传到csdn上可登录下载(http://download.csdn.net/detail/taiyang1987912/7492657)。

(4)若需要沟通可以联系yang.ao@i-soft.com.cn

patch1

让背景框架透明,在加上移动盘面和右键退出就构成了一个比较理想的时钟(思路来自同学的程序)。

void Clock::mouseMoveEvent(QMouseEvent *event)
{if (m_pressMouse) {   //移动窗口QPoint movePos = event->globalPos();move(movePos - m_movePoint);}
}
void Clock::contextMenuEvent(QContextMenuEvent *)
{QCursor cur=this->cursor();QMenu *menu=new QMenu(this);QAction *deleteAction= new QAction(tr("关闭"), this);menu->addAction(deleteAction);connect(deleteAction, SIGNAL(triggered()), SLOT(close()));menu->exec(cur.pos());
}
void Clock::mousePressEvent(QMouseEvent *event)
{if (event->button() == Qt::LeftButton) {m_pressMouse = true;}m_movePoint = event->globalPos() - pos();   //窗口移动距离
}
void Clock::mouseReleaseEvent(QMouseEvent * event)
{m_pressMouse = false;
}

实现效果如下图5所示:(无外边框)

Qt浅谈之二:钟表(时分秒针)相关推荐

  1. C++ 浅谈之二叉搜索树

    C++ 浅谈之二叉搜索树 HELLO,各位博友好,我是阿呆

  2. IT领域标准化浅谈(二):中国IT领域标准制定工作程序

    IT领域标准化浅谈(二):中国IT领域标准制定工作程序 我国国家标准制定阶段的划分和流程如下表所示: 阶段代码 阶段名称 阶段任务 阶段成果 完成周期  主要工作 00 预阶段 提出新工作项目建议 P ...

  3. ​利息浅谈(二)——利息到底是怎么算的?

    上回说到利息的基本原理,重点探讨了钱能生息的本质(详情请戳:<利息浅谈(一)--为啥钱能生息?>).今天我们进入更加硬核的数学部分,看下利息的核算原理究竟用的是怎样的数学模型. 很多人说, ...

  4. gif透明背景动画_前端基础系列之bmp、jpg、png、gif、svg常用图片格式浅谈(二)...

    IT客栈 作者:大腰子 bmp.jpg.png.gif.svg常用图片格式 之前为大家介绍了几种WEB前端常用的图片格式,对比了它们的特点,参见<前端基础系列之bmp.jpg.png.gif.s ...

  5. 云计算浅谈之二:云计算介绍(2)

    本来这一讲应该随上一讲结束,不过本人时间有限,所以拆开了.另外既然题名为浅谈,就些微提一些概念,唤起大家对云计算的注意,抛砖引玉.更多的内容可以参考我上一讲给大家提示的"windows az ...

  6. Qt浅谈之一:内存泄露(总结)

    一.简介        Qt内存管理机制:Qt 在内部能够维护对象的层次结构.对于可视元素,这种层次结构就是子组件与父组件的关系:对于非可视元素,则是一个对象与另一个对象的从属关系.在 Qt 中,在 ...

  7. IDE / Qt / 浅谈 qmake 之 pro、pri、prf、prl文件

    一. *.pro qmake 的工程(project)文件,栗子: 这是一个典型的 Qt 示例程序的 .pro 文件(propriprfprl.pro): TEMPLATE = app CONFIG ...

  8. Qt浅谈之三十系统托盘(QSystemTrayIcon)

    一.简介 Qt自带的例子/usr/lib64/qt4/examples/desktop/systray中详尽介绍了系统托盘的功能,在其基础上进行拓展,定制适合自己的系统托盘.        托盘菜单实 ...

  9. Qt浅谈之八:富文本转换成pdf

    一.简介 Qt对富文本的处理,主要有几个感兴趣的知识点才写下这篇文章,将文本或图片转换成pdf格式.文件直接拖拽到文本框中.双击对程序全屏和缩小.滚动滑轮对文字放大缩小及安装事件过滤器通过键盘的上下按 ...

最新文章

  1. 再见,Python!你好,Go语言
  2. PyCharm使用笔记
  3. oracle执行计划连接方式
  4. php正则表达式2,php正则表达式(2)
  5. linq学习笔记(2):DataContext
  6. 简明天线理论与设计应用_天线理论与设计笔记5--(宽带天线、口径天线)
  7. 【生活科普】这7个影视剧的经典桥段,骗了我们很多年……
  8. 流程控制: jQ Deferred 与 ES6 Promise 使用新手向入坑!
  9. 机器学习基础(三十二) —— 使用 Apriori 算法进行关联分析
  10. NetOps Defined
  11. php扩展zval,PHP扩展开发(7):zval结构
  12. Java 操作 EXCEL
  13. 数学逻辑习题集(2)
  14. WordPress直接调用头像地址
  15. 【音频】音频文件格式以及相关参数
  16. 小码哥C++学院-零基础入门C语言
  17. 零基础学软件测试难吗?小白怎么半年内成为测试工程师
  18. 微信小程序,大佬救我!!!
  19. vue阻止浏览器默认事件
  20. 如何磁盘格式化?分享格式化U盘的3个方法

热门文章

  1. codevs2495 水叮当的舞步(IDA*)
  2. python对建筑设计的作用_Python 与深度学习有哪些与建筑设计相接轨的可能性?...
  3. 从零开始学五线谱_初学者福利 | 学音乐,从五线谱开始
  4. 纸业供应链协同管理系统:全链路数字化,实现供应链平台订单智能管控
  5. 如何用excel制作图表?
  6. 百度地图显示服务器已满,百度地图APP启动次数居首 生活服务深得用户青睐
  7. centos7云主机nginx+WordPress完整建站流程记录
  8. 中国服务器销售排名,IDC Q3:华为FusionServer Pro智能服务器发货量、销售额荣登中国区x86标准服务器排名双冠王...
  9. 智能硬件“双雄”:先跑的VR何故被智能音箱反超?
  10. 计算机网络协议编号是什么,因特网协议