C++用桌面图标系列之三【整理-时钟】

他来了,他来了,桌面图标一百种玩法第三种,桌面时钟。

学会了就发给女朋友玩吧,效果炫酷,学不了吃亏,学不了上当,走过路过不要错过。

老规矩,先看看视频效果。

C++用桌面图标系列之三【整理-时钟】

 

核心代码

除了基本的时间展示之外,还包含了初始动画。

int nScreenWith;
int nScreenHeigh;
typedef struct tagMovingIcon
{
	int index;
	int targetX;
	int targetY;
	int startX;
	int startY;
	int aniDelay;                           //动画延迟时间,随机的。打造一种乱中有序的氛围

}MovingIcon, *PMovingIcon;

vector vMoveAniIcons;           //动画队列的图标索引
ULONGLONG startAniTick;                     //记录动画起始时间

DWORD dwProcessId = 0;
HANDLE hProcess;
LPVOID lpvPt;

BOOL MoveTo(int numIndex, int posX, int posY, int iconIndex, bool moveAni = false);
void WriteNumber(int numIndex, int numberShade[ROW][COL], bool moveAni = false);
BOOL CALLBACK EnumWindowsProc(_In_ HWND TopHandle, _In_ LPARAM topparamhandle);
void DoMoveAni();
//桌面图标层句柄
HWND  hwndSysListView32;

//逻辑起点
void ClockLogic()
{
	vector vNumberShade;
	vNumberShade.push_back(num0);
	vNumberShade.push_back(num1);
	vNumberShade.push_back(num2);
	vNumberShade.push_back(num3);
	vNumberShade.push_back(num4);
	vNumberShade.push_back(num5);
	vNumberShade.push_back(num6);
	vNumberShade.push_back(num7);
	vNumberShade.push_back(num8);
	vNumberShade.push_back(num9);

	HWND  hwndParent = ::FindWindow("Progman", "Program Manager");
	HWND  hwndSHELLDLL_DefView = ::FindWindowEx(hwndParent, NULL, "SHELLDLL_DefView", NULL);
	hwndSysListView32 = ::FindWindowEx(hwndSHELLDLL_DefView, NULL, "SysListView32", "FolderView");

	if (hwndSysListView32 == NULL)
	{
		//***注意,某些情句柄有空的,尝试用下面的函数来查找句柄***
		//***也可以自行使用vs的工具spy++工具来查看层级是否准确*****
		EnumWindows(EnumWindowsProc, (LPARAM)nullptr);
		if (hwndSysListView32 == NULL)
			return;
	}

	int iconCount = ListView_GetItemCount(hwndSysListView32);
	if (iconCount < TOTAL_ICON_COUNT)
	{
		//图标数量不够啊大佬,多复制几个
		return;
	}

	GetWindowThreadProcessId(hwndSysListView32, &dwProcessId);                        //通过桌面窗口句柄获取此窗口所在进程的PID,其实就是explorer进程
	hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);                   //打开指定PID进程,取得进程句柄
	lpvPt = VirtualAllocEx(hProcess, NULL, sizeof(POINT), MEM_COMMIT, PAGE_READWRITE);//在指定进程里面申请一个POINI结构大小的空间.


	for (size_t i = 0; i < iconCount; i++)
	{
		if (i >= TOTAL_ICON_COUNT - 1)
		{
			//这里会将所有多余的桌面图标放到接们看不见的位置,后面可以右键桌面设置对齐网格还原图标位置
			SendMessage(hwndSysListView32, LVM_SETITEMPOSITION, i, MAKELPARAM(-100, -100));
		}
		else
		{
			//将图标打乱,这部分只是为了拍视频  可删除
			random_device rd;

			uniform_int_distribution ranX(0, nScreenWith);
			uniform_int_distribution ranY(0, nScreenHeigh);
			SendMessage(hwndSysListView32, LVM_SETITEMPOSITION, i, MAKELPARAM(ranX(rd), ranY(rd)));
		}
	}

	//这部分只是为了拍视频   可删除
	Sleep(3000);

	time_t currentTime;
	struct tm* p;

	ULONGLONG nextClockTick = GetTickCount64() + ANI_TOTAL_TIME + ANI_DELAY_TIME;//加上动画需要的时间,动画阶数再开始显示时间
	ULONGLONG nextAniTick = GetTickCount64();
	startAniTick = GetTickCount64();

	int checkHour = -1;
	int checkMin = -1;
	while (1)
	{
		if (GetTickCount64() >= nextAniTick)
		{
			time(¤tTime);
			p = localtime(¤tTime);

			if (vMoveAniIcons.size() <= 0)
			{

				int hour1 = p->tm_hour / 10;
				int hour2 = p->tm_hour % 10;
				WriteNumber(0, vNumberShade[hour1], true);
				WriteNumber(1, vNumberShade[hour2], true);

				int min1 = p->tm_min / 10;
				int min2 = p->tm_min % 10;
				WriteNumber(2, vNumberShade[min1], true);
				WriteNumber(3, vNumberShade[min2], true);

				int sec1 = p->tm_sec / 10;
				int sec2 = p->tm_sec % 10;
				WriteNumber(4, vNumberShade[sec1], true);
				WriteNumber(5, vNumberShade[sec2], true);
			}

			DoMoveAni();
			nextAniTick += 10;//移动间隔
		}

		//下面是正式的时钟显示逻辑///

		if (GetTickCount64() < nextClockTick)
			continue;
		nextClockTick = GetTickCount64() + 1000;

		time(¤tTime);
		p = localtime(¤tTime);


		//小时
		if (checkHour == -1 || checkHour != p->tm_hour)
		{
			checkHour = p->tm_hour;
			int hour1 = p->tm_hour / 10;//十位数
			int hour2 = p->tm_hour % 10;//个位数
			WriteNumber(0, vNumberShade[hour1]);
			WriteNumber(1, vNumberShade[hour2]);
		}


		//分钟
		if (checkMin == -1 || checkMin != p->tm_min)
		{
			checkMin = p->tm_min;
			int min1 = p->tm_min / 10;
			int min2 = p->tm_min % 10;
			WriteNumber(2, vNumberShade[min1]);
			WriteNumber(3, vNumberShade[min2]);
		}

		//秒的
		int sec1 = p->tm_sec / 10;
		int sec2 = p->tm_sec % 10;
		WriteNumber(4, vNumberShade[sec1]);
		WriteNumber(5, vNumberShade[sec2]);

	}

}


