想用C++实现一个简单的屏幕截图工具的开发,工具程序是放在系统托盘(IconTray)中的,然后通过鼠标点击托盘图标弹出菜单,再点击菜单中的截屏菜单,完成截屏操作。
软件界面如下:
一旦全屏截屏或框选区域截屏点击之后,程序就开始运行,将当前的屏幕DC保存下来,然后借助memDC将屏幕DC复制到一个bitmap中,再完成写盘操作。看上去是个非常简单的需求。
但是在Windows系统中(Win10),这个icontray的弹出菜单在点击之后并不会立即消失,我这里感觉大约会有500ms的减淡消失效果,最终导致截屏保存下来的图像,总是会带有被点击菜单的残影,如下图:
在程序里面处理其实可以有很简单的方法,就是做一个延迟处理,例如我现在延迟了0.6s、也就是600ms之后在创建screenDC:
// 立即对当前屏幕进行全屏截屏操作 void MyApp::CaptureWholeScreen(wxCommandEvent& event) { wxString _imgSavePath = DatetimeUtil::getTodayScreenShotPath(); if (PathUtil::dirExistOrMkdirSuccessful(_imgSavePath) != true) { wxLogDebug("截图存储目录不存在且无法创建,无法完成截图操作"); return; } // 延迟0.6秒后将整个屏幕DC保存下来,待后面按显示器切割使用 // @todo icontray的菜单点击后会渐变淡出,如果不设置这个0.6s的延迟,会有残影现象 Sleep(600); wxScreenDC _screenDC; // 遍历每一个显示器对应的桌面,按各自桌面尺寸,从_screenDC上截取各个桌面的图像 for (unsigned int _screenIndex = 0; _screenIndex < wxDisplay::GetCount(); _screenIndex++) { wxRect _screenGeometry = wxDisplay(_screenIndex).GetGeometry(); wxBitmap _screenCaptureBitmap(_screenGeometry.GetSize()); wxMemoryDC _memDC; _memDC.SelectObject(_screenCaptureBitmap); _memDC.Blit(wxPoint(0, 0), _screenGeometry.GetSize(), &_screenDC, _screenGeometry.GetPosition()); _memDC.SelectObject(wxNullBitmap); wxString _filename = PathUtil::desktopTimestampFilename(_imgSavePath, _screenIndex); if (_screenCaptureBitmap.SaveFile(_filename, wxBITMAP_TYPE_PNG) == true) { // @todo 生成缩略图,并将图像的文件信息写入本地数据库 // @todo 若软件主界面隐藏状态,则通知icontray弹出已生成截屏提示信息 } } } |
这样就可以基本确保不会将菜单残影带进最终的截图图像中了。
但是这样的写法总是给人一种“怪怪”的感觉,心理上很难接受。它奇怪在并不是精确的控制,而是一个凭借感觉的控制——是所有的windows系统都这样吗?是所有的windows主题、所有的电脑CPU性能无论高低,都一定能在0.5s左右之后残影消失吗?
而且这个菜单残影是windows的视觉淡入淡出效果、还是我程序写的不好导致的?会不会有一个系统事件来通知我菜单真的已经彻底消失了?
不清楚,现在为了赶软件开发的进度,所以这里只能先简单粗暴的Sleep(600),等软件的整体功能全部完成之后,这里再返回头来深入的推敲一下吧。