“我要做太空人”----太空人表盘制作

2021-06-15 16:02:37 浏览数 (2)

需求

有智能手表的人都知道,前段时间的“太空人表盘”非常火热。那么我们也可以自己动手来制作一款太空人表盘。

准备

  1. Visual Studio 2019
  2. EasyX Graphics Library :Visual C 的免费绘图库

程序

huawei.h

代码语言:javascript复制
#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 %dn", CursorPos.x - WndPtSize.x, CursorPos.y - WndPtSize.y);
      }
    }
    else if (msg.uMsg == WM_RBUTTONDOWN)//右键按下
    {
      exit(0);
    }
  }
}
#endif // !_TOOLS_H_


huawei.c

代码语言:javascript复制
#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:d", p->tm_hour, p->tm_min);
  outtextxy(105, 120, szBuf);
  // 秒
  setTextStyle(55, 23, "Arial");
  sprintf(szBuf, "d", 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;
}

我将工程文件放在这里,可以自行下载。

运行图

0 人点赞