Qt绘图之时钟
·前言
Qt简介
Qt 由奇趣科技公司(Trolltech)的两位创始人于1990年着手开发,1995年发布Qt 1.0。2008年,奇趣科技被诺基亚公司收购,Qt也因此成为诺基亚旗下的编程语言工具。在智能手机的冲击下诺基亚大厦轰然倒塌,2012年将 Qt 转让给Digia公司。Digia 是一家总部位于芬兰的IT业务供应商,每天向全球数以百万的人提供通讯技术的及时解决方案,业务涉及电信、工业、贸易、金融等,客户包括诺基亚、索尼爱立信、惠普、甲骨文等全球一流企业。超过1200名研发精英分别位于芬兰、瑞典、爱沙尼亚、俄罗斯、中国等地为客户提供端到端的服务。
正文
准备
硬件:一台电脑
软件:(IDE)Qt Creator 4.5.0(Community)、(版本)Qt5.9.4
创建项目
点击“New Project”创建新项目
如上图所示选择之后点击左下角的choose
自定义项目名称和项目路径
选择引用(Qt的版本)
定义类名、头文件名和源文件名
选择默认
创建成功
需要的头文件
#include <QWidget> // QWidget 类是所有用户界面对象的基类
#include <QPaintEvent> // QPaintEvent 类包含绘制事件的事件参数。
#include <QPainter> // QPainter 类在小部件和其他绘画设备上执行低级绘画
#include <QPen> // QPen 类定义了 QPainter 应该如何绘制形状的线条和轮廓。
#include <QBrush> // QBrush 类定义了 QPainter 绘制的形状的填充模式
#include <QtMath> //这些函数是C或标准模板库中不可用的基本数学运算的部分方便定义
#include <QTimer> // QTimer 类提供重复和单次计时器。
#include <QDebug> // QDebug 类为调试信息提供输出流。
绘制表盘
首先我们要确定绘制表盘需要哪些参数,半径和Π?按照数学的逻辑来说确实没错,不过把它运用到计算机中还是需要有所改变才可以,表盘的制作需要用到void QPainter::drawEllipse(int x, int y, int width, int height)这个函数,这是一个过载功能。以给定的宽度和高度绘制由从 (x, y) 开始的矩形定义的椭圆。
绘制刻度盘
绘制刻度盘我们需要知道每次转动的角度是多少,时钟有12个大的刻度,每个大的刻度有5个小刻度,所有秒钟每秒转动的角度为360/60 = 6°。圆心所在竖线上方向为y轴正半轴,0°参考点为x轴正半轴,顺时针旋转。从12点处开始绘制,那么我们的基础仰角就是90° * 3 = 270°,接下来依次是276°、282°。
绘制指针
时钟的指针分为时针、分针和秒针,原理基本上一模一样, 时针我们将其看作是一个等腰三角形,底边在中心指针圆域中,顶点指向刻度,所以我们需要知道三个点的坐标才可以绘制出时针(三角形)。
流程
首先我们分别通过QTime::currentTime.hour、QTime::currentTime.minute、QTime::currentTime.second获取系统的时、分、秒然后再把值赋给Hs、Ms、Ss,如何实时更新时间呢?我们需要一个定时器QTimer值设为1000,表示每间隔1秒返回一次系统时间。
实现
头文件
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QPaintEvent>
#include <QPainter>
#include <QPen>
#include <QBrush>
#include <QtMath>
#include <QTimer>
#define Pai 3.14
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget();
void paintEvent(QPaintEvent *);//重写绘制事件函数
void Init_Parameter();//初始化参数函数
void Draw_Clock(QPainter *);//绘制时钟
void Draw_Dial(QPainter *);//绘制刻度盘
void Draw_Text(QPainter *);//绘制刻度值
void Draw_Pointer(QPainter *);//绘制 指针
private:
QTimer *timer;//定时器
QPoint Center_pos;//时钟圆心坐标
int R_Edge;//外圆半径
int R_Inside;//内圆半径
int R_Center;//中心小圆半径
int R_Pointer;//中心指针圆半径
int Div_Max = 12;//大刻度值
int Div_Min = 5;//小刻度值
float BaseAngle = 270;//仰角
int Hs;//时
int Ms;//分
int Ss ;//秒
};
#endif // WIDGET_H
.cpp文件
#include "widget.h"
#include <QTime>
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
timer = new QTimer(this);
connect(timer,SIGNAL(timeout()),this,SLOT(update()));//定时调用绘制事件函数
timer->start(1000);//开启定时器
}
Widget::~Widget()
{
}
void Widget::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);//设置抗锯齿
Draw_Clock(&painter);
painter.drawEllipse(Center_pos,R_Edge,R_Edge);
}
void Widget::Draw_Clock(QPainter *painter) //绘制时钟(刻度盘、刻度值、指针)
{
Init_Parameter();
Draw_Dial(painter);
Draw_Text(painter);
Draw_Pointer(painter);
}
void Widget::Init_Parameter()
{
Center_pos = QPoint(this->width()/2,this->height()/2);
R_Edge = this->height()/2;
R_Inside = R_Edge-10;
R_Center = 15;
R_Pointer = 6;
QTime Time = QTime::currentTime();//获取当前系统时间
Hs=Time.hour();
Ms=Time.minute();
Ss=Time.second();
}
void Widget::Draw_Dial(QPainter *painter)
{
painter->save();
for(int Loop = 0; Loop <= Div_Max*Div_Min; Loop++)
{
float Angle = BaseAngle + (360 / (Div_Max * Div_Min))*Loop;
int R = R_Inside-1;
int x_start = Center_pos.x() + R * cos((Angle / 180) * Pai);
int y_start = Center_pos.y() + R * sin((Angle / 180) * Pai);
if(Loop % Div_Min == 0) //判断大小刻度
{
QPen pen(Qt::black);
pen.setWidth(2);
painter->setPen(pen);
R = R_Inside-20;
}
else
{
QPen pen(Qt::black);
pen.setWidth(2);
painter->setPen(pen);
R = R_Inside-15;
}
int x_end = Center_pos.x() + R * cos((Angle / 180) * Pai);
int y_end = Center_pos.y() + R * sin((Angle / 180) * Pai);
painter->drawLine(QPoint(x_start,y_start),QPoint(x_end,y_end));
}
painter->restore();
}
void Widget::Draw_Text(QPainter *painter)
{
painter->save();
QPen qPen(Qt::black);
qPen.setWidth(2);
painter->setPen(qPen);
QFont qFont("楷体",14,QFont::Bold,false);
painter->setFont(qFont);
int Dial_Text = 12;
for(int Loop = 0;Loop < Div_Max;Loop++)
{
if(Dial_Text >12 )
Dial_Text = 1;
int R = R_Inside-60;
float Angle = BaseAngle + (360 / Div_Max )*Loop;
int x = Center_pos.x() + R * cos((Angle / 180) * Pai);
int y = Center_pos.y() + R * sin((Angle / 180) * Pai);
painter->drawText(QRect(x-20,y-20,80,80),QString::number(Dial_Text++));
}
painter->restore();
}
void Widget::Draw_Pointer(QPainter *painter)
{
painter->save();
QBrush qBrush = QBrush(QColor(Qt::black));
painter->setBrush(qBrush);
QPen qPen(Qt::black);
qPen.setWidth(2);
painter->setPen(qPen);
//绘制秒针
float Angle = BaseAngle + (360 / (Div_Max * Div_Min))*Ss;
float RightAngle = Angle + 90;
float LeftAngle = Angle - 90;
int R = R_Inside-1;
int x_start = Center_pos.x() + R * cos((Angle / 180) * Pai);
int y_start = Center_pos.y() + R * sin((Angle / 180) * Pai);
R = R_Pointer-1;
int x_end1 = Center_pos.x() + R * cos(RightAngle * 3.14 / 180);
int y_end1 = Center_pos.y() + R * sin(RightAngle * 3.14 / 180);
int x_end2 = Center_pos.x() + R * cos(LeftAngle * 3.14 / 180);
int y_end2 = Center_pos.y() + R * sin(LeftAngle * 3.14 / 180);
QPointF qTriangle_S[3] = {QPoint(x_start,y_start),QPoint(x_end1,y_end1),QPoint(x_end2,y_end2)};
painter->drawPolygon(qTriangle_S,3);
//绘制分针
Angle = BaseAngle + (360 / (Div_Max * Div_Min))*Ms;
RightAngle = Angle + 90;
LeftAngle = Angle - 90;
R = R_Inside-60;
x_start = Center_pos.x() + R * cos((Angle / 180) * Pai);
y_start = Center_pos.y() + R * sin((Angle / 180) * Pai);
R = R_Pointer-1;
x_end1 = Center_pos.x() + R * cos(RightAngle * 3.14 / 180);
y_end1 = Center_pos.y() + R * sin(RightAngle * 3.14 / 180);
x_end2 = Center_pos.x() + R * cos(LeftAngle * 3.14 / 180);
y_end2 = Center_pos.y() + R * sin(LeftAngle * 3.14 / 180);
QPointF qTriangle_M[3] = {QPoint(x_start,y_start),QPoint(x_end1,y_end1),QPoint(x_end2,y_end2)};
painter->drawPolygon(qTriangle_M,3);
//绘制时针
Angle = BaseAngle + (360 / Div_Max)*Hs;
RightAngle = Angle + 90;
LeftAngle = Angle - 90;
R = R_Inside-120;
x_start = Center_pos.x() + R * cos((Angle / 180) * Pai);
y_start = Center_pos.y() + R * sin((Angle / 180) * Pai);
R = R_Pointer-1;
x_end1 = Center_pos.x() + R * cos(RightAngle * 3.14 / 180);
y_end1 = Center_pos.y() + R * sin(RightAngle * 3.14 / 180);
x_end2 = Center_pos.x() + R * cos(LeftAngle * 3.14 / 180);
y_end2 = Center_pos.y() + R * sin(LeftAngle * 3.14 / 180);
QPointF qTriangle_H[3] = {QPoint(x_start,y_start),QPoint(x_end1,y_end1),QPoint(x_end2,y_end2)};
painter->drawPolygon(qTriangle_H,3);
painter->restore();
}
效果图
最后附上一首李白的将进酒供大家欣赏:
将进酒
君不见黄河之水天上来,奔流到海不复回。
君不见高堂明镜悲白发,朝如青丝暮成雪。
人生得意须尽欢,莫使金樽空对月。
天生我材必有用,千金散尽还复来。
烹羊宰牛且为乐,会须一饮三百杯⑨。
与君歌一曲,请君为我倾耳听。
钟鼓馔玉不足贵,但愿长醉不复醒。
古来圣贤皆寂寞,惟有饮者留其名。
陈王昔时宴平乐,斗酒十千恣欢谑。
主人何为言少钱,径须沽取对君酌。
五花马、千金裘,呼儿将出换美酒,与尔同销万古愁。