14. 利用Canvas自制时钟组件
1. 说明
在自定义时钟组件时,使用到的基本控件主要是Canvas,在绘制相关元素时有两种方式:一种时在同一个canvas中绘制所有的部件元素,这样需要不断的对画笔和画布的属性进行保存和恢复,容易混乱;另一种就是创建多个canvas组件,每一部分的元素绘制都在各自的画布进行绘制,逻辑比较清晰,但是canvas组件会相对较多,本文使用的是第二种方式。
效果展示:

2. 整体代码
import QtQuick 2.15
import QtQuick.Controls 2.15Item{id:rootimplicitWidth: 400implicitHeight: implicitWidth// 尺寸属性property real outerCircleRadius:root.width / 2.05property real innerCircleRadius:root.width / 2.05// 颜色属性property color bgColor:"white"property color outerColor:"black"property color innerColor:"black"property color innerRootColor:"lightSlateGray"property color innerLineColorL:"#484D58"property color innerLineColorS:"#63677A"property color textColor:"black"property color hourLineColor:"#484D58"property color minuteLineColor:"#484D58"property color secondLineColor:"red"property color timeTxtColor:"black"// 时间属性property var hoursproperty var minutesproperty var secondsproperty var currentTimeproperty alias hoursAngle:hourLine.angleproperty alias minutesAngle:minuteLine.angleproperty alias secondsAngle:secondLine.angle// 组件加载完成后先初始化当前时间Component.onCompleted: {calculateAngle()}// 时间计算function calculateAngle(){var date = new Date()hours = date.getHours()// 模除得到12小时制的小时数hours = hours % 12minutes = date.getMinutes()seconds = date.getUTCSeconds()currentTime = hours + ":" + minutes + ":" + secondshoursAngle = Math.PI*2/12*hours+Math.PI*2*minutes/12/60-Math.PIminutesAngle = Math.PI*2*minutes/60 + Math.PI*2*seconds/60/60 -Math.PIsecondsAngle = Math.PI*2*seconds/60-Math.PI}// 绘制背景Canvas{id:bgCirclewidth: root.widthheight: root.heightanchors.centerIn: parentonPaint: {// 绘制背景var ctx = getContext("2d") ctx.save()ctx.lineWidth = root.width/50 ctx.fillStyle = bgColorctx.beginPath()ctx.arc(root.width/2,root.height/2,outerCircleRadius,0,Math.PI * (12/6))ctx.fill()ctx.restore()}}// 绘制圆环轮廓Canvas{id:outerCirclewidth: root.widthheight: root.heightanchors.centerIn: parentonPaint: {var ctx = getContext("2d") //创建画师//为画师创建画笔并设置画笔属性ctx.lineWidth = root.width/50 //设置画笔粗细ctx.strokeStyle = outerColor //设置画笔颜色ctx.beginPath() //每次绘制调用此函数,重新设置一个路径// 按照钟表刻度进行划分,一圈是Math.PI * 2,分成12个刻度,每个刻度占用 1/6// canvas绘制圆弧,是按照顺时针绘制,起点默认在三点钟方向ctx.arc(root.width/2,root.height/2,outerCircleRadius,0,Math.PI * (12/6))ctx.stroke() //根据strokeStyle对边框进行描绘}}// 绘制圆环内衬Canvas{id:innerCirclewidth: root.widthheight: root.heightanchors.centerIn: parentproperty real endAngle:Math.PI * (12/6)onPaint: {var ctx = getContext("2d") ctx.save()ctx.lineWidth = root.width/50 ctx.strokeStyle = innerColor ctx.beginPath() ctx.arc(root.width/2,root.height/2,innerCircleRadius,0,endAngle)ctx.stroke() ctx.restore()// 绘制指针根部圆圈ctx.save()ctx.lineWidth = root.width/50 ctx.fillStyle = innerRootColorctx.beginPath()ctx.arc(root.width/2,root.height/2,innerCircleRadius/16,0,endAngle)ctx.fill()ctx.restore()}}// 绘制刻度线Canvas{id:innerLinewidth: root.widthheight: root.heightanchors.centerIn: parentproperty real lineNums:60onPaint: {var ctx = getContext("2d") for (var i = 0; i <= lineNums; ++i){ctx.beginPath();var angle = 2 * Math.PI / 60 * i;var dx = Math.cos(angle)*(outerCircleRadius-15);var dy = Math.sin(angle)*(outerCircleRadius-15);var dx2 = Math.cos(angle)*(outerCircleRadius-7);var dy2 = Math.sin(angle)*(outerCircleRadius-7);if (i % 5 === 0){ctx.lineWidth = root.width/100ctx.strokeStyle = innerLineColorL}else{ctx.lineWidth = root.width/200ctx.strokeStyle = innerLineColorS}ctx.moveTo(root.width/2+dx,root.height/2+dy);ctx.lineTo(root.width/2+dx2,root.height/2+dy2);ctx.stroke();}}}// 绘制数字Canvas{id:drawTextwidth: root.widthheight: root.heightanchors.centerIn: parentproperty var numbers : [1,2,3,4,5,6,7,8,9,10,11,12]onPaint: {var ctx = getContext("2d") ctx.font = "18px Arial";ctx.textAlign = "center";ctx.textBaseline = "middle";for(var i = 0; i < 12; ++i){ctx.fillStyle = textColorvar angle = 2 * Math.PI / 12 * numbers[i] - 3.14 / 2;var dx = Math.cos(angle)*(outerCircleRadius-30);var dy = Math.sin(angle)*(outerCircleRadius-30);ctx.fillText(numbers[i],root.width/2 + dx,root.height / 2 + dy);ctx.fill()}}}// 绘制时针线Canvas{id:hourLinewidth: root.widthheight: root.heightanchors.centerIn: parentproperty real angleonPaint: {var ctx = getContext("2d") // 先清空画布上之前的内容ctx.clearRect(0,0,width,height)ctx.save()ctx.beginPath()ctx.lineWidth = root.width/100ctx.strokeStyle=hourLineColor// 平移坐标点(注意:坐标系原点先平移,再旋转)ctx.translate(root.width/2,root.height/2)// 旋转坐标系ctx.rotate(angle)// 坐标原点变化之后再进行实际的绘图ctx.moveTo(0,-20);ctx.lineTo(0,outerCircleRadius / 2 - 15);ctx.stroke()ctx.restore()}}// 绘制分针线Canvas{id:minuteLinewidth: root.widthheight: root.heightanchors.centerIn: parentproperty real angleonPaint: {var ctx = getContext("2d") ctx.clearRect(0,0,width,height)ctx.save()ctx.beginPath()ctx.lineWidth = root.width/100ctx.strokeStyle=minuteLineColor// 平移坐标点(注意:坐标系原点先平移,再旋转)ctx.translate(root.width/2,root.height/2)// 旋转坐标系ctx.rotate(angle)// 坐标原点变化之后再进行实际的绘图ctx.moveTo(0,-25);ctx.lineTo(0,outerCircleRadius / 2 - 5);ctx.stroke()ctx.restore()}}// 绘制秒针线Canvas{id:secondLinewidth: root.widthheight: root.heightanchors.centerIn: parentproperty real angleonPaint: {var ctx = getContext("2d") ctx.clearRect(0,0,width,height)ctx.save()ctx.beginPath()ctx.lineWidth = root.width/100ctx.strokeStyle=secondLineColor// 平移坐标点(注意:坐标系原点先平移,再旋转)ctx.translate(root.width/2,root.height/2)// 旋转坐标系ctx.rotate(angle)// 坐标原点变化之后再进行实际的绘图ctx.moveTo(0,-30);ctx.lineTo(0,outerCircleRadius / 1.5);ctx.stroke()ctx.restore()}}// 当前时间显示Text{id:timeTxty:root.height * 0.75anchors.horizontalCenter: root.horizontalCentertext: currentTimefont.pixelSize: root.width/12color: timeTxtColor}// 使用定时器(每秒钟进行计算)Timer{id:angleCalinterval: 1000repeat: truerunning: trueonTriggered: {calculateAngle()hourLine.requestPaint()minuteLine.requestPaint()secondLine.requestPaint()}}
}相关文章:
14. 利用Canvas自制时钟组件
1. 说明 在自定义时钟组件时,使用到的基本控件主要是Canvas,在绘制相关元素时有两种方式:一种时在同一个canvas中绘制所有的部件元素,这样需要不断的对画笔和画布的属性进行保存和恢复,容易混乱;另一种就是…...
微信小程序使用云存储和Markdown开发页面
最近想在一个小程序里加入一个使用指南的页面,考虑到数据存储和减少页面的开发工作量,决定尝试在云存储里上传Markdown文件,微信小程序端负责解析和渲染。小程序端使用到一个库Towxml。 Towxml Towxml是一个可将HTML、Markdown转为微信小程…...
【C++】运算符重载 | 赋值运算符重载
Ⅰ. 运算符重载 引入 ❓什么叫运算符重载? 就是:运用函数,将现有的运算符重新定义,使其能满足各种自定义类型的运算。 回想一下,我们以前运算的对象是不是都是int、char这种内置类型? 那我们自定义的“…...
Python学习 -- 类对象从创建到常用函数
在Python编程中,类是一种强大的工具,用于创建具有共同属性和行为的对象。本篇博客将详细介绍Python中类和对象的创建,类的属性和方法,以及一些常用的类函数,通过丰富的代码例子来帮助读者深入理解。 一、类和对象的创…...
数组分割(2023省蓝桥杯)n种讨论 JAVA
目录 1、题目描述:2、前言:3、动态规划(bug):3、递归 剪枝(超时):4、数学(正解): 1、题目描述: 小蓝有一个长度为 N 的数组 A [A0, A1,…, AN−…...
很好的启用window10专业版系统自带的远程桌面
启用window10专业版系统自带的远程桌面 文章目录 启用window10专业版系统自带的远程桌面前言1.找到远程桌面的开关2. 找到“应用”项目3. 打开需要远程操作的电脑远程桌面功能 总结 前言 Windows操作系统作为应用最广泛的个人电脑操作系统,在我们身边几乎随处可见。…...
TCP定制协议,序列化和反序列化
目录 前言 1.理解协议 2.网络版本计算器 2.1设计思路 2.2接口设计 2.3代码实现: 2.4编译测试 总结 前言 在之前的文章中,我们说TCP是面向字节流的,但是可能对于面向字节流这个概念,其实并不理解的,今天我们要介…...
YOLOX在启智AI GPU/CPU平台部署笔记
文章目录 1. 概述2. 部署2.1 拉取YOLOX源码2.2 拉取模型文件yolox_s.pth2.3 安装依赖包2.4 安装yolox2.5 测试运行2.6 运行报错处理2.6.1 ImportError: libGL.so.1: cannot open shared object file: No such file or directory2.6.2 ImportError: libgthread-2.0.so.0: cannot…...
23种设计模式攻关
👍一、创建者模式 🔖1.1、单例模式 单例模式(Singleton Pattern),用于确保一个类只有一个实例,并提供全局访问点。 在某些情况下,我们需要确保一个类只能有一个实例,比如数据库连接…...
【jsthreeJS】入门three,并实现3D汽车展示厅,附带全码
首先放个最终效果图: 三维(3D)概念: 三维(3D)是一个描述物体在三个空间坐标轴上的位置和形态的概念。相比于二维(2D)只有长度和宽度的平面,三维增加了高度或深度这一维度…...
unity将结构体/列表与json字符串相互转化
编写Unity程序时,面对大量需要传输或者保存的数据时,为了避免编写重复的代码,故采用NewtonJson插件来将定义好的结构体以及列表等转为json字符串来进行保存和传输。 具体代码如下: using System; using System.IO; using Newtons…...
【Vue】vue2项目使用swiper轮播图2023年8月21日实战保姆级教程
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、npm 下载swiper二、使用步骤1.引入库声明变量2.编写页面3.执行js 总结 前言 swiper轮播图官网 参考文章,最好先看完他的介绍,再看…...
【算法日志】贪心算法刷题:单调递增数列,贪心算法总结(day32)
代码随想录刷题60Day 目录 前言 单调递增数列 贪心算法总结 前言 今天是贪心算法刷题的最后一天,今天本来是打算刷两道题,其中的一道hard题做了好久都没有做出来(主要思路错了)。然后再总结一下。 单调递增数列 int monotoneIncreasingDigits(int n…...
MATLAB算法实战应用案例精讲-【深度学习】模型压缩
目录 模型压缩概述 1. 为什么需要模型压缩 2. 模型压缩的基本方法 Patient-KD 1. Patient-KD 简介...
Matlab使用
Matlab使用 界面介绍 新建脚本:实际上就是新建一个新建后缀为.m的文件 新建编辑器:ctrlN 打开:打开最近文件,以找到最近写过的文件 点击路径,切换当前文件夹 预设:定制习惯用的界面 常见简单指令 ;…...
BladeX多数据源配置
启用多租户数据库隔离,会默认关闭mybatis-plus多数据源插件的启动,从而使用自定义的数据源识别 若不需要租户数据库隔离只需要字段隔离,而又需要用到多数据源的情况,需要前往LauncherService单独配置 数据源切换失败 详情请看说明…...
go里面关于超时的设计
设想一下你在接收源源不断的数据,如果有700ms没有收到,则认为是一个超时,需要做出处理。 逻辑上可以设计一个grouting,里面放一个通道,每收到一条数据进行相应处理。通道中夹杂一个timer定时器的处理,若通道在700ms内…...
Qt下使用ModbusTcp通信协议进行PLC线圈/保持寄存器的读写(32位有符号数)
文章目录 前言一、引入Modbus模块二、Modbus设备的连接三、各寄存器数据的读取四、各寄存器数据的写入五、示例完整代码总结 前言 本文主要讲述了使用Qt的Modbus模块来进行ModbusTcp的通信,实现对PLC的线圈寄存器和保持寄存器的读写,基于TCP/IP的Modbus…...
ElasticSearch学习2
1、索引的操作 1、创建索引 对ES的操作其实就是发送一个restful请求,kibana中在DevTools中进行ES操作 创建索引时需要注意ES的版本,不同版本的ES创建索引的语句略有差别,会导致失败 如下创建一个名为people的索引,settings&…...
3D角色展示
先看效果: 再看代码: <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>3D卡片悬停</title><style>font-face {font-family: "Exoct";src: url("htt…...
龙虎榜——20250610
上证指数放量收阴线,个股多数下跌,盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型,指数短线有调整的需求,大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的:御银股份、雄帝科技 驱动…...
C++_核心编程_多态案例二-制作饮品
#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为:煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例,提供抽象制作饮品基类,提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...
基于Uniapp开发HarmonyOS 5.0旅游应用技术实践
一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架,支持"一次开发,多端部署",可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务,为旅游应用带来…...
ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...
JS手写代码篇----使用Promise封装AJAX请求
15、使用Promise封装AJAX请求 promise就有reject和resolve了,就不必写成功和失败的回调函数了 const BASEURL ./手写ajax/test.jsonfunction promiseAjax() {return new Promise((resolve, reject) > {const xhr new XMLHttpRequest();xhr.open("get&quo…...
08. C#入门系列【类的基本概念】:开启编程世界的奇妙冒险
C#入门系列【类的基本概念】:开启编程世界的奇妙冒险 嘿,各位编程小白探险家!欢迎来到 C# 的奇幻大陆!今天咱们要深入探索这片大陆上至关重要的 “建筑”—— 类!别害怕,跟着我,保准让你轻松搞…...
并发编程 - go版
1.并发编程基础概念 进程和线程 A. 进程是程序在操作系统中的一次执行过程,系统进行资源分配和调度的一个独立单位。B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。C.一个进程可以创建和撤销多个线程;同一个进程中…...
【Linux】自动化构建-Make/Makefile
前言 上文我们讲到了Linux中的编译器gcc/g 【Linux】编译器gcc/g及其库的详细介绍-CSDN博客 本来我们将一个对于编译来说很重要的工具:make/makfile 1.背景 在一个工程中源文件不计其数,其按类型、功能、模块分别放在若干个目录中,mak…...
规则与人性的天平——由高考迟到事件引发的思考
当那位身着校服的考生在考场关闭1分钟后狂奔而至,他涨红的脸上写满绝望。铁门内秒针划过的弧度,成为改变人生的残酷抛物线。家长声嘶力竭的哀求与考务人员机械的"这是规定",构成当代中国教育最尖锐的隐喻。 一、刚性规则的必要性 …...
MeshGPT 笔记
[2311.15475] MeshGPT: Generating Triangle Meshes with Decoder-Only Transformers https://library.scholarcy.com/try 真正意义上的AI生成三维模型MESHGPT来袭!_哔哩哔哩_bilibili GitHub - lucidrains/meshgpt-pytorch: Implementation of MeshGPT, SOTA Me…...
