C++星罗万象时钟罗盘

33 篇文章 3 订阅 ¥79.90 ¥99.00
15 篇文章 7 订阅 ¥79.90 ¥99.00

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

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

#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);						// 绘图坐标向下为正
}

效果图
请添加图片描述

  • 6
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
要创建一个多媒体时钟,你可以使用 Windows API 中的多媒体定时器(Multimedia Timer),具体步骤如下: 1. 在程序中包含 Windows.h 和 MMSystem.h 头文件。 2. 使用 timeSetEvent 函数创建一个多媒体定时器。该函数的原型如下: ```c++ UINT timeSetEvent( UINT uDelay, UINT uResolution, LPTIMECALLBACK lpTimeProc, DWORD_PTR dwUser, UINT fuEvent ); ``` 其中,参数含义如下: - uDelay:定时器间隔,以毫秒为单位。 - uResolution:定时器精度,以毫秒为单位。 - lpTimeProc:回调函数指针,用于处理定时器事件。 - dwUser:传递给回调函数的参数。 - fuEvent:定时器类型,可以是 TIME_ONESHOT(单次定时器)或 TIME_PERIODIC(循环定时器)。 3. 在回调函数中处理定时器事件,例如更新时钟显示。 4. 在程序退出时使用 timeKillEvent 函数销毁定时器。该函数的原型如下: ```c++ MMRESULT timeKillEvent( UINT uTimerID ); ``` 其中,参数 uTimerID 是 timeSetEvent 函数返回的定时器 ID。 下面是一个简单的示例代码: ```c++ #include <Windows.h> #include <MMSystem.h> #include <iostream> #pragma comment(lib, "winmm.lib") void CALLBACK TimerProc(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2) { // 处理定时器事件,例如更新时钟显示 std::cout << "Tick..." << std::endl; } int main() { // 创建定时器,每秒触发一次 UINT timerID = timeSetEvent(1000, 0, TimerProc, 0, TIME_PERIODIC); // 等待用户输入并在退出时销毁定时器 std::cin.get(); timeKillEvent(timerID); return 0; } ``` 注意,多媒体定时器的精度受到系统负载、硬件性能等因素影响,可能会有一定误差。如果需要更高精度的定时器,可以考虑使用 QueryPerformanceCounter 函数等其他方法。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值