创意桌面移动图标-技术片

历经一年时间,一次又一次的迭代,逐渐趋于稳定,从一开始简单几何运动到现在复杂的逐帧播放舞动视频。每一次大版本迭代都需要一个好的创意,以及技术去实现。

眼界开阔,创意无限!

废话不多说,步入正题。

开发环境

软件基于windows系统运行,调用windows运行库和组件实现桌面图标移动功能。所以,理论上任何可以使用任何你熟悉的能调用windows运行库的语言开发,像VB、C#、C/C++、golang等。笔者使用Visual studio开发MFC windows应用程序,C++并带有一点C的风格。

核心功能介绍

软件本身并不复杂,其核心功能有两个:

  • 驱动图标:让桌面图标动起来,此模块是整个软件运行的基石。

  • 运动模块:桌面图标以什么样的方式运动,其重点在于抽象出运动接口,各种运动方案是基于接口的实现,并完成自由组合。

驱动图标

关于如何移动桌面图标,废话不多说,直接上代码。

代码借鉴于 :https://blog.csdn.net/hejingdong123/article/details/106299349

void FindDesktopFolderView(REFIID riid, void **ppv)

{
	CComPtr<IShellWindows> spShellWindows;
	spShellWindows.CoCreateInstance(CLSID_ShellWindows);
	CComVariant vtLoc(CSIDL_DESKTOP);
	CComVariant vtEmpty;
	long lhwnd;
	CComPtr<IDispatch> idispatchs;
	IShellWindows *psw;
	HRESULT hresult;
	hresult = CoInitialize(NULL);
	if (SUCCEEDED(hresult))
	{
		hresult= CoCreateInstance(CLSID_ShellWindows,NULL,CLSCTX_ALL,IID_IShellWindows,(void**)&psw);
		if (SUCCEEDED(hresult))
		{
			// Use the IShellWindows instance...
			psw->FindWindowSW(&vtLoc, &vtEmpty,SWC_DESKTOP, &lhwnd, SWFO_NEEDDISPATCH, &idispatchs);
			//psw->Release();
		}
	}
	CComPtr<IShellBrowser> stlBrowser;
	CComQIPtr<IServiceProvider>(idispatchs)->QueryService(SID_STopLevelBrowser,IID_PPV_ARGS(&stlBrowser));
	CComPtr<IShellView> spView;
	stlBrowser->QueryActiveShellView(&spView);
	spView->QueryInterface(riid, ppv);
}
void moveIconFunc(LPVOID lpParam) {
	CComPtr<IFolderView> ifView;
	FindDesktopFolderView(IID_PPV_ARGS(&ifView));	//获取桌面窗口句柄
	if (NULL == ifView)
	{
		return;
	}
	CComPtr<IShellFolder> isFolder;
	ifView->GetFolder(IID_PPV_ARGS(&isFolder));    //获取桌面文件夹
	//记录每个图标新的位置
	POINT* pts = (POINT*)malloc(sizeof(POINT) * 100);
	CComPtr<IEnumIDList> spEnum;
	ifView->Items(SVGIO_ALLVIEW, IID_PPV_ARGS(&spEnum));  //获取游标
	int counts = 0;  //需要移动图标的数量
	//开辟新的空间,临时存储需要移动的图标地址
	PCITEMID_CHILD* pchilds = (PCITEMID_CHILD*)malloc(sizeof(PCITEMID_CHILD) * (5));
	for (int k = 0; k < 5; k++) {
		pchilds[k] = nullptr;
	}
	//判断哪些图标需要移动
	for (CComHeapPtr<ITEMID_CHILD> cchptr; spEnum->Next(1, &cchptr, nullptr) == S_OK; ) {
		STRRET str;
		isFolder->GetDisplayNameOf(cchptr, SHGDN_NORMAL, &str);	//获取图标名称
		CComHeapPtr<wchar_t> spscname;
		StrRetToStr(&str, cchptr, &spscname);
		//设置图标移动规则
		//if (L"判断条件" == std::wstring(spscname)) {
		pchilds[counts] = cchptr;
		pts[counts].x = round(100+counts*80);  //根据移动规则设置新坐标
		pts[counts++].y = round(200);
		//}
		if (counts >= 5)break;
	}
	double width = GetSystemMetrics(SM_CXFULLSCREEN);//获取屏幕宽度
	double height = GetSystemMetrics(SM_CYFULLSCREEN);//获取屏幕高度
	while (true) {			//让图标运动
		for (int i = 0; i < counts; i++) {
			pts[i].x = pts[i].x >= width-80 ? 0:pts[i].x+1;
			pts[i].y = pts[i].y >= height-80 ? 0:pts[i].y+1;
		}
		//设置单个图标位置,i表示图标的顺序
		//ListView_SetItemPosition32((HWND)hWnd,i,x, y);  
		//批量移动图标,其底层依然是调用ListView_SetItemPosition32
		ifView->SelectAndPositionItems(counts, pchilds, pts, SVSI_POSITIONITEM);
		
	}
	std::free(pchilds);
	//最后记得释放内存
	std::free(pts);
}
		

移动桌面的不能影响软件主窗口的正常运行,因此桌面移动移动模块必须使用新的线程移动。如下

	CWinThread* cWinThreadPaint = AfxBeginThread((AFX_THREADPROC)&moveIconFunc, this, 0, 0, CREATE_SUSPENDED, NULL);
	//cWinThreadPaint->m_bAutoDelete = false;
	if (cWinThreadPaint->ResumeThread() == -1)
	{
		perror("fail to log thread");
	}

运动预览

如果上述代码正常能在你电脑上正常跑起来,那么恭喜你,你已经完成了最简单的而又最重要的一个步骤。代码运行效果如下

题外篇

桌面移动类似于游戏开发,那么如何稳定运行帧率。

在每一次循环时记录时间,在循环结束时计算本次运行时间,如果小于1000/帧数,则让程序休眠到每一帧需要的时间。

while (true) {
		//SendMessage((HWND)hWnd,WM_SETREDRAW,(WPARAM)false,NULL);
		startTime = clock();//计时开始
		//运算
		endTime = clock();//计时结束
		if (endTime - startTime < CLOCKS_PER_SEC/ drawFrame) {  //40针
			Sleep(CLOCKS_PER_SEC / drawFrame + startTime - endTime-1);
		}
		else {
			Sleep(1);
		}
}

下节预告

运动模块详细讲解 创意桌面之移动图标-技术片(二)

文章作者: Lulu6432
本文链接:
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Lulu6432技术漫步
创意桌面
喜欢就支持一下吧