需求

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

准备

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