• 数字时钟制作


    数字时钟程序,制作的出发点是因为参考程序太简单了,又想起了一个抖音挺火的数字时钟,后就开始创作这个小程序,这个数字时钟程序我也不是凭空捏造出来的,我参考的是一个windows小程序,也是时钟例子,绘制一个时分秒的时钟样式。

    本期的文章就介绍下数字时钟的制作过程,介绍的内容还是以未加缓存和动画的制作过程为主。

    我已经讲述了如何利用windows的API对窗口进行移动和追加菜单并对菜单功能进行实现,以及定时器的开启和使用。

    开启了定时器之后,在WM_TIMER消息处进行时钟的绘制

    在绘制之前我们需要了解下字体,因为数字时钟利用的是字体的旋转

    我封装了一个绘制旋转 n° 的函数,函数如下

    1. //绘制倾斜字体
    2. void DrawText(HDC hdc, int x, int y, int org, wchar_t szText[])
    3. {
    4.   SetTextAlign(hdc, TA_BOTTOM | TA_LEFT);  //修改锚点
    5.   HFONT ft = nullptr;            //字体句柄
    6.   ft = CreateFont(00, org * 100100falsefalsefalse, GB2312_CHARSET, 0000NULL);
    7.   SelectObject(hdc, ft);
    8.   TextOut(hdc, x, y, szText, wcslen(szText));
    9.   DeleteObject(ft);
    10. }

    在这里我们需要创建一个旋转 n° 的字体,创建规则如下

    1. hdc = GetDC(hWnd);
    2. //默认系统字体 
    3. HFONT ft = nullptr;    //字体句柄
    4. ft = CreateFont(0,    //字符的高度,如果给0,按默认高度来设置
    5.                 0,    //字符的宽度,如果给0,按高度横纵比来匹配宽度
    6.                 0,    //文字的倾斜角度,10表示1
    7.                 0,    //基线的倾斜角度
    8.                 100,  //字体的粗细,取值0-900400以下为细体,700以上为粗体
    9.                 false,//斜体,取值false,true
    10.                 false,//下划线,取值false,true
    11.                 false,//水平线,取值false,true
    12.                 GB2312_CHARSET,//字符集
    13.                 0,//输出精度
    14.                 0,//裁剪精度
    15.                 0,//字体的输出质量
    16.                 0,//字体的间距和系列
    17.                 NULL);//字样名
    18. SelectObject(hdc, ft);

    将旋转角度设置成函数参数,从而控制字体的旋转角度,然而在我封装的那段函数里面有修改锚点操作,这是为什么呢

    如果不进行该操作的话,字体旋转的锚点在左上角,旋转得到的字体不是预期的,对制作360°旋转的数字时钟达不到效果,我们需要设置锚点为左下角

    就这样封装好一个可以在某个DC的x,y位置上绘制倾斜角度为org的字符串szText,这样我们就准备好了绘制数字时钟的基本条件

    在WM_TIMER消息内

    获取客户区信息

    我们首先要得到DC和客户区大小,因为我们需要在窗口上完整的显示数字时钟,这需要数字时钟随客户区的大小改变而改变

    1.     HDC hdc = GetDC(hwnd);
    2.     RECT rt;
    3.     GetClientRect(hwnd, &rt);   //获取客户区大小
    4.     SetBkMode(hdc, TRANSPARENT);//设置文字背景透明

    设置坐标轴和坐标原点

    1.     //设置坐标轴
    2.     int cx = rt.right;
    3.     int cy = rt.bottom;
    4.     SetViewportExtEx(hdc, cx, cy, NULL);
    5.     //设置原点
    6.     SetViewportOrgEx(hdc, rt.right / 2, rt.bottom / 2NULL);

    获取系统时间

    1.     //获取系统时间
    2.     wchar_t szTime[100];
    3.     SYSTEMTIME currentTime;
    4.     GetLocalTime(¤tTime);

    定义变量

    1.     //定义相关变量
    2.     int i = 0;
    3.     int initOrg = 0;    //定义初始旋转角度
    4.     int minSize = 0;    //数字时钟最小半径
    5.     int date_x = 0;     //时间显示的x坐标

    在数字时钟制作过程中我的依据是通过一个圆圈的旋转使得x坐标轴上的时间为系统时间,上述变量中的变量initOrg是月份或者日期的第一个时间点的旋转角度

    变量data_x是时间绘制的横向坐标,使得月份,日期,时,分,秒在不同的圆周内

    其中minSize控制着data_x,使得数字时钟随客户区的大小改变而改变

    确定时钟最小半径

    1.     //确定时钟最小半径
    2.     if (rt.bottom > rt.right)
    3.     {
    4.         minSize = rt.right / 2;
    5.     }
    6.     else
    7.         minSize = rt.bottom / 2;

    通过之前得到的客户区大小从而确定数字时钟的最小半径,其实这里定义成最大半径更好理解,不知道为什当时脑袋犯抽写成了最小半径,不想改了

    这些准备工作完成之后就是真真的绘制环节

    首先绘制年份,要将年份绘制在最中间,在之前已经将坐标原点设置在客户区的中间了,所以我们需要进行的操作就是

    绘制年份

    1.     //绘制年
    2.     wsprintf(szTime, L"%d 年", currentTime.wYear);
    3.     DrawText(hdc, -3000, szTime);

    这个很简单通过将之前获取的时间写入到szTime里面,然后绘制在坐标(-30,0)处

    绘制月份

    1.     //绘制月
    2.     i = 1;
    3.     date_x = minSize / 6;
    4.     initOrg = -(currentTime.wMonth * 360 / 12+ 360 / 12;
    5.     for (int org = initOrg; org < initOrg + 360; org += (360 / 12))
    6.     {
    7.         wchar_t tempArr[MAX_PATH];
    8.         double temp = 3.1415926 * 2 * org / 360;
    9.         int x = date_x * cos(temp);
    10.         int y = -date_x * sin(temp);
    11.         wsprintf(tempArr, L"%d", i++);
    12.         DrawText(hdc, x, y, org, tempArr);
    13.     }
    14.     DrawText(hdc, date_x + 2000, L"月");

    这个月份的绘制就有点东西了啊,用到了数学里面的东西,首先月份是从1月开始,所以初始化i = 1;我将 年、月、日、时、分、秒绘制在6个同心圆处,相当于将minSize 6 等分,使得数字时钟看起来对称又有层次感

    然后初始旋转角度initOrg是通过 当前的月份 * 每个月份的度数,至于后面为什么又要加上360/12,也就是30,是因为月份是从1开始的,当currentTime.wMonth = 1;时,初始旋转角度initOrg应该为0,也就是不旋转。

    然后就是一个圆的循环,度数org从0增加到360°绘制月份,步长为 360/12 也就是30°,然后就是循环体内确定x,y坐标,就是圆圈上12个点的坐标,这里就是三角关系了,头文件加上math.h,定义变量temp将角度单位转化为弧度制,x,y坐标的计算方法就真的是纯数学了,不懂的可以去问初中数学老师。

    后面的代码和这个月份的都是一个样的,CV,然后修改一些变量就可以了,我源代码里面写的还算清楚,可以参考下。

  • 相关阅读:
    06 图形学——光照模型
    Python在WRF模型自动化运行及前后处理中的应用
    MongoDB的安装使用
    JAVA--类的继承
    深入理解数据库视图
    odoo15 crm 客户资料导出按钮的实现
    Matlab绘图(2)通过代码进行局部放大绘图、多文件绘图
    每日优鲜深陷“破产风波”,生鲜电商路在何方?
    数据驱动——新材料发展的新引擎
    【Java系列】LinkedList
  • 原文地址:https://blog.csdn.net/qq_31716541/article/details/132985219