void WriteNumber(int numIndex, int numberShade[ROW][COL], bool moveAni)
{
	int nIconIndex = numIndex * (ROW * COL);
	for (size_t row = 0; row < ROW; row++)
	{
		for (size_t col = 0; col < COL; col++)
		{
			if (numberShade[row][col] == 1)
				MoveTo(numIndex, row, col, nIconIndex, moveAni);
			else
				MoveTo(numIndex, -1, -1, nIconIndex, moveAni);	//不需要显示的就挪到看不见的地方
			++nIconIndex;
		}
	}
}

//图标iconIndex 移动到目标点
BOOL MoveTo(int numIndex, int row, int col, int iconIndex, bool moveAni)
{
	//int numGap = numIndex % 2 == 0 ? (numIndex / 2) * NUM_GAP2 : ((numIndex - 1) / 2) * NUM_GAP2 + NUM_GAP1;//
	int targetX = 0, targetY = 0, numGap = 0;
	if (row == -1)//需要移出屏幕的图标
	{
		targetX = -100;
		targetY = 0;
	}
	else if (numIndex == 0 || numIndex == 1)//时
	{
		numGap = numIndex % 2 == 0 ? 0 : NUM_GAP1;
		targetX = nScreenWith / 4 - GRID_WIDTH * COL + numGap + col * GRID_WIDTH;
		targetY = nScreenHeigh / 3 + row * GRID_WIDTH - 120;
	}
	else if (numIndex == 2 || numIndex == 3)//分
	{
		numGap = numIndex % 2 == 0 ? 0 : NUM_GAP1;
		targetX = (3 * nScreenWith / 4) - GRID_WIDTH * COL + numGap + col * GRID_WIDTH;
		targetY = nScreenHeigh / 3 + row * GRID_WIDTH - 120;
	}
	else if (numIndex == 4 || numIndex == 5)//秒
	{
		numGap = numIndex % 2 == 0 ? 0 : NUM_GAP1;
		targetX = nScreenWith / 2 - GRID_WIDTH * COL + numGap + col * GRID_WIDTH;
		targetY = nScreenHeigh / 2 + row * GRID_WIDTH + 30;
	}

	//需要播放动画的
	if (moveAni && row != -1)
	{
		//获取图标初始位置
		POINT pIconCurPos;
		ListView_GetItemPosition(hwndSysListView32, iconIndex, lpvPt);
		ReadProcessMemory(hProcess, lpvPt, &pIconCurPos, sizeof(POINT), NULL);

		random_device rd;
		//取0 - ANI_DELAY_TIME的随机数
		uniform_int_distribution dist(0, ANI_DELAY_TIME);

		MovingIcon icon;
		icon.index = iconIndex;
		icon.targetX = targetX;
		icon.targetY = targetY;
		icon.startX = pIconCurPos.x;
		icon.startY = pIconCurPos.y;
		icon.aniDelay = dist(rd);
		//放到动画队列里
		vMoveAniIcons.push_back(icon);
	}
	else
	{
		SendMessage(hwndSysListView32, LVM_SETITEMPOSITION, iconIndex, MAKELPARAM(targetX, targetY));
	}

	return true;
}

//做初始动画
void DoMoveAni()
{
	//动画做了多久
	ULONGLONG nPassedTime = GetTickCount64() - startAniTick;
	if (nPassedTime > ANI_TOTAL_TIME + ANI_DELAY_TIME)
		return;
	for (auto iter = vMoveAniIcons.begin(); iter != vMoveAniIcons.end(); ++iter)
	{
		if (nPassedTime < iter->aniDelay)
			continue;

		if (nPassedTime - iter->aniDelay >= ANI_TOTAL_TIME)
		{
			//校正最后的位置
			SendMessage(hwndSysListView32, LVM_SETITEMPOSITION, iter->index, MAKELPARAM(iter->targetX, iter->targetY));
			continue;
		}

		//当前所在位置  =  (经过的时间 / 总时间) * (总路程)
		//按时间比例来算,应该不复杂 = =!
		int targetX = 0, targetY = 0;
		targetX = ((double)(nPassedTime - iter->aniDelay) / (ANI_TOTAL_TIME)) * (iter->targetX - iter->startX);
		targetY = ((double)(nPassedTime - iter->aniDelay) / (ANI_TOTAL_TIME)) * (iter->targetY - iter->startY);

		//在vs的输出界面打印信息
		char out0[128] = { 0 };
		sprintf(out0, "index=%d x=%d y=%d \n", iter->index, targetX, targetY);
		//OutputDebugStringA(out0);

		targetX += iter->startX;
		targetY += iter->startY;
		SendMessage(hwndSysListView32, LVM_SETITEMPOSITION, iter->index, MAKELPARAM(targetX, targetY));

	}
}

这里是完整代码和可执行文件。

https://download.csdn.net/download/Yang9325/13999888

你可能感兴趣的:(c++,心情,奇葩,c++,c/c++,源码,桌面图标)