一、简介

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. 几个常用的数据库连接字符串
  2. 动态代理--cglib
  3. [转载]Mysql数据库千万级数据处理优化
  4. linux如何把nfs数据导出来,linux – NFS导出已经挂载NFS的目录(在服务器上)
  5. MFC+OPENCV实现角点检测
  6. 性能调优的方法及概念
  7. oss按量付费_ACP云计算笔记—VPCamp;OSS
  8. 安装python工具
  9. 分布式云时代,腾讯云为何自研操作系统
  10. [转]Win XP常遇网络故障分析:局域网问题
  11. 配置LANMP环境(1)-- 安装虚拟机VMware与安装CentOS7.2系统
  12. 6. JavaScript HTML DOM
  13. Appium 1.21.x 百度网盘下载
  14. 抖音超火的罗马时钟html代码,最近抖音上挺火的圆形文字时钟
  15. Linux内核数据结构之哈希表
  16. sketch 52.2 中文破解版发布 附下载地址
  17. 东南亚外卖平台分析报告
  18. Python dataframe绘制饼图_Python可视化29|matplotlib-饼图(pie)
  19. 看黄天鹅如何下一颗高端鸡蛋?
  20. oracle 10g固定执行计划,oracle 10g执行计划 (转帖)

热门文章

  1. 软件测试专业院校研究生,北化信息科学与技术学院导师赵瑞莲【计算机考研软件测试与软件可靠性方向】...
  2. golang力扣leetcode 675.为高尔夫比赛砍树
  3. 基于MATLAB的LBM代码: Rough jet model
  4. Dedecms建站详细流程
  5. Win11系统怎么禁止OneDrive开机自启操作分享
  6. 越想越难,越做越简单,电磁兼容性设计
  7. 修改监控录像时间的方法以及基础常识,必看!...
  8. javascript 中冒号(:)意思?
  9. 人工智能在制造业的工程化应用实践----工业软件讲坛第九次讲座
  10. 第二章 GPU虚拟化方案之——GPU直通模式