技术片(一)-创意桌面之移动图标
创意桌面移动图标-技术片
历经一年时间,一次又一次的迭代,逐渐趋于稳定,从一开始简单几何运动到现在复杂的逐帧播放舞动视频。每一次大版本迭代都需要一个好的创意,以及技术去实现。
眼界开阔,创意无限!
废话不多说,步入正题。
开发环境
软件基于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);
}
}
下节预告
本文链接:
/archives/1697849126036
版权声明:
本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自
Lulu6432技术漫步!
喜欢就支持一下吧