在互联网上,发现许多放大镜程序要么价格昂贵,要么功能过于简单。多年来,一直使用“Workers Collection Magnifying Glass ver. 1.0”,虽然它功能强大,但仍有一些想要的功能缺失。因此,决定自己动手编写一个屏幕放大程序。
在开发过程中,参考了以下资源来实现程序的功能:
这些资源都为程序开发提供了宝贵的帮助。
程序中的菜单设计非常独特。它需要始终位于放大镜下方,但在.NET中实现这一点并不容易,因此对菜单系统进行了重构,以提供所需的功能。
这是第一次尝试使用全局热键。用户可以自定义热键序列。
代码内部有详细的注释,这里只提供一个简要概述。
程序启动时,OnLoad
事件会设置各种设置并读取用户配置。这些设置在用户退出程序时通过itmExit_Click
例程保存。
程序分为四个主要区域:
每个区域都专注于程序执行的不同部分。
放大例程控制所有必要的步骤,以简单地放大屏幕上的图像并将其绘制在表单中。这是一个多步骤过程:
tmrRepaint_Tick
:首先,计时器触发,开始重绘序列。放大镜移动到顶部(除非打开子菜单)。放大镜移出屏幕捕获的路径。创建临时捕获位图并传递给下一个例程。CaptureDesktop
:临时位图用桌面的捕获绘制。CaptureCursor
:当前光标图像被捕获为另一个临时位图,并直接传递给组合例程。CombineCursorDesktop
:光标被添加到尚未放大的桌面位图的正确位置。RepaintMagnifier
:现在包含桌面和光标的临时位图被绘制到表单上的正确放大倍数。如果需要,首先清除表单。在此过程中,对象仅在例程不会自动执行删除和销毁时才被删除和销毁(为了简单起见)。此外,每次重绘操作后,都会运行垃圾收集,以确保内存不会在自动收集运行之间急剧增加。
所有与菜单中包含的设置和选项相关的操作都在这里管理。有例程可以在一个项目被选中时更改菜单上的复选标记。有例程可以检查输入的值是否正确。这些例程执行时也会设置选项。
热键例程允许自定义用于隐藏和显示放大镜的全局热键。此代码可以在项目KeyPressDecoder
中找到,由cjbarth编写,也可以在Managed Windows API
中找到。
菜单管理例程相当复杂。在.NET中,上下文菜单会在同一个应用程序的表单上方出现。这意味着,在这种情况下,它不会被放大。为了克服这个问题,菜单实际上被分解成几个相互关联的菜单。没有子菜单。使用子菜单会隐藏一些处理菜单所需的事件和属性。
当菜单打开时,它会设置一个全局变量,并启动一个计时器。每次计时器触发时,它都会检查鼠标是否在菜单上(MouseOffMenu
和MouseOut
)。这并不像看起来那么容易,因为这里可能涉及潜在的子菜单。此外,在多显示器系统上,.Contains
操作是有问题的。从未能够可靠地报告鼠标是否真的在菜单或其任何子菜单上。
如果鼠标不在菜单上,它将透明度降低2%。当菜单“消失”时,它就会关闭。
由于一次只能打开一个子菜单,每当一个子菜单打开时,它会将全局变量更改为自身。然后,当鼠标悬停在菜单上的例程运行时,它们将检查主菜单(它们总是这样做)以及可能打开的任何子菜单。
无法使用基于集合的单个上下文菜单的子菜单获取有关哪个子菜单打开的信息(例如Size
和Location
),以及有关子菜单发生的事件(例如Opened
事件)。因此,使用了多个上下文菜单来获取此信息。然后将上下文菜单链接在一起,使它们看起来像一个单一的菜单。
布局类clsLayout
是代码存储的地方,用于移动放大镜并保持光标在正确的位置。这个类的设计相当复杂,但使用起来很简单。
基本上,每次需要移动框时,都会调用这个类来确定位置应该在哪里。这个类会考虑诸如框的大小、光标的位置、框靠近屏幕边缘的距离、光标靠近框的距离以及当前的缩放级别等因素。每件事都对框的位置有影响。
这些例程的复杂性源于框不是固定在光标上,而是框试图避开光标,同时仍然靠近光标。此外,框必须处于这样的位置,即它不会放大自身,也不得超出屏幕边缘。
这个类中的代码有详细的注释(所以不会被自己搞糊涂)。更多信息,建议阅读代码及其注释。
模块mdlWin32
包含与捕获屏幕、捕获光标和清理这些操作后内存相关的信息。引用了诸如BitBlt
和GetCursorInfo
之类的系统调用,以及用于保存返回数据的结构。总共调用了两个不同的系统DLL(user32
和gdi32
),总共调用了七个例程。