需求

有智能手表的人都知道,前段时间的“太空人表盘”非常火热。被称为6块钱的快乐。但其实动手做这样一款太空人表盘并不难。我们也可以自己动手来制作一款太空人表盘。经过我的一番研究,总算制作成功了。今天就来分享给大家。

准备

  • Visual Studio 2019
  • EasyX Graphics Library :Visual C++ 的免费绘图库
程序huawei.h
  1. #ifndef _HUAWEI_H_
  2. #define _HUAWEI_H_
  3. #include<graphics.h>
  4. void SetWindowNewStyle(int w, int h)
  5. {
  6.         // 去掉标题
  7.         SetWindowLong(GetHWnd(), GWL_STYLE, GetWindowLong(GetHWnd(), GWL_STYLE) & ~WS_CAPTION);
  8.         // 初始化界面为圆形
  9.         SetWindowRgn(GetHWnd(), CreateEllipticRgn(0, 0, w, h), true);
  10. }
  11. //png透明贴图
  12. void drawImg(IMAGE* pimg, int x, int y)
  13. {
  14.         // 变量初始化
  15.         DWORD* dst = GetImageBuffer();
  16.         DWORD* src = GetImageBuffer(pimg);
  17.         int dst_width = ::getwidth();                        //窗口宽高
  18.         int dst_height = ::getheight();
  19.         int _w = pimg->getwidth();
  20.         int _h = pimg->getheight();
  21.         // 计算贴图的实际长宽
  22.         int iwidth = (x + _w > dst_width) ? dst_width - x : _w;                // 处理超出右边界
  23.         int iheight = (y + _h > dst_height) ? dst_height - y : _h;        // 处理超出下边界
  24.         if (x < 0) { src += -x;                                iwidth -= -x;        x = 0; }                                // 处理超出左边界
  25.         if (y < 0) { src += (_w * -y);        iheight -= -y;        y = 0; }                                // 处理超出上边界
  26.                                                                                                                                                 // 修正贴图起始位置
  27.         dst += (dst_width * y + x);
  28.         // 实现透明贴图
  29.         for (int iy = 0; iy < iheight; iy++)
  30.         {
  31.                 for (int ix = 0; ix < iwidth; ix++)
  32.                 {
  33.                         byte a = (byte)(src[ix] >> 24);//计算透明通道的值[0,256) 0为完全透明 255为完全不透明
  34.                         if (a > 100)
  35.                         {
  36.                                 dst[ix] = src[ix];
  37.                         }
  38.                 }
  39.                 //换到下一行
  40.                 dst += dst_width;
  41.                 src += _w;
  42.         }
  43. }
  44. //去掉窗口标题以后,能够点击移动窗口
  45. void mouseEvent()
  46. {
  47.         //求鼠标相对于当前窗口左上角的坐标(即鼠标距离窗口左上的的宽度和高度)
  48.         static POINT WndPtSize;
  49.         static bool isMove = false;
  50.         if (MouseHit())
  51.         {
  52.                 MOUSEMSG msg = GetMouseMsg();
  53.                 if (msg.uMsg == WM_LBUTTONDOWN)        //左键按下
  54.                 {
  55.                         //获取窗口相对与屏幕左上角的 左上角坐标,和右下角坐标
  56.                         RECT wndRect;
  57.                         GetWindowRect(GetHWnd(), &wndRect);
  58.                         //获取鼠标光标相对于屏幕的坐标
  59.                         POINT curPos;
  60.                         GetCursorPos(&curPos);
  61.                         //求鼠标相对于当前窗口左上角的坐标
  62.                         WndPtSize.x = curPos.x - wndRect.left;
  63.                         WndPtSize.y = curPos.y - wndRect.top;
  64.                         isMove = true;
  65.                 }
  66.                 else if (msg.uMsg == WM_LBUTTONUP)//左键弹起
  67.                 {
  68.                         isMove = false;
  69.                 }
  70.                 else if (msg.uMsg == WM_MOUSEMOVE)//鼠标移动
  71.                 {
  72.                         if (isMove)
  73.                         {
  74.                                 POINT CursorPos;
  75.                                 GetCursorPos(&CursorPos);
  76.                                 /*把窗口移动到屏幕的x,y的位置
  77.                                 * @hwnd:窗口句柄
  78.                                 * @hwndInsertAfter:窗口的z顺序  HWND_TOPMOST {在前面, 位于任何顶部窗口的前面}
  79.                                 * @X,Y: 窗口左上角的新位置(相对于屏幕)
  80.                                 * @cx,xy: 窗口大小
  81.                                 * @uFlags:SWP_NOSIZE {忽略 cx、cy, 保持大小}
  82.                                 */
  83.                                 SetWindowPos(GetHWnd(), HWND_TOPMOST, CursorPos.x - WndPtSize.x, CursorPos.y - WndPtSize.y, 0, 0, SWP_NOSIZE);
  84.                                 //CursorPos.x - WndPtSize.x        //获取当前窗口左上角相对于屏幕的坐标
  85.                                 //CursorPos.y - WndPtSize.y
  86.                                 //printf("%d %d\n", CursorPos.x - WndPtSize.x, CursorPos.y - WndPtSize.y);
  87.                         }
  88.                 }
  89.                 else if (msg.uMsg == WM_RBUTTONDOWN)//右键按下
  90.                 {
  91.                         exit(0);
  92.                 }
  93.         }
  94. }
  95. #endif // !_TOOLS_H_
