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();
}