Qt仿Android带特效的数字时钟源码分析(滑动,翻页,旋转效果)

这个数字时钟的源码可以在Qt Demo中找到,风格是仿Android的,不过该Demo中含有三种动画效果(鉴于本人未曾用过Android的系统,因此不知道Android的数字时钟是否也含有这三种效果),其分别为滑动、翻页和旋转。

由于本人的Qt Creator输入中文后显示的都是乱码,因而在此只能使用英文进行注释,后期如果有时间再进行中文的相关整理。可能有些地方理解并不是很正确。希望大家多多指正!

 

以下为源码:

 

[cpp] view plaincopy
 
  1. #include <QtCore>  
  2. #include <QtGui>  
  3.   
  4. class Digits: public QWidget  
  5. {  
  6.     Q_OBJECT  
  7.   
  8. public:  
  9.   
  10.     /*Define three transition modes of the digital clock*/  
  11.     enum {  
  12.         Slide,  
  13.         Flip,  
  14.         Rotate  
  15.     };  
  16.   
  17.     Digits(QWidget *parent)  
  18.         : QWidget(parent)  
  19.         , m_number(0)  
  20.         , m_transition(Slide)  
  21.     {  
  22.         setAttribute(Qt::WA_OpaquePaintEvent, true);  
  23.         //Widget paints all its pixels when it receives a paint event  
  24.   
  25.         setAttribute(Qt::WA_NoSystemBackground, true);  
  26.         //Indicates that the widget has no background, i.e. when the widget receives paint events, the background is not automatically repainted.  
  27.   
  28.         connect(&m_animator, SIGNAL(frameChanged(int)), SLOT(update()));  
  29.         //start animation  
  30.   
  31.         m_animator.setFrameRange(0, 100);  
  32.         m_animator.setDuration(600);  
  33.         //Construct a 0.6-second timeline with a frame range of 0 - 100  
  34.   
  35.         m_animator.setCurveShape(QTimeLine::EaseInOutCurve);  
  36.         //starts growing slowly, then runs steadily, then grows slowly again  
  37.     }  
  38.   
  39.     /*Set transition when time changed*/  
  40.     void setTransition(int tr) {  
  41.         m_transition = tr;  
  42.     }  
  43.   
  44.     /*Get transition mode*/  
  45.     int transition() const {  
  46.         return m_transition;  
  47.     }  
  48.   
  49.     /*Set hours and minutes*/  
  50.     void setNumber(int n) {  
  51.         if (m_number != n) {  
  52.             m_number = qBound(0, n, 99);  
  53.             preparePixmap();  
  54.             update();  
  55.         }  
  56.     }  
  57.   
  58.     /*Flip to next state*/  
  59.     void flipTo(int n) {  
  60.         if (m_number != n) {  
  61.             m_number = qBound(0, n, 99);  
  62.             m_lastPixmap = m_pixmap;  
  63.             preparePixmap();  
  64.             m_animator.stop();  
  65.             m_animator.start();  
  66.         }  
  67.     }  
  68.   
  69. protected:  
  70.   
  71.     /*Draw the main frame of the digits area*/  
  72.     void drawFrame(QPainter *p, const QRect &rect) {  
  73.         p->setPen(Qt::NoPen);  
  74.         QLinearGradient gradient(rect.topLeft(), rect.bottomLeft());  
  75.         //Set linear gradient area  
  76.   
  77.         gradient.setColorAt(0.00, QColor(245, 245, 245));  
  78.         gradient.setColorAt(0.49, QColor(192, 192, 192));  
  79.         gradient.setColorAt(0.51, QColor(245, 245, 245));  
  80.         gradient.setColorAt(1.00, QColor(192, 192, 192));  
  81.         //Creates stop points at the given position with the given color  
  82.   
  83.         p->setBrush(gradient);  
  84.         QRect r = rect;  
  85.         p->drawRoundedRect(r, 15, 15, Qt::RelativeSize);  
  86.         /* 
  87.             Draws outer rectangle rect with rounded corners. 
  88.             Qt::RelativeSize specifies the size relative to the bounding rectangle, 
  89.             typically using percentage measurements. 
  90.         */  
  91.   
  92.         r.adjust(1, 4, -1, -4);  
  93.         //Adds 1, 4, -1 and -4 respectively to the existing coordinates of the rectangle  
  94.   
  95.         p->setPen(QColor(181, 181, 181));  
  96.         p->setBrush(Qt::NoBrush);  
  97.         p->drawRoundedRect(r, 15, 15, Qt::RelativeSize);  
  98.         //Draws inner rectangle rect with rounded corners.  
  99.   
  100.         p->setPen(QColor(159, 159, 159));  
  101.         int y = rect.top() + rect.height() / 2 - 1;  
  102.         p->drawLine(rect.left(), y, rect.right(), y);  
  103.         //Draws the mid-line from (rect.left(), y) to (rect.right(), y) and sets the current pen position to (rect.right(), y)  
  104.   
  105.     }  
  106.   
  107.     /*Draw the digits*/  
  108.     QPixmap drawDigits(int n, const QRect &rect) {  
  109.   
  110.         int scaleFactor = 2;  
  111. #if defined(Q_OS_SYMBIAN) || defined(Q_OS_WINCE_WM)  
  112.         if (rect.height() > 240)  
  113.             scaleFactor = 1;  
  114. #endif  
  115.   
  116.         QString str = QString::number(n);  
  117.         if (str.length() == 1)  
  118.             str.prepend("0");  
  119.         //Ensure it is double-digit  
  120.   
  121.         QFont font;  
  122.         font.setFamily("Helvetica");  
  123.         int fontHeight = scaleFactor * 0.55 * rect.height();  
  124.         font.setPixelSize(fontHeight);  
  125.         //Sets the font size to pixelSize pixels  
  126.   
  127.         font.setBold(true);  
  128.   
  129.         QPixmap pixmap(rect.size() * scaleFactor);  
  130.         pixmap.fill(Qt::transparent);  
  131.   
  132.         QLinearGradient gradient(QPoint(0, 0), QPoint(0, pixmap.height()));  
  133.         //Constructs a linear gradient with interpolation area between (0,0) and (0,pixmap.height())  
  134.   
  135.         gradient.setColorAt(0.00, QColor(128, 128, 128));  
  136.         gradient.setColorAt(0.49, QColor(64, 64, 64));  
  137.         gradient.setColorAt(0.51, QColor(128, 128, 128));  
  138.         gradient.setColorAt(1.00, QColor(16, 16, 16));  
  139.         //Creates stop points at the given position with the given color  
  140.   
  141.         QPainter p;  
  142.         p.begin(&pixmap);  
  143.         p.setFont(font);  
  144.         QPen pen;  
  145.         pen.setBrush(QBrush(gradient));  
  146.         //Set penbrush with linergrident  
  147.   
  148.         p.setPen(pen);  
  149.         p.drawText(pixmap.rect(), Qt::AlignCenter, str);  
  150.         //Draws the digit number(str here) within the provided rectangle  
  151.   
  152.         p.end();  
  153.   
  154.         return pixmap.scaledToWidth(width(), Qt::SmoothTransformation);  
  155.         //Returns a scaled copy of the image which is transformed using bilinear filtering  
  156.     }  
  157.   
  158.     /*prepare the pixmap  */  
  159.     void preparePixmap() {  
  160.         m_pixmap = QPixmap(size());  
  161.         m_pixmap.fill(Qt::transparent);  
  162.         //Fills the pixmap with the given transparent black value (i.e., QColor(0, 0, 0, 0))  
  163.   
  164.         QPainter p;  
  165.         p.begin(&m_pixmap);  
  166.         p.drawPixmap(0, 0, drawDigits(m_number, rect()));  
  167.         //Draws the given digits-pixmap at position (0, 0)  
  168.   
  169.         p.end();  
  170.     }  
  171.   
  172.     /*define a resize event*/  
  173.     void resizeEvent(QResizeEvent*) {  
  174.         preparePixmap();  
  175.         update();//Causes a paintEvent() call  
  176.   
  177.     }  
  178.   
  179.     /*Paint the static state*/  
  180.     void paintStatic() {  
  181.         QPainter p(this);  
  182.         p.fillRect(rect(), Qt::black);  
  183.         //Fill the widget rec with black color  
  184.   
  185.         int pad = width() / 10;  
  186.         drawFrame(&p, rect().adjusted(pad, pad, -pad, -pad));  
  187.         p.drawPixmap(0, 0, m_pixmap);  
  188.     }  
  189.   
  190.     /*Paint the slide state*/  
  191.     void paintSlide() {  
  192.         QPainter p(this);  
  193.         p.fillRect(rect(), Qt::black);  
  194.   
  195.         int pad = width() / 10;  
  196.         QRect fr = rect().adjusted(pad, pad, -pad, -pad);  
  197.         drawFrame(&p, fr);  
  198.         p.setClipRect(fr);  
  199.         //sets the clip region to the given rectangle using the given clip operation  
  200.   
  201.         int y = height() * m_animator.currentFrame() / 100;  
  202.         p.drawPixmap(0, y, m_lastPixmap);  
  203.         //Draw last-time state pixmap from 0 to height()(Y Coordinate)  in 0.6 second  
  204.   
  205.         p.drawPixmap(0, y - height(), m_pixmap);  
  206.         //Draw current-time state pixmap from -height() to 0 (Y Coordinate) in 0.6 second  
  207.     }  
  208.   
  209.     /*Paint the flip state*/  
  210.     void paintFlip() {  
  211.         QPainter p(this);  
  212. #if !defined(Q_OS_SYMBIAN) && !defined(Q_OS_WINCE_WM)  
  213.         p.setRenderHint(QPainter::SmoothPixmapTransform, true);  
  214.         p.setRenderHint(QPainter::Antialiasing, true);  
  215. #endif  
  216.         p.fillRect(rect(), Qt::black);  
  217.   
  218.         int hw = width() / 2;  
  219.         int hh = height() / 2;  
  220.   
  221.         // behind is the new pixmap  
  222.         int pad = width() / 10;  
  223.         QRect fr = rect().adjusted(pad, pad, -pad, -pad);  
  224.         drawFrame(&p, fr);  
  225.         p.drawPixmap(0, 0, m_pixmap);  
  226.   
  227.         int index = m_animator.currentFrame();  
  228.   
  229.         if (index <= 50) {  
  230.   
  231.             // the top part of the old pixmap is flipping  
  232.             int angle = -180 * index / 100;  
  233.             QTransform transform;  
  234.             transform.translate(hw, hh);  
  235.             //Moves the coordinate system to the center of widget  
  236.   
  237.             transform.rotate(angle, Qt::XAxis);  
  238.             //Rotates the coordinate system counterclockwise by angle about the X axis  
  239.   
  240.             p.setTransform(transform);  
  241.             drawFrame(&p, fr.adjusted(-hw, -hh, -hw, -hh));  
  242.             p.drawPixmap(-hw, -hh, m_lastPixmap);  
  243.   
  244.             // the bottom part is still the old pixmap  
  245.             p.resetTransform();  
  246.             p.setClipRect(0, hh, width(), hh);  
  247.             //Enables clipping, and sets the clip region to the rectangle beginning at (0, hh) with the given width and height  
  248.   
  249.             drawFrame(&p, fr);  
  250.             p.drawPixmap(0, 0, m_lastPixmap);  
  251.         } else {  
  252.   
  253.             p.setClipRect(0, hh, width(), hh);  
  254.   
  255.             // the bottom part is still the old pixmap  
  256.             drawFrame(&p, fr);  
  257.             p.drawPixmap(0, 0, m_lastPixmap);  
  258.   
  259.             // the bottom part of the new pixmap is flipping  
  260.             int angle = 180 - 180 * m_animator.currentFrame() / 100;  
  261.             QTransform transform;  
  262.             transform.translate(hw, hh);  
  263.             transform.rotate(angle, Qt::XAxis);  
  264.             p.setTransform(transform);  
  265.             drawFrame(&p, fr.adjusted(-hw, -hh, -hw, -hh));  
  266.             p.drawPixmap(-hw, -hh, m_pixmap);  
  267.   
  268.         }  
  269.   
  270.     }  
  271.   
  272.     /*Paint the rotate state*/  
  273.     void paintRotate() {  
  274.         QPainter p(this);  
  275.   
  276.         int pad = width() / 10;  
  277.         QRect fr = rect().adjusted(pad, pad, -pad, -pad);  
  278.         drawFrame(&p, fr);  
  279.         p.setClipRect(fr);  
  280.   
  281.         int angle1 = -180 * m_animator.currentFrame() / 100;  
  282.         int angle2 = 180 - 180 * m_animator.currentFrame() / 100;  
  283.         int angle = (m_animator.currentFrame() <= 50) ? angle1 : angle2;  
  284.         QPixmap pix = (m_animator.currentFrame() <= 50) ? m_lastPixmap : m_pixmap;  
  285.   
  286.         QTransform transform;  
  287.         transform.translate(width() / 2, height() / 2);  
  288.         transform.rotate(angle, Qt::XAxis);  
  289.   
  290.         p.setTransform(transform);  
  291.         p.setRenderHint(QPainter::SmoothPixmapTransform, true);  
  292.         p.drawPixmap(-width() / 2, -height() / 2, pix);  
  293.     }  
  294.   
  295.     void paintEvent(QPaintEvent *event) {  
  296.         Q_UNUSED(event);  
  297.         if (m_animator.state() == QTimeLine::Running) {  
  298.             if (m_transition == Slide)  
  299.                 paintSlide();  
  300.             if (m_transition == Flip)  
  301.                 paintFlip();  
  302.             if (m_transition == Rotate)  
  303.                 paintRotate();  
  304.         } else {  
  305.             paintStatic();  
  306.         }  
  307.     }  
  308.   
  309. private:  
  310.     int m_number;//number to set to digits  
  311.   
  312.     int m_transition;//transition mode(change effect)  
  313.   
  314.     QPixmap m_pixmap;//current time pixmap  
  315.   
  316.     QPixmap m_lastPixmap;//next state time pixmap  
  317.   
  318.     QTimeLine m_animator;  
  319.     //used to animate a GUI control by calling a slot periodically  
  320.     //The timeline's duration describes for how long the animation will run  
  321.     //connect the frameChanged() signal to a suitable slot in the widget you wish to animate  
  322. };  
  323.   
  324. class DigiFlip : public QMainWindow  
  325. {  
  326.     Q_OBJECT  
  327.   
  328. public:  
  329.     DigiFlip(QWidget *parent = 0)  
  330.         : QMainWindow(parent)  
  331.     {  
  332.         m_hour = new Digits(this);  
  333.         m_hour->show();  
  334.         m_minute = new Digits(this);  
  335.         m_minute->show();  
  336.   
  337.         QPalette pal = palette();  
  338.         pal.setColor(QPalette::Window, Qt::black);  
  339.         //Sets the color used for the given color role, in all color groups, to the specified solid color.  
  340.   
  341.         setPalette(pal);  
  342.   
  343.         m_ticker.start(1000, this);  
  344.         //Send a timer event every second  
  345.   
  346.         QTime t = QTime::currentTime();  
  347.         m_hour->setNumber(t.hour());  
  348.         m_minute->setNumber(t.minute());  
  349.         updateTime();  
  350.   
  351.         QAction *slideAction = new QAction("&Slide", this);  
  352.         QAction *flipAction = new QAction("&Flip", this);  
  353.         QAction *rotateAction = new QAction("&Rotate", this);  
  354.         connect(slideAction, SIGNAL(triggered()), SLOT(chooseSlide()));  
  355.         connect(flipAction, SIGNAL(triggered()), SLOT(chooseFlip()));  
  356.         connect(rotateAction, SIGNAL(triggered()), SLOT(chooseRotate()));  
  357. #if defined(Q_OS_SYMBIAN) || defined(Q_OS_WINCE_WM)  
  358.         menuBar()->addAction(slideAction);  
  359.         menuBar()->addAction(flipAction);  
  360.         menuBar()->addAction(rotateAction);  
  361. #else  
  362.         addAction(slideAction);  
  363.         addAction(flipAction);  
  364.         addAction(rotateAction);  
  365.         setContextMenuPolicy(Qt::ActionsContextMenu);  
  366.         //Shows a context menu(right click)  
  367. #endif  
  368.     }  
  369.   
  370.     /*Real-time updates*/  
  371.     void updateTime() {  
  372.         QTime t = QTime::currentTime();  
  373.         m_hour->flipTo(t.hour());  
  374.         m_minute->flipTo(t.minute());  
  375.         QString str = t.toString("hh:mm:ss");  
  376.         str.prepend(": ");  
  377.         if (m_hour->transition() == Digits::Slide)  
  378.             str.prepend("Slide");  
  379.         if (m_hour->transition() == Digits::Flip)  
  380.             str.prepend("Flip");  
  381.         if (m_hour->transition() == Digits::Rotate)  
  382.             str.prepend("Rotate");  
  383.         setWindowTitle(str);  
  384.     }  
  385.   
  386.     /*Switch transition mode*/  
  387.     void switchTransition(int delta) {  
  388.         int i = (m_hour->transition() + delta + 3) % 3;  
  389.         m_hour->setTransition(i);  
  390.         m_minute->setTransition(i);  
  391.         updateTime();  
  392.     }  
  393.   
  394. protected:  
  395.     void resizeEvent(QResizeEvent*) {  
  396.         int digitsWidth = width() / 2;  
  397.         int digitsHeight = digitsWidth * 1.2;  
  398.   
  399.         int y = (height() - digitsHeight) / 3;  
  400.   
  401.         m_hour->resize(digitsWidth, digitsHeight);  
  402.         m_hour->move(0, y);  
  403.   
  404.         m_minute->resize(digitsWidth, digitsHeight);  
  405.         m_minute->move(width() / 2, y);  
  406.     }  
  407.   
  408.     /*Timer event,receive timer events */  
  409.     void timerEvent(QTimerEvent*) {  
  410.         updateTime();  
  411.     }  
  412.   
  413.     /* Get key press event */  
  414.     void keyPressEvent(QKeyEvent *event) {  
  415.         if (event->key() == Qt::Key_Right) {  
  416.             switchTransition(1);  
  417.             event->accept();  
  418.         }  
  419.         if (event->key() == Qt::Key_Left) {  
  420.             switchTransition(-1);  
  421.             event->accept();  
  422.         }  
  423.     }  
  424.   
  425. private slots:  
  426.     void chooseSlide() {  
  427.         m_hour->setTransition(0);  
  428.         m_minute->setTransition(0);  
  429.         updateTime();  
  430.     }  
  431.   
  432.     void chooseFlip() {  
  433.         m_hour->setTransition(1);  
  434.         m_minute->setTransition(1);  
  435.         updateTime();  
  436.     }  
  437.   
  438.     void chooseRotate() {  
  439.         m_hour->setTransition(2);  
  440.         m_minute->setTransition(2);  
  441.         updateTime();  
  442.     }  
  443.   
  444. private:  
  445.     QBasicTimer m_ticker;  
  446.     Digits *m_hour;  
  447.     Digits *m_minute;  
  448. };  
  449.   
  450. #include "digiflip.moc"  
  451.   
  452. int main(int argc, char *argv[])  
  453. {  
  454.     QApplication app(argc, argv);  
  455.   
  456.     DigiFlip time;    
  457. //#if defined(Q_OS_SYMBIAN) || defined(Q_OS_WINCE_WM)  
  458. //  time.showFullScreen();  
  459. //#else  
  460.     time.resize(320, 240);  
  461.     time.show();  
  462. //#endif  
  463.   
  464.     return app.exec();  
  465. }  

以下为程序截图:

http://blog.csdn.net/huihui1988/article/details/5853728#comments

posted @ 2015-11-17 22:56  findumars  Views(897)  Comments(0Edit  收藏  举报