huawei.c
  1. #include <stdio.h>
  2. #include <time.h>
  3. #include "huawei.h"
  4. #include <mmsystem.h>
  5. #pragma comment(lib,"winmm.lib")
  6. #pragma warning(disable:4996)
  7. /*
  8. 1,文本字体设置
  9. 2,图片动画效果
  10. 3,绘制表盘
  11. */
  12. #define WIN_SIZE 500
  13. #define WIN_HALF (WIN_SIZE/2)        //窗口的一半
  14. IMAGE spaceMan[59];
  15. IMAGE other[6];
  16. const char *week[7] = { "日","一","二","三","四","五","六" };
  17. void setTextStyle(int height, int width, const char *faceName)
  18. {
  19.         LOGFONT f = { 0 };
  20.         f.lfHeight = height;
  21.         f.lfWidth = width;
  22.         f.lfQuality = ANTIALIASED_QUALITY;
  23.         strcpy(f.lfFaceName, faceName);
  24.         settextstyle(&f);
  25. }
  26. void loadImg()
  27. {
  28.         mciSendString("D:\\VS\\作品\\智能表盘\\images/风儿吹.mp3", NULL, 0, NULL);
  29.         mciSendString("D:\\VS\\作品\\智能表盘\\images/风儿吹.mp3 repeat", NULL, 0, NULL);
  30.         char fileName[50] = { 0 };
  31.         for (int i = 0; i < 30; i++)
  32.         {
  33.                 sprintf_s(fileName, "./images/guoguoxiaoshidi (%d).jpeg", i + 1);
  34.                 loadimage(spaceMan + i, fileName, 140, 130);
  35.         }
  36.         loadimage(&other[0], "./images/xinlv.jpg", 60, 60);//心率
  37.         loadimage(&other[1], "./images/sun.jpg", 40, 40);//太阳
  38.         loadimage(&other[2], "./images/shoes.jpg", 40, 40);//鞋子
  39.         loadimage(&other[3], "./images/shang.jpg", 30, 30);//上箭头
  40.         loadimage(&other[4], "./images/xia.jpg", 30, 30);//下箭头
  41.         loadimage(&other[5], "./images/rocket.jpg", 40, 40);//火箭
  42. }
  43. //太空人旋转动画
  44. void animation()
  45. {
  46.         static int index = 0;        //[0~59)
  47.         putimage(175, 210, spaceMan + index);
  48.         static DWORD t1;
  49.         DWORD t2 = clock();//获取程序运行到调用该函数经过的毫秒
  50.         if (t2 - t1 > 20)
  51.         {
  52.                 index = (index + 1) % 30;
  53.                 t1 = t2;
  54.         }
  55. }
  56. void gameDraw()
  57. {
  58.         setbkcolor(RGB(255, 0, 0));
  59.         cleardevice();
  60.         //绘制表盘
  61.         setlinecolor(RGB(0, 0, 0));//设置边框颜色
  62.         setlinestyle(PS_SOLID, 30);
  63.         setfillcolor(RGB(255, 255, 255));//设置圆的填充白色
  64.         fillellipse(0, 0, WIN_SIZE, WIN_SIZE);//绘制一个圆
  65.         //绘制线条
  66.         setlinestyle(PS_SOLID, 4);
  67.         setlinecolor(BLACK);
  68.         //最上面竖线
  69.         line(WIN_HALF - 30, 20, WIN_HALF - 30, 130);
  70.         //横线x2
  71.         line(WIN_HALF - 195, WIN_HALF - 120, WIN_HALF + 195, WIN_HALF - 120);
  72.         line(WIN_HALF - 195, WIN_HALF + 120, WIN_HALF + 195, WIN_HALF + 120);
  73.         //下面线条x3
  74.         line(WIN_HALF + 80, WIN_HALF + 120, WIN_HALF + 80, WIN_HALF + 175);
  75.         line(WIN_HALF + 80, WIN_HALF + 175, WIN_HALF - 60, WIN_HALF + 175);
  76.         line(WIN_HALF - 60, WIN_HALF + 175, WIN_HALF - 60, WIN_HALF + 175 + 48);
  77.         setbkmode(TRANSPARENT);
  78.         //左上空气湿度90%
  79.         setTextStyle(55, 23, "Arial");
  80.         settextcolor(BLACK);
  81.         outtextxy(WIN_HALF - 155, 75, "90%");
  82.         drawImg(other + 5, WIN_HALF - 90, 35);        //火箭                                                                                        //右上
  83.         putimage(WIN_HALF - 90, 35, other + 5);
  84.         setTextStyle(25, 15, "黑体");
  85.         outtextxy(WIN_HALF - 25, 35, "空气良好");
  86.         setTextStyle(25, 13, "宋体");
  87.         outtextxy(WIN_HALF - 25, 65, "晴天");
  88.         outtextxy(WIN_HALF - 25, 95, "25℃");
  89.         outtextxy(WIN_HALF + 38, 65, "26°");
  90.         outtextxy(WIN_HALF + 38, 95, "17°");
  91.         drawImg(other + 4, WIN_HALF + 73, 60);        //上面的箭头
  92.         drawImg(other + 3, WIN_HALF + 73, 90);        //下面的箭头
  93.         drawImg(other + 1, WIN_HALF + 105, 70);        //太阳
  94.         putimage(WIN_HALF + 73, 60, other + 4);
  95.         putimage(WIN_HALF + 73, 90, other + 3);
  96.         putimage(WIN_HALF + 105, 70, other + 1);
  97.         // 下部分
  98.         setTextStyle(37, 17, "宋体");
  99.         outtextxy(100, WIN_HALF + 130, "睡眠");
  100.         outtextxy(WIN_HALF + 90, WIN_HALF + 130, "距离");
  101.         outtextxy(50, WIN_HALF-40, "平顶山");
  102.         setTextStyle(40, 15, "Arial");
  103.         outtextxy(185, WIN_HALF + 125, "7h30m");
  104.         outtextxy(215, WIN_HALF + 180, "9.88km");
  105.         //中间
  106.         //心率
  107.         setTextStyle(25, 13, "宋体");
  108.         outtextxy(60, WIN_HALF + 30, "80~128");
  109.         drawImg(&other[0], 65, WIN_HALF + 50);        //心率图
  110.         putimage(65, WIN_HALF + 50, other + 0);
  111.         setTextStyle(40, 15, "Arial");
  112.         outtextxy(135, WIN_HALF + 60, "92");
  113.         // 步数
  114.         drawImg(&other[2], WIN_HALF + 65, WIN_HALF + 65);
  115.         putimage(WIN_HALF + 65, WIN_HALF + 65, &other[2]);
  116.         outtextxy(WIN_HALF + 125, WIN_HALF + 75, "9527");
  117.         //时间、日期相关
  118.         time_t timep = time(NULL);                        //获取当前时间
  119.         struct tm* p = localtime(&timep);        //把时间转成格式化时间
  120.         setTextStyle(25, 12, "宋体");
  121.         outtextxy(WIN_HALF + 110, WIN_HALF - 20, "四月六号");
  122.         char fileName[40] = { 0 };
  123.         sprintf_s(fileName, "周%s %d-%d", week[p->tm_wday], p->tm_mon + 1, p->tm_mday);
  124.         outtextxy(WIN_HALF + 110, WIN_HALF + 10, fileName);
  125.         // 获取字体
  126.         setTextStyle(100, 40, "Arial");
  127.         char szBuf[40] = { 0 };
  128.         sprintf_s(szBuf, "%d:%02d", p->tm_hour, p->tm_min);
  129.         outtextxy(105, 120, szBuf);
  130.         // 秒
  131.         setTextStyle(55, 23, "Arial");
  132.         sprintf(szBuf, "%02d", p->tm_sec);
  133.         outtextxy(335, 160, szBuf);
  134. }
  135. int main()
  136. {
  137.         initgraph(WIN_SIZE, WIN_SIZE/*,EW_SHOWCONSOLE*/);
  138.         SetWindowNewStyle(WIN_SIZE, WIN_SIZE);
  139.         loadImg();
  140.         BeginBatchDraw();//双缓冲 防止闪屏
  141.         while (true)
  142.         {
  143.                 gameDraw();
  144.                 animation();
  145.                 mouseEvent();
  146.                 FlushBatchDraw();
  147.         }
  148.         EndBatchDraw();
  149.         return 0;
  150. }
运行图
watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NjI5MTA5,size_16,color_FFFFFF,t_70#pic_center.jpg