QT开发(十六)——QT绘图实例-钟表

QT开发(十六)——QT绘图实例-钟表_第1张图片

一、钟表实现原理

    钟表的实现需要设置定时器,定时器每隔一秒发送timeout()信号到QWidget::update()槽函数,update()槽函数将会重绘一次窗口,重写重绘事件函数paintEvent(QPaintEvent *event),根据获取的当前系统时间的时钟、分钟、秒钟重绘钟表的时针、分针、秒针。

    QTimer *timer = new QTimer(this);

    timer->start(1000);//一秒钟

    connect(timer,SIGNAL(timeout()),this,SLOT(update()));

    setWindowTitle("The Clock");

二、钟表的界面绘制

    钟表由时针、分针、秒针、刻度盘组成,绘制时针、分针、秒针、刻度盘刻度线需要翻转坐标系,因此在绘制前需要先保存当前的坐标系状态,对坐标系进行翻转需要的角度后绘制图形,绘制完成后需要恢复坐标系的状态。

1、时针绘制

    确定组成时针的四个点,使用drawConvexPolygon函数绘制出四边形时针。

    const QPoint Clock::hourHand[4] = {

        QPoint(3, 5),

        QPoint(0, 13),

        QPoint(-3, 5),

        QPoint(0, -40)

        };

    QPainter painter(this);

    painter.setBrush(Qt::black);

    painter.setPen(Qt::black);

    painter.drawConvexPolygon(hourHand,4);//绘制时针

2、分针绘制

确定组成分针的四个点,使用drawConvexPolygon函数绘制出四边形分针。

    const QPoint Clock::minuteHand[4] = {

        QPoint(3, 5),

        QPoint(0, 16),

        QPoint(-3, 5),

        QPoint(0, -70)

        };

    QPainter painter(this);

    painter.setBrush(Qt::black);

    painter.setPen(Qt::black);

    painter.drawConvexPolygon(minuteHand,4);//绘制分针

3、秒针绘制

确定组成秒针的四个点,使用drawConvexPolygon函数绘制出四边形秒针。

    const QPoint Clock::secondHand[4] = {

        QPoint(3, 5),

        QPoint(0, 18),

        QPoint(-3, 5),

        QPoint(0, -90)

        };

    QPainter painter(this);

    painter.setBrush(Qt::black);

    painter.setPen(Qt::black);

    painter.drawConvexPolygon(secondHand,4);//绘制秒针

4、钟表刻度盘绘制

    钟表刻度盘分为时钟刻度和分钟刻度,分钟刻度每隔一分钟一根刻度线,因此坐标轴系统顺时针旋转6°时为一个分钟刻度,但是由于时钟刻度线与分钟刻度线重合,每隔30°的分钟刻度线同时也为时钟刻度线。

void Clock::drawClockDial(QPainter *painter)
{
     for (int i = 1; i <=60; ++i)
    {
        painter->save();
        painter->rotate(6*i);//坐标轴旋转6度
        if (i % 5 == 0)
        {
            painter->setPen(hourHandPen);
            painter->drawLine(0, -98, 0, -82);
            painter->drawText(-20, -82, 40, 40,
              Qt::AlignHCenter | Qt::AlignTop,QString::number(i/5));
        }
        else
        {
            painter->setPen(minuteHandPen);
            painter->drawLine(0, -98, 0, -88);
        }
        painter->restore();//绘制图形后复位坐标系
    }
}

三、钟表的业务逻辑

钟表正确计时必须依赖于获取系统时间,根据获取的系统时间计算出的时钟、分钟、秒钟的数重绘时针、分针、秒针。

1、时针的重绘

    时针指向的位置需要计算时针偏转的角度,每两个时钟刻度线相隔30°,因此根据获取的系统时间计算出的小时数与30相乘即可等到时针需要顺时针偏转的角度。

    30.0*(time.hour()+time.minute()/60.0)

    时针重绘代码:

    QTime time = QTime::currentTime();

    painter->setBrush(Qt::black);

    painter->setPen(Qt::black);

    painter->save();

    painter->rotate(30.0*(time.hour()+time.minute()/60.0));

    painter->drawConvexPolygon(hourHand,4);//绘制时针

    painter->restore();//绘制图形后复位坐标系

2、分针的重绘

    分针指向的位置需要计算分针偏转的角度,每两个分钟刻度线相隔6°,因此根据获取的系统时间计算出的分钟数与6相乘即可等到分针需要顺时针偏转的角度。

    6.0*(time.minute()+time.second()/60.0)

    分针重绘代码:

    QTime time = QTime::currentTime();

    painter->setBrush(Qt::blue);

    painter->setPen(Qt::blue);

    painter->save();

    painter->rotate(6.0*(time.minute()+time.second()/60.0));

    painter->drawConvexPolygon(minuteHand,4);//绘制分针

    painter->restore();//绘制图形后复位坐标系

