系统托盘菜单点击之后500毫秒内的残影

想用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),等软件的整体功能全部完成之后,这里再返回头来深入的推敲一下吧。

以前上学的时候觉得所有的知识都挺容易理解的,现在也许是年龄大了,即便是对已经已经熟练掌握了的知识,再看的时候,都会感觉是“一头雾水”,唯有继续艰难的、一点点的重新理解,才能让自己感觉有所收获。

Related Posts

Android Studio开发应用在真机上安装运行

昨天在电脑上安装了一套Android Studio,这是一套非常高效边界的Android应用开发工具。初步使用觉得除了安装过程比较耗时,其它都很顺利。 以前从来没有接触过Java语言和Android应用开发,所以上手有一些缓慢,但网上例子很多,Android Studio本身也提供了初始应用程序框架,所以只需要新建一个项目就可以直接运行、观察结果。 我想将这个最基本的Demo运行在自己的手机上,也就是真机体验一下。看网上介绍都很繁琐,估计这些介绍都是基于低版本Android Studio而言吧?至少在我所安装的版本上,几乎不用做任何设计、不做任何额外的工作,很顺利就可以完成真机运行。 只需要两步:手机开启“开发者模式”、在AS内使用自带的包管理器安装USB Driver。如此两步中的第二步我也不确定是否是必须的,也许连USB Driver都不需要安装也说不定,总之我就只做了如上两步,并没有如其他文章列举的,又要升级驱动、又要安装额外的什么东西,什么都没有做,连上手机,就可以直接真机运行了。 然后我又看了看Kotlin语言,据说是比Java更先进、更优雅的语言。但是只大概看了一两眼,就觉得不喜欢。说实话我连Java都不喜欢,相对而言还是喜欢C/C++那样“板板正正”的语言风格,对于“如诗如画”的语言,你觉得它能够写出“自然语言感觉”,但在我看来这是一种凌乱与松散。 之所以要体验一下这个开发工具、以及上手接触一下Android应用开发,也不是有什么项目或开发任务,只是想在自己的手机里实现一些自己觉得比较有用的小工具。这些小工具在应用市场上其实很多,但不是收费、就是内置了广告,我觉得我既不需要太多的功能、也不想花钱或看广告。 所以自己实现一下,自给自足好了。

PHP8中不再提供XMLRPC模块

自从PHP8.0版本开始,php for windows的默认安装包里面已经不在提供php-xmlrpc模块。这是因为xmlrpc模块的编译依赖于libxml,也是一个古老且停止了更新维护的模块。也许是处于安全性和先进性的考虑,所以PHP8中的xmlrpc模块便也不再默认提供了。 但在官方文档中并没有明确的提出这一点,而是“暧昧”的说可以在pecl中找到相关的模块。在pecl的官网也的确能够看到这个xmlrpc的页面,其中也是模棱两可的继续展示着它的二进制下载地址。 不过它所提供的DLL二进制下载包的下载地址中所有的链接,都已经是无效的、无法完成下载的了。 不清楚这些预编译的dll文件,是曾经提供过、但后来某种原因不再继续进行编译、提供。以至于现在都无法下载;还是从PHP8发行之处,就已经不再提供。如果是后者,有一点很难解释:既然不提供、那么还发布这个页面做什么呢?如果是前者、也很难解释,页面上没有任何的变更提示声明。 无论如何,对于xmlrpc模块的使用,现阶段只有以下四个方案,并且也许只有第一个方案是可行的: 方案一、降配使用PHP7进行模块的使用; 方案二、在PHP8中使用networking-xmlrpc平替模块; 方案三、自己通过源代码进行PHP8扩展模块的编译,编译生成xmlrpc的dll文件使用; 方案四、自己使用simpleXML对需要的XML格式文件进行解析,完成相关功能。 我现在为了追求开发速度,临时使用了方案一,这样至少能让开发进度继续进行下去。不过这样一来,整个项目中的其他代码又会因为使用了PHP8的语言语法特性而无法正常运行。不大可能再对整个项目进行代码调整,所以这一方案只是临时的、仅仅用于完成xmlrpc相关功能部分的实现。 之后也许会考虑使用方案四重写现在的代码,自己实现其中具体的解析,这样就可以再将环境语言重新恢复回PHP8版,以确保整个项目依然能够正常运行。

