当前位置: 首页 > news >正文

Qt:玩转QPainter后转之时钟(步骤详细、包含源码)

前言

简单了解了QPainter之后当然是要找两个例子练练手啦。

正文

先看效果图
在这里插入图片描述

在绘制之前我们要先构思好自己要绘制的对象可以分成几部分,比如我要绘制时钟的话,我可以分成:外边框(圆环或者圆),圆形背景,刻度,时间数字,秒针,分针,时针,中心点;
当然也可以不分这么细,或者分的更细,留下接口以实现更多的效果。

绘制外边框

ClockPainter::ClockPainter(QWidget *parent): QWidget(parent), ui(new Ui::ClockPainter)
{ui->setupUi(this);// 外半径outRadius = 108;// 内半径inRadius = 100;crownColorStart = QColor(255,0,0);crownColorEnd = QColor(64,156,250);
}void ClockPainter::paintEvent(QPaintEvent *)
{QPainter painter(this);// 设置图形和文本抗锯齿painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);// 将绘制点移动到窗口中心painter.translate(width() / 2, height() / 2);drawCrown(&painter);
}void ClockPainter::drawCrown(QPainter *painter)
{painter->save();// 接下来的绘制不用笔,如果没有填充的话将什么效果都没有painter->setPen(Qt::NoPen);// 渐变QLinearGradient gradient(-outRadius, -outRadius, outRadius, outRadius);gradient.setColorAt(0, crownColorStart);gradient.setColorAt(1, crownColorEnd);painter->setBrush(gradient);painter->drawEllipse(-outRadius, -outRadius, outRadius<<1, outRadius<<1);painter->restore();
}
效果

在这里插入图片描述

绘制背景

ClockPainter::ClockPainter(QWidget *parent): QWidget(parent), ui(new Ui::ClockPainter)
{ui->setupUi(this);// 外半径outRadius = 108;// 内半径inRadius = 100;crownColorStart = QColor(255,0,0);crownColorEnd = QColor(64,156,250);
}void ClockPainter::paintEvent(QPaintEvent *)
{QPainter painter(this);// 设置图形和文本抗锯齿painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);// 将绘制点移动到窗口中心painter.translate(width() / 2, height() / 2);drawCrown(&painter);drawBg(&painter);
}void ClockPainter::drawBg(QPainter *painter)
{painter->save();painter->setBrush(Qt::black);painter->drawEllipse(-inRadius, -inRadius, inRadius<<1, inRadius<<1);painter->restore();
}
效果

在这里插入图片描述

绘制刻度

