尤里的复仇任务包 尤里的复仇新战役任务包
窗口贴边的功能其实很早就存在了。
早在N年之前,电脑的屏幕分辨率极其的小,像类似于QQ这样的聊天工具,就有贴边功能,当然,现在也有只不过似乎默认已经不启动了。
我的一些老的软件还有这样的功能,但是只要是新的软件都几乎都没有这个功能了。可能是因为时代变了,屏幕的分辨率非常的高,所以就没有这个需要了。
Win7之后还有一个鼠标拖着窗口移到屏幕边缘的时候,就可以让窗口占据半个屏幕的功能。
我记得我之前就在精易论坛上看到过关于窗口贴边的程序源码,但是我在手头的源码库里没有找到这个源码。
事后我才想起来,可能我没有保留那个源码,因为那个源码其实没有什么实质性的参考性。因为它是在窗口上放了一个“时钟”控件。
然后这个时钟控件会在一个很短的周期内做一个判断,利用窗口的“左边”、“顶边”等四个参数,判断这个窗口是不是有一部分在屏幕外边,并且根据这个特性再次更改窗口的位置,让它仅仅一很小的一部分出现在屏幕上。
就像看魔术师表演一样,看效果很神奇,但是看了代码又觉得很无聊。由于这个代码几近于硬编排一样的代码,所以我没有保留。最近也是我无聊,我又开始研究起这个功能来了。
第一个源码
我下载了好几个源码,它们各不相同,每个都有一点点的缺陷。不过都能实现贴边,而且它们的原理是一样的。都是一个能够判断鼠标位置和窗口位置的函数,并且根据判断结果相应的更改窗口的位置,位置可以是恢复也可以是隐藏窗口。之后还有一个周期性运行的时钟来循环运行这个函数。
当然这个比我上次看到的那个代码不同的地方是,这个没有用到时钟,而是通过“控件行为”的方式,判断了鼠标位置。然后更改了窗口的位置。这个代码里有一个很好的示范了两种场景。
一种是鼠标在软件界面上的情况。在软件界面上有两种情况,一种是,程序没有贴边。那么什么事情都不会发生。
一种是贴边了,那么它只露出了小小的一部分,那么这个时候鼠标放到软件上之后,这个窗体的显示应该被复原。
第二种是鼠标离开窗体后的场景。那么在这种情况下,如果程序没有贴边,依旧什么事情都不会发生。一种是贴边了,那么它应该把自己隐藏起来,留下仅仅一条小的边缘。
当然控件行为中的“失去焦点”和我述说的“鼠标在不在窗口”上还有一个非常出入的地方。因为Windows的窗口有一个特性就是被“激活”的窗口和未被激活的窗口。
一般性情况下一定有一个被激活的窗口,如果没有窗口被激活,就是桌面被激活。(桌面其实是一个全屏的程序。你可以关闭explorer.exe 文件资源管理器关掉它的。)我们当前使用的窗口就是激活的那个。其他的窗口都是“非激活”状态。
在Win7之后,两种窗口的外观上就相差还不大了(Win7中激活的窗口的边缘阴影会更重一点。)要是你用的是例如98之类的,就会知道,激活的窗口的标题是蓝色的,非激活的窗口是灰色的。
这里就有一个不一样的地方就是,一个窗口不会因为你的鼠标移到别的窗口上就会进入非激活状态,也就是“失去焦点”。你必须要点一下其他位置,才能激活其他窗口,那么原来的那个窗口才失去了焦点。
也就是说,这个程序必须把它放到屏幕边缘,然后鼠标点一下窗口外的地方才能让它隐藏。其实这个样子和我记忆中的QQ软件的样子是不一样的。
QQ是在屏幕边缘的时候,鼠标移开QQ,就会自动隐藏了。然后鼠标接近隐藏的地方就会复原窗口。期间我没有任何点击鼠标的行为。这个和我预期的不一样。
但是这个代码里还有一个优点,就是它做了向右隐藏的功能。
这点非常重要,和接下来要分析的第二个源码相比,它多了向右隐藏,却少了向上隐藏。那向右和向左隐藏有什么区别呢?其实还是很大的。因为类似于易语言这样的标准窗体通常都是由四个值来决定位置,“顶边”、“左边”、“长度”、“宽度”。
左边和顶边可以理解为坐标。将屏幕最左上角的那个像素点认为是圆点。横过来从左到右是x轴。从上到下是y轴。(数学课上老师教我们的坐标轴,y轴是从下到上的。)那么顶边和左边就是生成的这个窗体,它的最左上角,对于屏幕最左上角的坐标。而长度和宽度更容易理解,其实它就是窗体的最右下角的那个点到与最左上角的那个点为圆点的坐标。由于窗体的边都是和屏幕的边缘平行的,所以这两个点就可以确定这个窗体的位置和大小。那么在这种特性下,如果左边的值是负的,那么这个窗体就会有一部分在屏幕外,它就符合贴边要求了。但是右边却不行。
因为窗体的位置是由最左上角决定的,就算你的左上角坐标完全一样。你也有可能会因为这个窗体的宽度过宽而导致出框。或者说左上角的坐标是不变的,窗体的大小也是不变的,可电脑屏幕的分辨率变了,也会出框。所以左边只要考虑“左边”这一个因素。而右边要考虑,左边、宽度、屏幕分辨率三个因素。
当然作者说他只做了左右的代码,往上的他没有做。他说往上的和往左的差不多。这也不假,但是以前的QQ,是贴哪条边就要往哪边隐藏的,这包括了上边。
第二个源码
第二个源码就比较厉害了。
首先它应用了大量的windows api,并且引入了句柄、鼠标坐标、矩形、时钟等等概念。要不是学点gdi什么的可能无法理解。
首先看下面的部分。首先是通过一个循环,取出窗口的句柄。句柄是一个数字,它代表着一个控件。然后取出了对应窗体的“矩形”。矩形由4个数字组成,简单来说就是上下左右。前面说了,左上角和右下角就可以决定窗体大小和位置。这里我还和上面的代码搞混了一个概念。易语言里是左上、长宽。而矩形是上下左右。其实有两个值是不一样的。长=右-左。而宽=下-上。其他就差不多了。第二个是鼠标的坐标,鼠标的坐标和窗体的左上角有点像。
那么屏幕是一个长方形,窗体是一个长方形,鼠标是一个点,那么这个点在不在长方形之上的逻辑还是很简单的。就是x坐标在左右之间,y在上下之间,那么鼠标就在那个窗体上了。这样的判断无需点击窗口,这个和QQ就一样了。接下来也有改变位置的逻辑,不过这个就和第一个一样了。
接下来看第一个子程序。SetTimer,其实啊这个和易语言里的控件时钟是一摸一样的,不过没有控件要求。这个api,需要将一个子程序以指针的形式作为一个参数,填入到api里,然后周期性地运行这个程序。也就是说在失去了控件的前提下,我们同时也失去了操作控件行为的能力。所以我们只能运行一个程序不停地监控鼠标的坐标,来实现第一个源代码中实现的目的。
还有这个子程序中是利用句柄来对窗体进行控制的,这样被控制的控件成为了一个参数。也就是说我可以让任何的窗体都实现贴边能力。甚至是其他软件的窗口。只要取到他们的句柄,就能让它们贴边。
评价
源码1:
优点:
展示了向右边贴边的代码。(反正在贴边的逻辑里,不做右贴边的功能就是避重就轻了。)
缺点:
几乎是硬编排,如果我再写第二个窗体的话,我可能要把代码复制一遍。
利用窗口的“焦点”作为判断节点,出现的效果似乎没有达到预期。
源码2:
优点:
开关能力。只要愿意,可以立即停止贴边功能。
使用句柄,让这个贴边代码可以反复应用在任何窗体上。
缺点:
没写右边。
共同缺点:
因为只是功能的演示,它们几乎都是直接改变了窗体的位置。而我们看到的窗体贴边似乎是慢慢地滑进去的。有一种动画效果。于是我结合了两者的优点重写了这个贴边的代码。
根据这个原理,我添加了两个参数。一个是留边的距离,这个可以调整这个窗口遗留在屏幕上的像素长度。当然我观察了一下现在QQ的贴边功能。它整个窗体都移出去了。
但是你的鼠标在移出去的地方附近就可以恢复窗口。其实窗口的底边都是负数的时候,只要设置一个矩形区域用于恢复窗口即可。这个区域不一定是窗体的区域。
第二个是移动距离,我为调整窗口的代码添加了移动距离,这样窗体是慢慢的划出,而不是生硬的突然出现。
第三,补全了所有方向的贴边。包括向下,因为有些人的电脑,他的任务栏居然是在左边的,还有更夸张的是在上面的(MAC的忠实用户?)。
BUG
这样的代码似乎还有一个bug,就是如果这个窗口在屏幕的角落的时候,可能它的两个边都是出屏幕的,它有可能会向两个方向贴边,最后整个窗体就变成角落上的小疙瘩了。当然这个解决方法很简单,你只要在判断的过程多加一个判断条件就可以了。
别忘了看看火星鼠的汉化作品。
心灵终结3.3.6汉化包BY火星鼠汉化组正式发布
尤里的复仇经典MOD《隐风之龙》1
MIX恢复小助手详细说明