Qt浅谈之二:钟表(时分秒针)
来源:互联网 发布:北上广 知乎 编辑:程序博客网 时间:2024/04/30 10:50
一、简介
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); //声明用来绘图用的painter painter.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); //填充时针,不需要边线所以NoPen QString 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); //填充时针,不需要边线所以NoPen painter.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浅谈之二:钟表(时分秒针)
- Qt浅谈之钟表(时分秒针)
- QT编程实例2--钟表(时分秒针) (上)
- Qt浅谈之四十二钟表摆动显示百分比
- 时分秒针重合
- 时分秒针重合问题
- 时分秒针重合
- 时分秒针旋转角度换算
- Qt浅谈之二十九Qt多线程
- 时分秒针在一天之内重合多少次
- Qt浅谈之二十二Qt样式表
- Qt浅谈之二十二Qt样式表
- Qt浅谈之二十二Qt样式表
- Qt浅谈之二十二Qt样式表
- 数据结构——算法之(035)(时钟的时分秒针每天重叠几次?时分每天相遇几次?分秒每小时遇到几次?)
- Qt浅谈之十六:TCP和UDP(之二)
- Qt浅谈之二十七进程间通信之QtDBus
- Qt浅谈之二十七进程间通信之QtDBus
- ERROR: No viable tables matched specification.
- 百度地图静态库的合成
- 使用libpng显示png图片
- document.body is null
- Android布局大全
- Qt浅谈之二:钟表(时分秒针)
- Sed学习笔记
- windows下svn的安装和配置
- ONVIF: gsoap安装过程
- mysql 查找包含某些字段且不包含另一些字段的表
- EA强大的画图工具---设计数据库表格
- inf复制文件
- 12_android入门_补间动画
- 新开一个博客