QT开发(十六)——QT绘图实例-钟表
一、钟表实现原理
钟表的实现需要设置定时器,定时器每隔一秒发送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(); }