3、秒针的重绘

    秒针指向的位置需要计算秒针偏转的角度,秒针指向的是分钟刻度线,每两个分钟刻度线相隔6°,因此根据获取的系统时间计算出的秒钟数与6相乘即可等到秒针需要顺时针偏转的角度。

    6.0*time.second()

    分针重绘代码:

    QTime time = QTime::currentTime();

    painter->setBrush(Qt::red);

    painter->setPen(Qt::red);

    painter->save();//保存坐标系,防止坐标系跑偏了

    painter->rotate(6.0*time.second());//注意是6.0,不是6

    painter->drawConvexPolygon(secondHand,4);//绘制秒针

    painter->restore();//绘制图形后复位坐标系

四、代码实现

Clock.h文件:

#ifndef CLOCK_H
#define CLOCK_H
#include 
#include 
#include 
#include 
#include 
#include 
#include 
class Clock : public QWidget
{
    Q_OBJECT
    
public:
    Clock(QWidget *parent = 0);
    ~Clock();
private:
    static const QPoint hourHand[4];
    static const QPoint minuteHand[4];
    static const QPoint secondHand[4];
    QPen hourHandPen;
    QPen minuteHandPen;
    QFont font;
protected:
    void paintEvent(QPaintEvent *event);
    void drawHourHand(QPainter *painter);
    void drawMinuteHand(QPainter *painter);
    void drawsecondHand(QPainter *painter);
    void drawClockDial(QPainter *painter);
};
#endif // CLOCK_H

 

Clock.cpp文件:

#include "Clock.h"
const QPoint Clock::hourHand[4] = {
    QPoint(3, 5),
    QPoint(0, 13),
    QPoint(-3, 5),
    QPoint(0, -40)
};
const QPoint Clock::minuteHand[4] = {
    QPoint(3, 5),
    QPoint(0, 16),
    QPoint(-3, 5),
    QPoint(0, -70)
};
const QPoint Clock::secondHand[4] = {
    QPoint(3, 5),
    QPoint(0, 18),
    QPoint(-3, 5),
    QPoint(0, -90)
};
Clock::Clock(QWidget *parent)
    : QWidget(parent)
{
    hourHandPen = QPen(palette().foreground(), 2.0);//设置小时刻度线为粗黑
    minuteHandPen = QPen(palette().foreground(), 1.0);//设置分钟刻度线为灰
    font.setPointSize(10);//字体大小设置为10
    setFont(font);
    QTimer *timer = new QTimer(this);
    timer->start(1000);//一秒钟
    connect(timer,SIGNAL(timeout()),this,SLOT(update()));
    setWindowTitle("The Clock");
    resize(360, 360);
}
Clock::~Clock()
{
}
void Clock::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing, true);
    int side = qMin(width(), height());
    painter.setViewport((width() - side) / 2, (height() - side) / 2,
                        side, side);
    painter.setWindow(0, 0, 200, 200);
    painter.translate(100,100);//重新设定坐标原点
    drawClockDial(&painter);
    drawHourHand(&painter);
    drawMinuteHand(&painter);
    drawsecondHand(&painter);
    painter.setBrush(Qt::black);
    painter.drawEllipse(QPoint(0,0),3,3);
}
void Clock::drawHourHand(QPainter *painter)
{
    QTime time = QTime::currentTime();
    painter->setBrush(Qt::black);
    painter->setPen(Qt::black);
    painter->save();
    painter->rotate(30.0*(time.hour()+time.minute()/60.0));
    painter->drawConvexPolygon(hourHand,4);//绘制时针
    painter->restore();//绘制图形后复位坐标系
}
void Clock::drawMinuteHand(QPainter *painter)
{
    QTime time = QTime::currentTime();
    painter->setBrush(Qt::blue);
    painter->setPen(Qt::blue);
    painter->save();
    painter->rotate(6.0*(time.minute()+time.second()/60.0));
    painter->drawConvexPolygon(minuteHand,4);//绘制分针
    painter->restore();//绘制图形后复位坐标系
}
void Clock::drawsecondHand(QPainter *painter)
{
    QTime time = QTime::currentTime();
    painter->setBrush(Qt::red);
    painter->setPen(Qt::red);
    painter->save();//保存坐标系,防止坐标系跑偏了
    painter->rotate(6.0*time.second());//注意是6.0,不是6
    painter->drawConvexPolygon(secondHand,4);//绘制秒针
    painter->restore();//绘制图形后复位坐标系
}
void Clock::drawClockDial(QPainter *painter)
{
    //绘制钟表刻度盘和数字
    for (int i = 1; i <=60; ++i)
    {
        painter->save();
        painter->rotate(6*i);//坐标轴旋转6度
        if (i % 5 == 0)
        {
            painter->setPen(hourHandPen);
            painter->drawLine(0, -98, 0, -82);
            painter->drawText(-20, -82, 40, 40,
                              Qt::AlignHCenter | Qt::AlignTop,
                              QString::number(i/5));
        }
        else
        {
            painter->setPen(minuteHandPen);
            painter->drawLine(0, -98, 0, -88);
        }
        painter->restore();//绘制图形后复位坐标系
    }
}

Main.cpp文件:

#include 
#include "Clock.h"
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Clock w;
    w.show();
    return a.exec();
}