需求
有智能手表的人都知道,前段时间的“太空人表盘”非常火热。那么我们也可以自己动手来制作一款太空人表盘。
准备
- 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;
}
运行图
后续
如果想了解更多物联网、智能家居项目知识,可以关注我的程序设计专栏。
或者关注公众号。
编写不易,感谢支持。
转载:https://blog.csdn.net/qq_44629109/article/details/117067545
查看评论