void ClockPainter::drawScale(QPainter *painter)
{painter->save();QPen pen;pen.setColor(Qt::white);for (int i = 0; i < 60; ++i) {// 长的和短的粗细不一样if (i % 5 == 0) {pen.setWidth(2);pen.setCapStyle(Qt::RoundCap);painter->setPen(pen);painter->drawLine(inRadius - 8, 0, inRadius, 0);} else {pen.setWidth(1);painter->setPen(pen);painter->drawLine(inRadius - 4, 0, inRadius, 0);}painter->rotate(6);}painter->restore();
}void ClockPainter::paintEvent(QPaintEvent *)
{QPainter painter(this);// 设置图形和文本抗锯齿painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);// 将绘制点移动到窗口中心painter.translate(width() / 2, height() / 2);drawCrown(&painter);drawBg(&painter);drawScale(&painter);
}
效果

在这里插入图片描述

绘制时间数字

QRectF ClockPainter::textRectF(qreal radius, int pointSize, qreal angle)
{// 用于计算每个数字所在的矩形QRectF rectF;rectF.setX(radius*qCos(angle*M_PI/180.0) - pointSize*2);rectF.setY(radius*qSin(angle*M_PI/180.0) - pointSize/2.0);rectF.setWidth(pointSize*4);rectF.setHeight(pointSize*1.5);return rectF;
}void ClockPainter::drawScaleNum(QPainter *painter)
{painter->save();// 获取当前字体QFont font = painter->font();// 设置粗体font.setBold(true);painter->setFont(font);int pointSize = font.pointSize();painter->setPen(Qt::white);int nHour = 0;for (int i = 0; i < 12; ++i) {nHour = i + 3;if (nHour > 12)nHour -= 12;painter->drawText(textRectF(inRadius*0.8, pointSize, i * 30), Qt::AlignCenter, QString::number(nHour));}painter->restore();
}void ClockPainter::paintEvent(QPaintEvent *)
{QPainter painter(this);// 设置图形和文本抗锯齿painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);// 将绘制点移动到窗口中心painter.translate(width() / 2, height() / 2);drawCrown(&painter);drawBg(&painter);drawScale(&painter);drawScaleNum(&painter);
}
效果

在这里插入图片描述

绘制中心点

void ClockPainter::drawCenterDot(QPainter *painter)
{painter->save();painter->setPen(Qt::NoPen);QLinearGradient gradient(-10, -10, 10, 10);gradient.setColorAt(0, Qt::gray);gradient.setColorAt(0.2,Qt::black);gradient.setColorAt(1, Qt::gray);painter->setBrush(gradient);painter->drawEllipse(-5,-5,10,10);painter->restore();
}void ClockPainter::paintEvent(QPaintEvent *)
{QPainter painter(this);// 设置图形和文本抗锯齿painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);// 将绘制点移动到窗口中心painter.translate(width() / 2, height() / 2);drawCrown(&painter);drawBg(&painter);drawScale(&painter);drawScaleNum(&painter);drawCenterDot(&painter);}
效果

在这里插入图片描述

绘制秒针

void ClockPainter::drawSec(QPainter *painter)
{painter->save();// 接下来的绘制不用笔,如果没有填充的话将什么效果都没有painter->setPen(Qt::NoPen);// 画一个四边形,两头大,两头小painter->setBrush(Qt::gray);QPolygon polygon;polygon<<QPoint(-3,-2)<<QPoint(70,-1)<<QPoint(70,1)<<QPoint(-3,2);painter->drawPolygon(polygon);painter->restore();
}void ClockPainter::paintEvent(QPaintEvent *)
{QPainter painter(this);// 设置图形和文本抗锯齿painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);// 将绘制点移动到窗口中心painter.translate(width() / 2, height() / 2);drawCrown(&painter);drawBg(&painter);drawScale(&painter);drawScaleNum(&painter);drawSec(&painter);drawCenterDot(&painter);}
效果

在这里插入图片描述

绘制分针

void ClockPainter::drawMin(QPainter *painter)
{painter->save();// 接下来的绘制不用笔,如果没有填充的话将什么效果都没有painter->setPen(Qt::NoPen);// 画一个四边形,两头大,两头小painter->setBrush(Qt::gray);QPolygon polygon;polygon<<QPoint(-6,-3)<<QPoint(63,-2)<<QPoint(63,2)<<QPoint(-6,3);painter->drawPolygon(polygon);painter->restore();
}void ClockPainter::paintEvent(QPaintEvent *)
{QPainter painter(this);// 设置图形和文本抗锯齿painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);// 将绘制点移动到窗口中心painter.translate(width() / 2, height() / 2);drawCrown(&painter);drawBg(&painter);drawScale(&painter);drawScaleNum(&painter);drawMin(&painter);drawSec(&painter);drawCenterDot(&painter);}
效果

在这里插入图片描述

绘制时针

void ClockPainter::drawHour(QPainter *painter)
{painter->save();// 接下来的绘制不用笔,如果没有填充的话将什么效果都没有painter->setPen(Qt::NoPen);// 画一个四边形,两头大,两头小painter->setBrush(Qt::gray);QPolygon polygon;polygon<<QPoint(-6,-4)<<QPoint(50,-3)<<QPoint(50,3)<<QPoint(-6,4);painter->drawPolygon(polygon);painter->restore();
}void ClockPainter::paintEvent(QPaintEvent *)
{QPainter painter(this);// 设置图形和文本抗锯齿painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);// 将绘制点移动到窗口中心painter.translate(width() / 2, height() / 2);drawCrown(&painter);drawBg(&painter);drawScale(&painter);drawScaleNum(&painter);drawHour(&painter);drawMin(&painter);drawSec(&painter);drawCenterDot(&painter);}
效果

在这里插入图片描述

其实从话指针就很容易看出来,只要会画一个,其余的就改动一点,代码重复性极高

添加定时器使得指针动起来

ClockPainter::ClockPainter(QWidget *parent): QWidget(parent), ui(new Ui::ClockPainter)
{ui->setupUi(this);// 外半径outRadius = 108;// 内半径inRadius = 100;crownColorStart = QColor(255,0,0);crownColorEnd = QColor(64,156,250);// 初始化时间QTime time = QTime::currentTime();hour = time.hour();min = time.minute();sec = time.second();// 初始化定时器timer = new QTimer(this);connect(timer, &QTimer::timeout, this, &ClockPainter::updateTime);// 设置时间间隔为1stimer->start(1000);}
void ClockPainter::updateTime()
{QTime time = QTime::currentTime();hour = time.hour();// 12小时制if (hour > 12) {hour -= 12;}min = time.minute();sec = time.second();// 更新图像update();
}
//关键是要在相应的绘制指针的函数中调用rotate函数,使得绘制的图像旋转
效果

总体代码

这里我定义了指针的颜色,但是我并没有使用,是想留一个接口进行下一步开发。
头文件

#ifndef CLOCKPAINTER_H
#define CLOCKPAINTER_H#include <QWidget>QT_BEGIN_NAMESPACE
namespace Ui { class ClockPainter; }
QT_END_NAMESPACEclass ClockPainter : public QWidget
{Q_OBJECTpublic:ClockPainter(QWidget *parent = nullptr);~ClockPainter();protected:void paintEvent(QPaintEvent *);// 画外边框void drawCrown(QPainter *painter);// 画背景void drawBg(QPainter *painter);// 画刻度void drawScale(QPainter *painter);// 画刻度上的数字void drawScaleNum(QPainter *painter);// 时针void drawHour(QPainter *painter);// 分针void drawMin(QPainter *painter);// 秒针void drawSec(QPainter *painter);// 画中心点void drawCenterDot(QPainter *painter);// 处理数字位置QRectF textRectF(qreal radius, int pointSize, qreal angle);private slots:void updateTime();
private:Ui::ClockPainter* ui;// 外边框半径int outRadius;// 内边框半径int inRadius;// 外边框渐变开始颜色QColor crownColorStart;// 外边框渐变结束颜色QColor crownColorEnd;// 背景色QColor background;// 时钟指针颜色QColor pointerHourColor;// 分钟指针颜色QColor pointerMinColor;// 秒钟指针颜色QColor pointerSecColor;// 定时器绘制QTimer *timer;// 时分秒int hour, min, sec;
};#endif // CLOCKPAINTER_H

源文件

#include "clockpainter.h"
#include "ui_clockpainter.h"
#include "qpainter.h"
#include "qpen.h"
#include "qcolor.h"
#include "qpolygon.h"
#include "qfont.h"
#include "qtimer.h"
#include "qmath.h"
#include "qrect.h"
#include "qtransform.h"
#include <QTime>
#include <QLinearGradient>
#include "qdebug.h"ClockPainter::ClockPainter(QWidget *parent): QWidget(parent), ui(new Ui::ClockPainter)
{ui->setupUi(this);// 外半径outRadius = 108;// 内半径inRadius = 100;crownColorStart = QColor(255,0,0);crownColorEnd = QColor(64,156,250);// 初始化时间QTime time = QTime::currentTime();hour = time.hour();min = time.minute();sec = time.second();// 初始化定时器timer = new QTimer(this);connect(timer, &QTimer::timeout, this, &ClockPainter::updateTime);// 设置时间间隔为1stimer->start(1000);}ClockPainter::~ClockPainter()
{delete ui;
}void ClockPainter::paintEvent(QPaintEvent *)
{QPainter painter(this);// 设置图形和文本抗锯齿painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);// 将绘制点移动到窗口中心painter.translate(width() / 2, height() / 2);drawCrown(&painter);drawBg(&painter);drawScale(&painter);drawScaleNum(&painter);drawHour(&painter);drawMin(&painter);drawSec(&painter);drawCenterDot(&painter);}void ClockPainter::drawCrown(QPainter *painter)
{painter->save();// 接下来的绘制不用笔,如果没有填充的话将什么效果都没有painter->setPen(Qt::NoPen);// 渐变QLinearGradient gradient(-outRadius, -outRadius, outRadius, outRadius);gradient.setColorAt(0, crownColorStart);gradient.setColorAt(1, crownColorEnd);painter->setBrush(gradient);painter->drawEllipse(-outRadius, -outRadius, outRadius<<1, outRadius<<1);painter->restore();
}void ClockPainter::drawBg(QPainter *painter)
{painter->save();painter->setBrush(Qt::black);painter->drawEllipse(-inRadius, -inRadius, inRadius<<1, inRadius<<1);painter->restore();
}void ClockPainter::drawScale(QPainter *painter)
{painter->save();QPen pen;pen.setColor(Qt::white);for (int i = 0; i < 60; ++i) {// 长的和短的粗细不一样if (i % 5 == 0) {pen.setWidth(2);pen.setCapStyle(Qt::RoundCap);painter->setPen(pen);painter->drawLine(inRadius - 8, 0, inRadius, 0);} else {pen.setWidth(1);painter->setPen(pen);painter->drawLine(inRadius - 4, 0, inRadius, 0);}painter->rotate(6);}painter->restore();
}void ClockPainter::drawScaleNum(QPainter *painter)
{painter->save();// 获取当前字体QFont font = painter->font();// 设置粗体font.setBold(true);painter->setFont(font);int pointSize = font.pointSize();painter->setPen(Qt::white);int nHour = 0;for (int i = 0; i < 12; ++i) {nHour = i + 3;if (nHour > 12)nHour -= 12;painter->drawText(textRectF(inRadius*0.8, pointSize, i * 30), Qt::AlignCenter, QString::number(nHour));}painter->restore();
}void ClockPainter::drawHour(QPainter *painter)
{painter->save();// 接下来的绘制不用笔,如果没有填充的话将什么效果都没有painter->setPen(Qt::NoPen);// 画一个四边形,两头大,两头小painter->setBrush(Qt::gray);QPolygon polygon;polygon<<QPoint(-6,-4)<<QPoint(50,-3)<<QPoint(50,3)<<QPoint(-6,4);// 旋转,角度需要减去90,因为不减的话,是从12开始计算角度painter->rotate(30.0 * ((hour + min / 60.0)) - 90);painter->drawPolygon(polygon);painter->restore();
}void ClockPainter::drawMin(QPainter *painter)
{painter->save();// 接下来的绘制不用笔,如果没有填充的话将什么效果都没有painter->setPen(Qt::NoPen);// 画一个四边形,两头大,两头小painter->setBrush(Qt::gray);QPolygon polygon;polygon<<QPoint(-6,-3)<<QPoint(63,-2)<<QPoint(63,2)<<QPoint(-6,3);// 旋转,角度需要减去90,因为不减的话,是从12开始计算角度painter->rotate(6.0 * (min + sec / 60.0) - 90);painter->drawPolygon(polygon);painter->restore();
}void ClockPainter::drawSec(QPainter *painter)
{painter->save();// 接下来的绘制不用笔,如果没有填充的话将什么效果都没有painter->setPen(Qt::NoPen);// 画一个四边形,两头大,两头小painter->setBrush(Qt::gray);QPolygon polygon;polygon<<QPoint(-3,-2)<<QPoint(70,-1)<<QPoint(70,1)<<QPoint(-3,2);// 旋转,角度需要减去90,因为不减的话,是从12开始计算角度painter->rotate(6.0 * sec - 90);painter->drawPolygon(polygon);painter->restore();
}void ClockPainter::drawCenterDot(QPainter *painter)
{painter->save();painter->setPen(Qt::NoPen);QLinearGradient gradient(-10, -10, 10, 10);gradient.setColorAt(0, Qt::gray);gradient.setColorAt(0.2,Qt::black);gradient.setColorAt(1, Qt::gray);painter->setBrush(gradient);painter->drawEllipse(-5,-5,10,10);painter->restore();
}QRectF ClockPainter::textRectF(qreal radius, int pointSize, qreal angle)
{// 用于计算每个数字所在的矩形QRectF rectF;rectF.setX(radius*qCos(angle*M_PI/180.0) - pointSize*2);rectF.setY(radius*qSin(angle*M_PI/180.0) - pointSize/2.0);rectF.setWidth(pointSize*4);rectF.setHeight(pointSize*1.5);return rectF;
}void ClockPainter::updateTime()
{QTime time = QTime::currentTime();hour = time.hour();// 12小时制if (hour > 12) {hour -= 12;}min = time.minute();sec = time.second();// 更新图像update();
}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Notepad++ 下载安装教程
  • 未来出行:高效智能的汽车充电桩
  • 亚信安慧AntDB数据库与华为DPA数据保护一体机完成兼容性互认证,共筑数据安全与效率新高地
  • 使用Conda内部环境的CUDA而不是系统层面上安装的CUDA
  • 【专题】2024年8月医药行业报告合集汇总PDF分享(附原数据表)
  • JS设计模式之“分即是合” - 建造者模式
  • Deep Ocr
  • 828华为云征文|华为云服务器Flexus X搭建悟空crm管理系统——助力企业云上管理(解决APP Referer校验失败问题)
  • Linux中的Vim文本编辑器
  • 设计模式之装饰器模式:让对象功能扩展更优雅的艺术
  • elementUI table 给表头添加气泡显示(鼠标悬浮显示注释)
  • Spring扩展点系列-InstantiationAwareBeanPostProcessor
  • 用ACF和PACF计算出一堆数据的周期个数以及周期时长,数据分析python
  • 【区块链 + 物联网】区块链边缘计算网关设备 | FISCO BCOS应用案例
  • 鸿蒙Next-拉起支付宝的三种方式——教程
  • AHK 中 = 和 == 等比较运算符的用法
  • CentOS 7 防火墙操作
  • Computed property XXX was assigned to but it has no setter
  • java B2B2C 源码多租户电子商城系统-Kafka基本使用介绍
  • JAVA_NIO系列——Channel和Buffer详解
  • open-falcon 开发笔记(一):从零开始搭建虚拟服务器和监测环境
  • Python 基础起步 (十) 什么叫函数?
  • Redux系列x:源码分析
  • vue 配置sass、scss全局变量
  • vue-cli3搭建项目
  • vuex 学习笔记 01
  • 安卓应用性能调试和优化经验分享
  • 汉诺塔算法
  • 缓存与缓冲
  • 精彩代码 vue.js
  • 开放才能进步!Angular和Wijmo一起走过的日子
  • 浅析微信支付:申请退款、退款回调接口、查询退款
  • 三栏布局总结
  • 使用Tinker来调试Laravel应用程序的数据以及使用Tinker一些总结
  • 数据可视化之 Sankey 桑基图的实现
  • 再谈express与koa的对比
  • 正则与JS中的正则
  • 格斗健身潮牌24KiCK获近千万Pre-A轮融资,用户留存高达9个月 ...
  • ​ssh-keyscan命令--Linux命令应用大词典729个命令解读
  • # 利刃出鞘_Tomcat 核心原理解析(七)
  • #13 yum、编译安装与sed命令的使用
  • #我与Java虚拟机的故事#连载07:我放弃了对JVM的进一步学习
  • (1)Map集合 (2)异常机制 (3)File类 (4)I/O流
  • (12)Linux 常见的三种进程状态
  • (ZT)薛涌:谈贫说富
  • (翻译)Entity Framework技巧系列之七 - Tip 26 – 28
  • (力扣记录)1448. 统计二叉树中好节点的数目
  • (七)Activiti-modeler中文支持
  • (转)ABI是什么
  • (转)linux自定义开机启动服务和chkconfig使用方法
  • (转载)Linux 多线程条件变量同步
  • ***详解账号泄露:全球约1亿用户已泄露
  • ./mysql.server: 没有那个文件或目录_Linux下安装MySQL出现“ls: /var/lib/mysql/*.pid: 没有那个文件或目录”...
  • .dwp和.webpart的区别
  • .net Application的目录