主要基于对easyX图形库的学习和运用,创作初期借鉴了许多的优秀的作品,在制作钟表的过程中,从对钟表的各种功能的需要,到后来发现钟表的设计比功能要更加的重要(个人认为);从在论坛上网罗资源,到后来的踏实认真的打磨作品。最后收尾阶段的总结以及汇报,虽然有些匆忙,但基本上该讲的也都讲到了。
对于我的钟表,现在看越来越感觉它不止是一块表那么普通了,而是在不断的调试以及寻找解决方案的之后,打磨出来的一个艺术品,他不像表,却像一个消遣的玩具,不像表,却像一个功能趋全钟表当道的异类。
首先,
实现了钟表主体,鼠标键值的
判断(单独的一个线程),音乐
的播放与暂停,以及弹窗提示
信息和鼠标轨迹的绘制。
其次,关于创作过程中遇到的困难:
鼠标键值的判断与main函数的执行之间的冲突
对于digitalClock中的文本信息以及主函数中的图片在编写初期无法同时展示的问题
图片数组的使用中出现了无法和主函数的画布同时显示的问题
然后,创新之处有:
对于鼠标键值的判断,我们单独出来了一个线程,使用了process.h中的_beginthread,返回一个uintptr_t类型的值,用来标识新创建的线程。
对于图片数组和主画布无法一同显示的问题我们果断放弃了在一张画布上显示,改做到了一个单独的画布作为开启钟表的前景。
我们使用了_TCHAR类型的变量来表示文本信息,同时在多字节字符集的配置下不与图片的输出冲突。
message()函数的解释:在画布上绘制鼠标的轨迹,如果点击鼠标的左键,画一个白色的小方格,按住ctrl并左键画一个大方格(从easyX官网上拼接来的)。
关于设计逻辑:
在经过开头的3秒的动画之后,进入星空(easyX官网上拼接来的)和绘制鼠标轨迹的函数;然后会有弹窗提供提示信息,提示按空格键,进入钟表界面,左键点击画布会播放音乐,右键点击会使音乐暂停。这就是钟表的全部内容了,写的真的是好烂😶🌫️😶🌫️😶🌫️
下面是代码部分:
#include<stdio.h>
#include<graphics.h>
#include<time.h>
#include<conio.h>
#include<easyx.h>
#include<process.h>
#include<Windows.h>
#include <mmsystem.h>
#pragma comment (lib,"winmm.lib")
#define PI 3.1415926
#define MAXSTAR 2000
//播放音乐🎵
static void BGM() {
mciSendString("open ./TheRange.mp3 ", NULL, 0, NULL);
mciSendString("Play ./TheRange.mp3 repeat", NULL, 0, NULL);
}
//画表盘⌚️
static void biaopan() {
setbkcolor(LIGHTGRAY);
setbkmode(TRANSPARENT);
setlinecolor(PS_SOLID);
setlinecolor(YELLOW);
int r = 150; // 定义半径为 150
setlinestyle(PS_SOLID, 4);
settextcolor(WHITE); // 设置字体颜色
setbkmode(TRANSPARENT); // 设置背景色为透明
for (int n = 0; n < 12; n++)
{
// 整点刻度
setfillcolor(YELLOW);
solidcircle((145 * cos(n * 2 * PI / 12)), -(145 * sin(n * 2 * PI / 12)), 2);
solidcircle((145 * cos(n * 2 * PI / 4)), -(145 * sin(n * 2 * PI / 4)), 4);
// 显示数字
_TCHAR s[10];
sprintf_s(s, _T("%d"), 12 - n);
// 设置字体、大小及输出
if ((12 - n) % 3 == 0) settextstyle(20, 0, _T("Arial"));
else settextstyle(20, 0, _T("Arial"));
// 定义字符串长和宽,居中
int w, h;
w = textwidth(s);
h = textheight(s);
outtextxy((125 * cos(n * 2 * PI / 12 + PI / 2) - w / 2),
-(125 * sin(n * 2 * PI / 12 + PI / 2) - h / 2 + 20),
s);
}
}
// 画表针📌
static void needles(int h, int m, int s)
{
double a = PI / 2 - (2 * PI * h / 12 + 2 * PI * 1 / 12 * m / 60); // 时针所走弧度
double b = PI / 2 - (2 * PI * m / 60 + 2 * PI * 1 / 60 * s / 60); // 分针所走弧度
double c = PI / 2 - 2 * PI * s / 60; // 秒针所走弧度
setlinecolor(LIGHTGRAY); // 设置画线颜色为浅灰色
setlinestyle(PS_SOLID, 7); // 设置线宽为7像素
line(0, 0, (50 * cos(a)), (-50 * sin(a))); // 画时针
setlinecolor(RGB(135,114,62));
setlinestyle(PS_SOLID, 6); // 设置线宽为6像素
line(0, 0, (100 * cos(b)), (-100 * sin(b))); // 画分针
setlinecolor(RED); // 设置画线颜色为红色
setlinestyle(PS_SOLID, 3); // 设置线宽为3像素
line((20 * cos(c + PI)), -(20 * sin(c + PI)), (130 * cos(c)), -(130 * sin(c))); // 画秒针
}
//电子表📀
static void digitalClock(int h,int m,int s) {
// 画显示当前时间的三个小矩形
setlinecolor(LIGHTGRAY); // 设置边框颜色为浅灰色
setbkcolor(TRANSPARENT);
fillrectangle(-40 - 13, 50, -40 + 13, 50 + 26);
fillrectangle(-13, 50, 13, 50 + 26);
fillrectangle(40 - 13, 50, 40 + 13, 50 + 26);
// 显示当前时间
settextstyle(24, 0, _T("Arial"));
settextcolor(RED);
_TCHAR a[10];
int w;
sprintf_s(a, _T("%02d"), h); w = textwidth(a); outtextxy(-40 - w / 2, 50, a);
sprintf_s(a, _T("%02d"), m); w = textwidth(a); outtextxy(-w / 2, 50, a);
sprintf_s(a, _T("%02d"), s); w = textwidth(a); outtextxy(40 - w / 2, 50, a);
}
static int message() {
ExMessage m; // 定义消息变量
while(1)
{
// 获取一条鼠标或按键消息
m = getmessage(EX_MOUSE | EX_KEY);
switch (m.message)
{
case WM_MOUSEMOVE:
// 鼠标移动的时候画红色的小点
putpixel(m.x, m.y, RED);
break;
case WM_LBUTTONDOWN:
// 如果点左键的同时按下了 Ctrl 键
if (m.ctrl)
// 画一个大方块
rectangle(m.x - 10, m.y - 10, m.x + 10, m.y + 10);
else
// 画一个小方块
rectangle(m.x - 5, m.y - 5, m.x + 5, m.y + 5);
break;
case WM_KEYDOWN:
if (m.vkcode == VK_SPACE)
return 0; // 按 空格 键退出程序
}
}
}
//播放动画🕳🌸
static void openMotion(int playCount, int delay) {
initgraph(456, 301);
cleardevice();
int i = 50;
IMAGE k[30];
// 定义一个图像数组来存储动画帧,大小为动画序列的图片数
char a[200];
for (; i < 80; i++) { // 循环加载动画序列的图片
sprintf_s(a, "./pictures/%d.png", i + 1);
loadimage(&k[i - 50], a, getwidth(), getheight()); // 加载图片到数组
}
// 播放动画 playCount 次
for (int count = 0; count < playCount; count++) {
for (int j = 0; j < 30; j++) { // 30 是动画序列的图片数
putimage(0, 0, &k[j]); // 显示当前帧
Sleep(delay); // 根据指定的延迟时间暂停
}
}
}
//判断鼠标值🖱
static void getMouseMsg(void* param) {
ExMessage mouse;
while (true) {
mouse = getmessage();
switch (mouse.message)
{
case WM_LBUTTONDOWN:
BGM();
break;
case WM_RBUTTONDOWN:
mciSendString("stop ./TheRange.mp3", NULL, 0, NULL);
break;
}
}
}
struct STAR
{
double x;
int y;
double step;
int color;
};
struct STAR star[MAXSTAR];
// 初始化星星
void InitStar(int i)
{
star[i].x = 0;
star[i].y = rand() % 640;
star[i].step = (rand() % 5000) / 1000.0 + 1;
star[i].color = (int)(star[i].step * 255 / 6.0 + 0.5); // 速度越快,颜色越亮
star[i].color = RGB(star[i].color, star[i].color, star[i].color);
}
// 移动星星
void MoveStar(int i)
{
// 擦掉原来的星星
putpixel((int)star[i].x, star[i].y, 0);
// 计算新位置
star[i].x += star[i].step;
if (star[i].x > 640) InitStar(i);
// 画新星星
putpixel((int)star[i].x, star[i].y, star[i].color);
}
void stars() {
srand((unsigned)time(NULL)); // 随机种子
initgraph(640, 640); // 创建绘图窗口
// 初始化所有星星
for (int i = 0; i < MAXSTAR; i++)
{
InitStar(i);
star[i].x = rand() % 640;
}
// 绘制星空,按任意键退出
while (!_kbhit())
{
for (int i = 0; i < MAXSTAR; i++)
MoveStar(i);
Sleep(20);
}
message();
}
//主函数
int main() {
openMotion(3,100);
initgraph(640, 640);
stars();
HWND hwnd = GetHWnd();
SetWindowTextA(hwnd, "CLOCK");
MessageBoxA(hwnd, "my clock you have to press the space key", "hello", NULL);
BeginBatchDraw();
setorigin(320, 320);
// 启动一个线程来处理鼠标消息,主循环就可以专注于绘图,而不会干扰消息处理
uintptr_t threadId = _beginthread(getMouseMsg, 0, NULL);
while (1) {
SYSTEMTIME ti;
GetLocalTime(&ti);
cleardevice();
IMAGE img;
loadimage(&img, "./background.jpg", 640, 640);
putimage(-320, -320, &img);
biaopan();
digitalClock(ti.wHour, ti.wMinute, ti.wSecond);
needles(ti.wHour, ti.wMinute, ti.wSecond);
FlushBatchDraw();
}
_getch();
EndBatchDraw();
closegraph();
return 0;
}
钟表展示:
小弹窗:
希望大家可以批评指正🌹🌹🌹