简单

行远必自迩,登高必自卑

星罗万象时钟罗盘

编写思路

该程序的难点在于字符串的书写角度,理解了这个就已经理解了这个程序的核心内容,需要注意的地方是这个程序的每一圈代表一个 for 循环,我开始写的时候认为一个 for 循环嵌套一个 for 循环,但是后面我发现 for 循环嵌套的太多,就会导致程序运行的速度变慢,为了提高程序的速度,我将所有的 for 循环分开写,不用循环嵌套。然后用一个 while 循环来控制主循环。还有一个问题,程序中我没有用 Sleep 函数,直接使用了获取系统时间的函数,通过慢羊羊的指导,后续又加以修正,让钟表产生旋转的效果。在这里要感谢慢羊羊,感谢他对我编写的每一个程序进行指导,并给我一个展示的平台,让我对编程产生了浓厚的兴趣,由衷的感谢他。

心得体会

写程序总是兴趣使然,实现自己的想法所带来的成就感还是挺不错。如果发现一个自己想用程序实现的东西,总是心中念念不忘,然后悄悄酝酿着,积累着,当有足够的能力将所看所学所想的组合起来时,那可能就是创新吧。多想,多看,多敲代码。这个程序创新之处就是旋转。就比如秒的那圈旋转,为了达到动态旋转的效果,并且需要符合时钟所对应的时间。每一秒之间是有间隔的。那这个间隔就是循环的次数。我们需要计算出每一秒间隔所对应弧度,这样就实现了不用 Sleep 函数,也实现了动态旋转效果。越是复杂的东西,就越简单。

效果图

源码

///////////////////////////////////////////////////
// 程序名称:星罗万象时钟罗盘
// 编译环境:Mictosoft Visual Studio 2013, EasyX_20200315(beta)
// 作  者:luoyh <2864292458@qq.com>
// 最后修改:2021-10-1
//

#include <graphics.h> 
#include <conio.h>
#include <math.h>
#include <time.h>
#include <stdio.h>

const double PI = acos(-1.0);
#define Width 800
#define Height 800

// str代表绘制的字符串
// variable 代表每次的变量
// fors 每次需要循环的次数总数
// R 该圈的半径
// Radian 累加的弧度
void DrawCircle(TCHAR str[25], int variable, int fors, int R, double Radian);		// 绘制一圈字符									
int monthdasy(int y, int m);														// 某年某月的天数 y 代表年份 m 代表月份

// 一个圈的结构体
struct TimeCircle
{
	int fors;											// 每一圈分成的份数
	int R;												// 圈的半径
	double NextTime;									// 上一个时刻时间
	double Radian;										// 累加的弧度
};

int main()
{
	initgraph(Width, Height);
	SYSTEMTIME ti;
	TimeCircle TC[7];
	TCHAR str[25];

	for (int i = 0; i < 7; i++)
	{
		TC[i].R = (i + 1) * 50;
		TC[i].Radian = 0;
		TC[i].NextTime = 0;

		switch (i)
		{
		case 0:TC[i].fors = 1; break;							// 年
		case 1:TC[i].fors = 12; break;							// 月
		case 2:TC[i].fors = 30; break;							// 日
		case 3:TC[i].fors = 7; break;							// 周
		case 4:TC[i].fors = 24; break;							// 时
		case 5:TC[i].fors = 60; break;							// 分
		case 6:TC[i].fors = 60; break;							// 秒
		}
	}
	
	BeginBatchDraw();
	while (true)
	{
		GetLocalTime(&ti);
		TC[2].fors = monthdasy(ti.wYear, ti.wMonth);
		for (int j = 0; j < 7; j++)
		{
			if (TC[5].NextTime != ti.wMinute)
			{
				TC[5].NextTime = ti.wMinute;
				TC[5].Radian = 0;
			}
			else
			{
				TC[5].Radian = TC[5].Radian + (2 * PI / TC[5].fors - TC[5].Radian) / 10;
			}

			if (TC[6].NextTime != ti.wSecond)
			{
				TC[6].NextTime = ti.wSecond;
				TC[6].Radian = 0;
			}
			else
			{
				TC[6].Radian = TC[6].Radian + (2 * PI / TC[6].fors - TC[6].Radian) / 10;
			}

			for (int i = 0; i < TC[j].fors; i++)
			{
				switch (j)
				{
				case 0: _stprintf_s(str, _T("%d年"), ti.wYear); break;
				case 1: _stprintf_s(str, _T("%d月"), (i + ti.wMonth) % TC[j].fors ? (i + ti.wMonth) % TC[j].fors : TC[j].fors); break;
				case 2: _stprintf_s(str, _T("%d号"), (i + ti.wDay) % TC[j].fors ? (i + ti.wDay) % TC[j].fors : i + ti.wDay); break;
				case 3: str[0] = L"周"[0];
					    str[1] = L"日一二三四五六"[(i + ti.wDayOfWeek) % 7];
					    str[2] = L""[0]; break;
				case 4: _stprintf_s(str, _T("%d时"), (i + ti.wHour) % TC[j].fors); break;
				case 5: _stprintf_s(str, _T("%d分"), (i + ti.wMinute) % TC[j].fors); break;
				case 6: _stprintf_s(str, _T("%d秒"), (i + ti.wSecond) % TC[j].fors); break;
				}
				DrawCircle(str, i, TC[j].fors, TC[j].R, TC[j].Radian);;
			}
		}
		FlushBatchDraw();
		cleardevice();
	}
	EndBatchDraw();
	return 0;
}

int monthdasy(int y, int m)
{
	if (m == 2)
		return ((y % 4 == 0 && y % 100 != 0) || y % 400 == 0) ? 29 : 28;
	else
		return 31 - (m - 3) % 5 % 2;
}

void DrawCircle(TCHAR str[25], int variable, int fors, int R, double Radian)
{
	settextcolor(variable ? HSLtoRGB((360.f / fors) * variable, 1, 0.5f) : WHITE);
	double a, x0, y0, w, h, x1, y1;
	int x, y;
	settextstyle(22, 0, L"微软雅黑", variable * 3600 / fors, variable * 3600 / fors, 0, false, false, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, DEFAULT_PITCH);

	a = (fors == 60) ? ((variable + 1) * PI * 2 / fors - Radian) : (variable * PI * 2 / fors);	// 计算字符串弧度 a
	
	w = textwidth(str);																			// 计算字符串宽 w、高 h
	h = textheight(str);

	x1 = R * cos(a);																			// 计算输出字符串的左上角位置
	y1 = R * sin(a);

	x0 = x1 * cos(-a) - y1 * sin(-a);															// 将字符串绕原点顺时针旋转 a 弧度
	y0 = y1 * cos(-a) + x1 * sin(-a);

	x0 -= w / 2;																				// 将字符串向左上偏移 w/2、h/2
	y0 += h / 2;																				// 绘图坐标向下为正

	x = (int)(x0 * cos(a) - y0 * sin(a));														// 将字符串绕原点逆时针旋转 a 弧度
	y = (int)(y0 * cos(a) + x0 * sin(a));

	outtextxy(int(Width / 2 + x + 0.5), int(Height / 2 - y + 0.5), str);						// 绘图坐标向下为正
}
分享到

添加评论