zoukankan      html  css  js  c++  java
  • Qt浅谈之二:钟表(时分秒针)

    一、简介

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

    二、效果图

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

    三、详解

    1、定时器

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

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

    2、重绘事件

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

    [cpp] view plain copy
     
    1. void Clock::paintEvent(QPaintEvent *event)  
    2. {  
    3.    //下面三个数组用来定义表针的三个顶点,以便后面的填充  
    4.     static const QPoint hourHand[3] = {  
    5.         QPoint(3, 8),  
    6.         QPoint(-3, 8),  
    7.         QPoint(0, -40)  
    8.     };  
    9.     static const QPoint minuteHand[3] = {  
    10.         QPoint(3, 8),  
    11.         QPoint(-3, 8),  
    12.         QPoint(0, -70)  
    13.     };  
    14.     static const QPoint secondHand[3] = {  
    15.         QPoint(3, 8),  
    16.         QPoint(-3, 8),  
    17.         QPoint(0, -90)  
    18.     };//秒针  
    19.     //填充表针的颜色  
    20.     QColor hourColor(127, 0, 127);  //分针颜色(第四个表示不透明度)  
    21.     QColor minuteColor(0, 127, 127, 191);  
    22.     QColor secondColor(127, 127, 0, 127);  
    23.     //...  
    24. }  

    (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:

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

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

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

    [cpp] view plain copy
     
    1. {  
    2.     painter.setPen(Qt::red);   //填充时针,不需要边线所以NoPen  
    3.     QString timeStr= QTime::currentTime().toString();     //绘制当前的时间  
    4.     painter.drawText(-40,30,80,30,Qt::AlignHCenter | Qt::AlignTop, timeStr);  
    5. }  
    
    
    
    

    (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()。

    [cpp] view plain copy
     
    1. {  
    2.     //...  
    3.     painter.setPen(Qt::NoPen);   //填充时针,不需要边线所以NoPen  
    4.     painter.setBrush(hourColor);  //画刷颜色设定  
    5.     painter.save();  //保存painter的状态,保存的是当前的坐标状态,如果不保存,画完之后坐标以改变不方便画下一个  
    6.     painter.rotate(30.0 * ((time.hour() + time.minute() / 60.0))); //将painter(的”视角“)根据时间参数转移(30° * (小时 + 分钟 / 60))  
    7.     painter.drawConvexPolygon(hourHand, 3);  //填充时针的区域  
    8.     painter.restore();  
    9.       
    10.      //后面的跟前面的类似,分别绘制了分针和秒针,及相应的刻度  
    11.     painter.setPen(Qt::NoPen);  
    12.     painter.setBrush(minuteColor);  
    13.     painter.save();  
    14.     painter.rotate(6.0 * (time.minute() + time.second() / 60.0));  //设旋转(角度 = 6° * (分钟 + 秒 / 60))  
    15.     painter.drawConvexPolygon(minuteHand, 3);  //填充分针部分  
    16.     painter.restore();  
    17.   
    18.     painter.setPen(Qt::NoPen);  
    19.     painter.setBrush(secondColor);  
    20.     painter.save();  
    21.     painter.rotate(6.0 * time.second());  //设置旋转(6° * 秒)  
    22.     painter.drawConvexPolygon(secondHand, 3);  //设置填充  
    23.     painter.restore();  
    24.     //...  
    25. }  
    
    

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

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

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

    [cpp] view plain copy
     
    1. {      
    2.     //...   
    3.     painter.setPen(Qt::NoPen);  
    4.     painter.setBrush(secondColor);  
    5.     painter.save();  
    6.     painter.rotate(6.0 * time.second());  //设置旋转(6° * 秒)  
    7.     painter.drawConvexPolygon(secondHand, 3);  //设置填充  
    8.     painter.restore();  
    9.   
    10.     painter.setBrush(Qt::black);  
    11.     painter.drawEllipse(QPoint(0,0),2,2);  
    12.   
    13.     painter.setBrush(Qt::NoBrush);  
    14.     painter.setPen(Qt::black);  
    15.     painter.drawEllipse(QPoint(0,0),97,97);  
    16.     //...  
    17. }  

    四、总结

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

    [cpp] view plain copy
     
    1.  static const QPoint hourHand[4]   ={QPoint(0,10),QPoint(-1,-30),QPoint(0,-60),QPoint(1,-30)};  
    2.  static const QPoint minuteHand[4] ={QPoint(0,10),QPoint(-1,-40),QPoint(0,-70),QPoint(1,-40)};  
    3.  static const QPoint secondHand[4] ={QPoint(0,10),QPoint(-1,-60),QPoint(0,-90),QPoint(1,-60)};  
    4.  QColor hourColor(255,0,0);  
    5.  QColor minuteColor(0,127,127);  
    6.  QColor secondColor(0,0,255);  

    运行效果如下图4:

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

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

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

    patch1

    让背景框架透明,在加上移动盘面和右键退出就构成了一个比较理想的时钟(思路来自同学的程序)。
    [html] view plain copy
     
    1. void Clock::mouseMoveEvent(QMouseEvent *event)  
    2. {  
    3.     if (m_pressMouse) {   //移动窗口  
    4.       QPoint movePos = event->globalPos();  
    5.       move(movePos - m_movePoint);  
    6.     }  
    7. }  
    8. void Clock::contextMenuEvent(QContextMenuEvent *)  
    9. {  
    10.     QCursor cur=this->cursor();  
    11.     QMenu *menu=new QMenu(this);  
    12.     QAction *deleteAction= new QAction(tr("关闭"), this);  
    13.     menu->addAction(deleteAction);  
    14.     connect(deleteAction, SIGNAL(triggered()), SLOT(close()));  
    15.     menu->exec(cur.pos());  
    16. }  
    17. void Clock::mousePressEvent(QMouseEvent *event)  
    18. {  
    19.     if (event->button() == Qt::LeftButton) {  
    20.       m_pressMouse = true;  
    21.     }  
    22.     m_movePoint = event->globalPos() - pos();   //窗口移动距离  
    23. }  
    24. void Clock::mouseReleaseEvent(QMouseEvent * event)  
    25. {  
    26.     m_pressMouse = false;  
    27. }  
    实现效果如下图5所示:(无外边框)
     

    http://blog.csdn.net/taiyang1987912/article/details/30272105

  • 相关阅读:
    POJ 1987 Distance Statistics(树的点分治)
    rabbitmq-c初探
    [置顶] Android开发实战记录(三)---HelloWorld
    debug连线指令
    Qt之信号连接,你Out了吗?
    hdu-4607-Park Visit
    MySQL 分区表 partition线上修改分区字段,后续进一步学习partition (1)
    如何用正则将多个空格看成一个空格结合spllit()方法将文本数据入库
    hdu 1711 Number Sequence(KMP模板题)
    [leetcode]Unique Paths
  • 原文地址:https://www.cnblogs.com/findumars/p/6090437.html
Copyright © 2011-2022 走看看