CI4中声明stdClass类实例

最近使用CodeIgniter4框架进行宠物项目的Server端开发,因为model层还没有全部实现好,所以准备用stdClass临时拼凑一些伪代码出来,相关代码如下: 但是如上的代码是无法正常运行的,会提示没有stdClass类声明。原因是CI4框架中引入了PHP的命名空间的概念,注意到上面代码截屏的第3行就已经指定的这段代码是在App\Controllers空间下,所以其中的地14行相当于是要声明一个App\Controllers\stdClass类的实例,显然这个“空间内类”是不存在的,自然也就无法找到类声明、进而无法完成类实例化。 将上面的new stdClass()语句稍作修改,使用“绝对空间路径”指定stdClass类的空间地址即可解决。 因为stdClass类是PHP内置的基础类,它的命名空间就是在“根”下,所以上面代码修改如下,即可解决问题: 附: 我是用CI框架好多年了,可能是从CI2开始使用的吧,当初选择这个框架是因为觉得它非常的轻便、小巧,足够的简单。后来CI3发布之后也用CodeIgniter3做过一些项目,对这个框架十分钟爱。 这次开发,便也选择了CI框架,本来起初想追求稳妥继续使用CI3框架。一来比较熟悉、二来也是因为基于CI3我已经积攒了足够多的基础库,开发速度会比较快。但到底还是犯了程序员最喜欢犯的毛病——追求新技术。 使用新的技术通常情况下似乎能够带来生产力的提升,但这也许是个“假象”,新技术并不一定就真的好用,尤其是在自己不熟悉、不熟练的时候,贸然使用新的技术,往往会导致初期开发成本的增加、效率低下。 所以不到迫不得已、不是必须由新技术才能搞定的需求,最好还是使用成熟的、自己最熟悉的工具和技术,才是稳妥的做法。

着手开始基于微信小程序的APP开发

虽然我对《又大又杂的APP》充满了厌恶,但既然已经答应了朋友,无论如何也只好硬着头皮开始了这个微信小程序的开发。才开始两天,就发现真的是太痛苦了。整个项目杂乱、庞大,而且连基本的规则都是混乱的。 它期望利用微信小程序完成一个SNS社交平台类应用的构建,这几乎就可以看作是痴人说梦,甚至可以说是“梦中梦中梦”。 微信其实就已经是“梦中梦”了,原本微信只应是一个IM工具,而诸如社交、分享、朋友圈的功能,应该是分散在手机系统的各个APP中,然而微信却将这所有的功能整合到了一个应用中,好像在手机系统中嵌入了一个子系统,加之微信提供的公众号、服务号、小程序等扩展能力,它真的可以完成“梦中梦”的实现。 然而我那个朋友想做的APP,是一款宠物兴趣人群的SNS应用,但他却只想在微信的小程序中实现,他的理由很简单:小程序开发成本低、推广起来用户基础好。 但是他想做的本身也是一个平台级应用,例如:这个应用是具有SNS属性的、拥有SNS属性就意味着有好友关系、好友之间能够进行短信短消息的交换…… 如此一来,相当于你打开手机之后想分享一个照片,不需要使用手机中的、成熟的SNS社区,只要进入微信那个“子系统”就可以操作了。 而当你想将自己的猫咪日常生活分享给你的“猫咪好友”时,这个好友其实即不再某个SNS平台中、也不再微信中、而是在微信的小程序的某个小程序服务商列表中,于是你就要:打开手机、进入微信、启动小程序,使用这个小程序APP分享照片。这不就是“梦中梦中梦”么? 我自己的电脑性能差、手机性能也很差,所以平日中我使用微信都比较费劲、卡顿的,有些时候去商场买东西必须使用店家的小程序时我总会皱眉——几乎可以肯定很难快速启动他们的小程序,几乎可以肯定大概率会加载慢、崩溃。而那些商家的小程序其实功能还算简单、页面也不复杂呢。 我现在都可以想象出朋友那个宠物SNS小程序,果真实现出来之后将会何其缓慢、问题重重。 事实上,它很可能实现不出来,因为是我在开发这个APP呀,我的电脑老旧得甚至连开发者工具都运行不起来。只一个非常简单的页面组件的开发,都会崩溃好几次。所以两天下来,连一个页面都没有完成。如此缓慢的进度,想实现出来?又是有点儿“痴人说梦”了。 开发过程的技术细节我觉得到没什么太多可以记录的,至少现在还没有遇到值得记录的内容。毕竟现在刚刚开始,只是做了一些基本的页面,而这些页面也就只是html代码和css样式的编写,其中不存在什么高新技术。 如果往后的日子里,这个项目能够持续开发,并且真能向着最终目标一点点的前行,那我就将开发过程中遇到的问题、值得写上几笔的地方,当作日记记录在这里,也方便自己今后回顾这段“痛苦不堪”的帮忙经历吧。

