利用QPainter 和QTimer 来实现精美的数字时钟。
QPainter 提供了 2D 绘图的常用操作,QTimer 提供了定时器功能,将两者相结合,绘制一个特效精美的指针式时钟。
通过使用 QTimer 定时刷新,设置时间为 1000 毫秒(1 秒)。
通过 paintEvent() 实现指针刻度以及背景的绘制,包括:时针、分针、秒针、及面板、表盘等。
选择界面
可选择时钟的大小以及风格,
点击OK按钮选择界面消失,
在源码可修改背景的文字以及图片。
没有安装QT的同学需要这个小程序也可以下载,我已经打包成可执行程序了。
下载地址链接:https://pan.baidu.com/s/1IpljEiIJ7r6DQxX9iGa8zA?pwd=syxu
提取码:syxu
Polygon:
闹钟头文件analogclock.h
#ifndef ANALOGCLOCK_H
#define ANALOGCLOCK_H
#include <QWidget>
#include<QObject>
#include <QMouseEvent>
#include <QPainter>
#include <QTime>
#include <QTimer>
#include <cmath>
#include "user.h"
namespace Ui {
class AnalogClock;
}
class AnalogClock : public QWidget
{
Q_OBJECT
public:
explicit AnalogClock(QWidget *parent = nullptr);
~AnalogClock();
private:
Ui::AnalogClock *ui;
//绘图
void paintEvent(QPaintEvent *e);
//切换深色浅色时改变几何图案的大小
int m_size = 0;
//求出正多边形的坐标:函数名(边数,外接圆半径,存放x坐标的数组,存放y坐标的数组)
void polygon(int edge, int r, double[], double[]);
void polygon2(int edge, int r, double[], double[]);
//鼠标
//标记
int mouse_flag = 0;
//鼠标点击的坐标
int mouse_x ;
int mouse_y;
//鼠标点击的次数
int m_clickClose = 0;
int m_clickColor = 0;
//鼠标按下
void mousePressEvent(QMouseEvent *ev);
//鼠标释放
void mouseReleaseEvent(QMouseEvent *ev);
//鼠标移动
void mouseMoveEvent(QMouseEvent *ev);
//定时器
QTimer *m_timer;
//时针 分针 秒针的颜色 (默认深色)
QColor hourColor;
QColor minuteColor;
QColor secondColor;
//使用说明
User *m_user;
};
#endif // ANALOGCLOCK_H
闹钟源文件analogclock.cpp
#include "analogclock.h"
#include "ui_analogclock.h"
#include "user.h"
#include <QDebug>
# pragma execution_character_set("utf-8")
#define M_PI 3.1415926
AnalogClock::AnalogClock(QWidget *parent) :
QWidget(parent),
ui(new Ui::AnalogClock)
{
ui->setupUi(this);
//初始化
m_user = new User;
//设置窗体大小
resize(m_user->m_x, m_user->m_y);
//设置标题
this->setWindowTitle("MyClock");
//设置无边框 显示置顶
setWindowFlags(Qt::FramelessWindowHint | Qt::Tool |Qt::WindowStaysOnTopHint);
//设置透明度
setAttribute(Qt::WA_TranslucentBackground);
//刷新时间1000ms
m_timer= new QTimer(this);
m_timer->start(1000);
connect(m_timer,SIGNAL(timeout()),this,SLOT(update()));
//分针时针秒针颜色设置rgba
hourColor = QColor(0,0,0,120);
minuteColor = QColor(112,127,127,121);
secondColor = QColor(225,0,0,100);
}
AnalogClock::~AnalogClock()
{
delete ui;
}
//由于系统窗口设置为Qt::FramelessWindowHint会导致窗口无法拖动,通过捕获鼠标移动事件从而实现窗口移动
//鼠标按下
void AnalogClock::mousePressEvent(QMouseEvent *ev)
{
mouse_flag = 1;
mouse_x = ev->x();
mouse_y = ev->y();
if(ev->button()==Qt::RightButton)
{
//每点击一次右键 m_clickClose+1
m_clickClose++;
if(m_clickClose==3)
this->close();
}
if(ev->button()==Qt::LeftButton)
{
m_clickClose++;
//点击两次后时钟变成浅色或者深色
if(m_clickColor==2)
{
m_size = 10;
this->hourColor= QColor(253,224,224,150);
this->minuteColor = QColor(112,127,127,121);
this->secondColor = QColor(250,250,225,115);
}
if(m_clickColor==4)
{
m_size=0;
this->hourColor= QColor(0,0,0,120);
this->minuteColor = QColor(112,127,127,121);
this->secondColor = QColor(250,0,0,100);
m_clickColor = 0;
}
}
}
//鼠标释放
void AnalogClock::mouseReleaseEvent(QMouseEvent *ev)
{
Q_UNUSED(ev);
mouse_flag = 0;
}
//鼠标移动
void AnalogClock::mouseMoveEvent(QMouseEvent *ev)
{
if(mouse_flag==1)
{
int x = this->x()+ev->x();
int y = this->y()+ev->y();
setGeometry(x-mouse_x, y-mouse_y,m_user->m_x,m_user->m_y);
}
}
//绘图
void AnalogClock::paintEvent(QPaintEvent *event)
{ Q_UNUSED(event);
//根据选择的大小改变时钟的大小
resize(m_user->m_x,m_user->m_y);
QPainter p(this);
//绘制时分秒针
//四边形的点坐标数据,目前原点还在左上角,后面会移动到窗口中心
//qwindow坐标y是反的,负数表示朝上
//点的顺序要么为逆时针,要么为顺时针
static const QPoint hourHand[5]=
{
QPoint(3,5),
QPoint(3,-50),
QPoint(0,-52),
QPoint(-3,-50),
QPoint(-3,5)
};
static const QPoint minuteHand[5]=
{
QPoint(2,5),
QPoint(2,-78),
QPoint(0,-80),
QPoint(-2,-78),
QPoint(-2,5)
};
static const QPoint secondHand[5]=
{
QPoint(1,15),
QPoint(1,-85),
QPoint(0,-90),
QPoint(-1,-85),
QPoint(-1,15)
};
//开始抗锯齿
p.setRenderHint(QPainter::Antialiasing);
//所有的点都进行一次位移,也就是将整个图片的原点从左上角移动到中心
p.translate(width()/2,height()/2);
//根据窗口大小进行缩放
int side = qMin(width(),height());
p.scale(side/200.0,side/200.0);
//获取当前时间
QTime time = QTime::currentTime();
//时针
//不需要边框,填充就行
p.setPen(Qt::NoPen);
p.setBrush(hourColor);
p.save();
//根据时间值计算角度
p.rotate(30.0*((time.hour()+time.minute()/60.0)));
//drawConvexPolygon绘制凸多边形
p.drawConvexPolygon(hourHand,5);
p.restore();
//小时的刻度线
if(!m_user->in_style)
//画笔的颜色和宽度
p.setPen(QPen(hourColor,1.5));
else {
p.setPen(QPen(hourColor,2.5));
}
for(int i = 0;i<12;++i)
{
if(!m_user->in_style)
{
p.drawLine(88,0,96,0);
p.rotate(30.0);
}
else {
//几何风格下的数字时钟
if(i==0||i==3||i==6||i==9)
{
if(i==0)
p.drawText(-20,-64,40,40,Qt::AlignHCenter|Qt::AlignTop,"12");
if(i==3)
p.drawText(-20,-64,40,40,Qt::AlignHCenter|Qt::AlignTop,"3");
if(i==6)
p.drawText(-20,-64,40,40,Qt::AlignHCenter|Qt::AlignTop,"9");
if(i==9)
p.drawText(-20,-64,40,40,Qt::AlignHCenter|Qt::AlignTop,"9");
}
else {
p.drawLine(54,0,62,0);
}
p.rotate(30.0);
}
}
//分针
p.setPen(Qt::NoPen);
if(!m_user->in_style)
//画笔的颜色和宽度
p.setBrush(minuteColor);
else {
p.setBrush(hourColor);
}
p.save();
//1min6°
p.rotate(6.0*(time.minute()+time.second()/60.0));
p.drawConvexPolygon(minuteHand,5);
p.restore();
p.setPen(minuteColor);
if(!m_user->in_style)
{
//分钟刻度线
for(int j=0;j<60;++j)
{
if((j%5)!=0)
p.drawLine(91,0,96,0);
p.rotate(6.0);
}
//秒针
p.setPen(Qt::NoPen);
p.setBrush(secondColor);
p.save();
//1s6°
p.rotate(6.0*time.second());
p.drawConvexPolygon(secondHand,5);
p.restore();
}
//圆心
p.setPen(Qt::NoPen);
p.setBrush(hourColor);
//画圆
p.drawEllipse(-6,-6,13,13);
p.setBrush(QColor(255,255,255,100));
p.drawEllipse(-2,-2,5,5);
if(m_user->in_style)
{
//polygon
//倒着的正五边形
double P_x[5];
double P_y[5];
polygon(5,80-4*m_size,P_x,P_y);
p.setPen(QPen(hourColor,0.5));
p.setBrush(QColor(255,255,255,0));
QPolygon duo = QPolygon();
for(int i =0;i<5;i++)
{
duo <<QPoint(P_x[i],P_y[i]);
}
p.drawPolygon(duo);
//正五边形
QPolygon duo1 = QPolygon();
for(int i =0;i<5;i++)
{
duo1 <<QPoint(-P_x[i],-P_y[i]);
}
p.drawPolygon(duo1);
//正十边形
double P_x1[10];
double P_y1[10];
polygon(10,80-4*m_size,P_x1,P_y1);
QPolygon duo2 = QPolygon();
for(int i =0;i<10;i++)
{
duo2 <<QPoint(P_x1[i],P_y1[i]);
}
p.drawPolygon(duo2);
//点不在轴上的正十边形
double P_x2[10];
double P_y2[10];
polygon(10,85-4*m_size,P_x2,P_y2);
QPolygon duo3 = QPolygon();
for(int i =0;i<10;i++)
{
duo3 <<QPoint(P_x2[i],P_y2[i]);
}
p.setPen(QPen(hourColor,2));
p.drawPolygon(duo3);
//九个点的连线
p.rotate(6.0*time.second());
p.setPen(QPen(hourColor,0.5));
double P_x3[5];
double P_y3[5];
polygon(5,27-m_size,P_x3,P_y3);
QPolygon duo4 = QPolygon();
for(int i =1;i<5;i++)
{
duo4 <<QPoint(P_x3[i],P_y3[i])<<QPoint(-P_x3[i],-P_y3[i]);
}
p.drawPolygon(duo4);
//十边形缺一个点变成九变行
p.setPen(hourColor);
double P_x4[10];
double P_y4[10];
polygon(10,27-m_size,P_x4,P_y4);
QPolygon duo5 = QPolygon();
for(int i =1;i<10;i++)
{
duo5 <<QPoint(P_x4[i],P_y4[i]);
}
p.drawPolygon(duo5);
}
}
//Polygon
// 起点在y轴上
void AnalogClock::polygon(int edge, int r, double P_x[], double P_y[])
{
double angle;
angle=2*M_PI/edge;
for (int i=0;i<edge;i++) {
angle=i*2*M_PI/edge;
P_x[i]=sin(angle)*r;
P_y[i]=cos(angle)*r;
}
}
//起点不在y轴上
void AnalogClock::polygon2(int edge, int r, double P_x[], double P_y[])
{
double angle;
double angle2;
angle=2*M_PI/edge;
angle2=M_PI/edge;
for (int i=0;i<edge;i++) {
angle=i*2*M_PI/edge+angle2;
P_x[i]=sin(angle)*r;
P_y[i]=cos(angle)*r;
}
}
由于篇幅有限,剩下代码见下一篇文章。