他来了,他来了,桌面图标一百种玩法第三种,桌面时钟。
学会了就发给女朋友玩吧,效果炫酷,学不了吃亏,学不了上当,走过路过不要错过。
老规矩,先看看视频效果。
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