辗转相除法计算两个数的最大公约数

本来想做一个在线的一元二次方程求解小工具,但是真的上手操作才发现,想法很简单、实现起来很麻烦。所以我只好不断的简化需求,经过几次简化现在只能先完成对分数的化简操作,也就是在给定一个分数之后,对这个分数进行约分得到最简分数。 其中用到了一个求两数最大公约数的方法——辗转相除法。 实际上想计算两个数的最大公约数,有几种不同的方法,其中辗转相除法是相对容易理解、也比较容易通过程序实现的。 这里是最终完成的效果演示: https://www.m3we.com/mathtools/gcd.php?numerator=3334&denominator=12 即便是这个简单的功能,现在的演示也仍然不够完善、不够完美,还有很多需要进一步完善的地方。所以对于求解一元二次方程,短期内是难以实现的,只有一步步的先将这些基础环节做好,之后再做打算了。 update 2024.07.13 自己试了几个,发现还是存在bug的,例如下面这个计算过程,就是不正确的,原因还没有推敲,估计还要几天才能解决。 https://www.m3we.com/mathtools/gcd.php?numerator=333143543545.12&denominator=124.32 update 2024.07.14 18:51 已经找到了上面bug产生的原因,并且初步解决了。这里欠着一篇关于这个bug的记录,额外的又发现了一些新的问题,例如对于如下的分数,最后的表现也不尽人意,所以这个小工具还是有很多要改进的地方: 1、如果分子或分母中有符号,则在最终的结果中,应该将符号提取到整个分数的外面: https://www.m3we.com/mathtools/gcd.php?numerator=-333&denominator=33 2、如果分子和分母中同时有符号,虽然最后的结果是正确的,但是这只是计算的结果,与思维的过程实际上是不同的。正确的思维过程应该是先完成(增加一步预处理)变号操作: https://www.m3we.com/mathtools/gcd.php?numerator=-333&denominator=-33

Electron.js中的警告错误2则

最近在使用electron.js进行一个客户端APP的开发,虽然electron.js的开发可以实现一端开发、跨平台实现。但实际上我的主要考虑发和运行环境是一样的——都是在Windows10系统中进行。此时遇到了2个警告问题,这2个警告都没有找到原因、并且都没有解决,只是先临时记录一下: 1、Request Autofill.enable failed APP启动之后,在主进程的控制台输出上会有如下的错误提示:”Request Autofill.enable failed. {“code”:-32601,”message”:”‘Autofill.enable’ wasn’t found”}”, source: devtools://devtools/bundled/core/protocol_client/protocol_client.js (1) 这个问题在网络上没有找到比较准确的答案,网上提到的通常是:这个警告信息并不构成实际问题,可以忽略。但是有人也提出“做为编码洁癖者,受不得这样的提示出现”。 经过尝试发现,这是在开发时打开了浏览器的debug窗口引起的,如果在开发的时候不打开调试窗口,则不会出现这个错误。 2、Electron Security Warning (Insecure Content-Security-Policy) This renderer process has either no Content…