65.9K
CodeProject 正在变化。 阅读更多。
Home

媒体中心放大镜

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0投票)

2009 年 10 月 14 日

CPOL

6分钟阅读

viewsIcon

32431

downloadIcon

425

可用于放大屏幕(包括分层窗口和透明效果)的工具。对媒体中心非常有用。

引言

开发此程序是因为我在互联网上找到的放大器程序要么太贵,要么功能太少。很多年来,我一直使用 Workers Collection Magnifying Glass ver. 1.0。我发现这是一个很棒的程序,但它缺少我想要的一些功能。我也觉得放大屏幕的想法很有趣,所以我自己写了一个程序。

背景

我通过参考以下内容学习了如何实现此程序中的功能:

以上每个程序都为我理解创建此程序所需的工具做出了有益的贡献。

此程序使用了一种创新的菜单管理方式。菜单本来应该保留在放大器下方,但在 .NET 中很难做到,所以菜单系统被重新设计以提供所需的功能。

这也是我第一次尝试使用全局热键。热键组合可由用户自定义。

Using the Code

代码是内部注释的,所以这里只给出简要概述。

程序启动时,OnLoad 事件将设置各种设置并读取用户配置。当用户退出程序时,这些设置会在 itmExit_Click 例程中保存。

除了这两个例程,代码中还定义了四个区域:

  • 放大例程
  • 菜单选项
  • 热键例程
  • 菜单管理

这些区域分别关注程序执行的不同部分。

放大例程

放大例程控制着将屏幕图像简单放大并将其绘制到窗体的所有必要步骤。这是一个多步骤的过程。

  1. tmrRepaint_Tick:首先,计时器触发,从而启动重绘序列。放大器会移动到顶部(除非有子菜单打开)。放大器会移开以避免遮挡屏幕捕获。创建临时捕获位图并将其传递给下一个例程。
  2. CaptureDesktop:临时位图会被绘制成屏幕的捕获图像。
  3. CaptureCursor:当前光标图像会作为另一个临时位图被捕获,并直接传递给组合例程。
  4. CombineCursorDesktop:光标会以正确的位置添加到尚未放大的桌面位图中。
  5. RepaintMagnifier:现在包含桌面和光标的临时位图会以正确的放大倍率绘制到窗体上。如有必要,窗体首先会被清除。

在此过程中,对象仅在例程不会自动删除和销毁时才会被处理(为了简化)。此外,每次重绘操作后,都会运行垃圾回收,以确保内存不会在自动收集运行之间急剧增加。

菜单选项

所有与菜单中包含的可配置设置和选项相关的操作均在此处管理。有用于更改菜单复选标记的例程,当某个项目被选中时。有用于检查输入值是否正确的例程。选项也在执行这些例程时设置。

热键例程

热键例程仅允许自定义用于隐藏和显示放大器的全局热键。相关代码可以在 cjbarth 的项目 KeyPressDecoderManaged Windows API 中找到。

菜单管理

菜单管理例程要复杂得多。在 .NET 中,上下文菜单会显示在同一应用程序的窗体之上。这意味着在这种情况下,它不会被放大。为了克服这个问题,菜单实际上被分解成几个相互关联的菜单。没有子菜单。使用子菜单会隐藏一些用于我所做的菜单处理所必需的事件和属性。

当菜单打开时,它会将自身设置为全局变量并启动一个计时器。每当计时器触发时,它就会检查鼠标是否在菜单上(MouseOffMenuMouseOut)。这并不像看起来那么容易,因为这里可能涉及子菜单。此外,在多显示器系统上,.Contains 操作已损坏。我从未能够可靠地报告鼠标是否实际在菜单或其任何子项上。

如果鼠标不在菜单上,它会降低 2% 的不透明度。当菜单“消失”时,它会关闭。

由于一次只能打开一个子菜单,每当子菜单打开时,它就会将全局变量更改为自身。然后,当鼠标悬停在菜单的例程运行时,它们将始终检查主菜单,然后检查可能打开的任何子菜单。

关于哪个子菜单已打开的信息(例如 SizeLocation)以及子菜单事件(例如 Opened 事件)对于单个上下文菜单的基于集合的子菜单来说是不可行的。因此,使用了多个上下文菜单来获取此信息。然后将这些上下文菜单链接在一起,使它们看起来像一个单一的菜单。

布局类

clsLayout 类是用于移动放大器并保持光标在正确位置的代码所在。此代码的设计相当复杂,但使用起来很简单。

基本上,每次需要移动框时,都会调用此类来确定其位置。此类会考虑诸如框的大小、光标的位置、框与屏幕边缘的接近程度、光标与框的接近程度以及当前缩放级别等因素。所有这些因素都会影响框的位置。

这些例程的复杂性源于这样一个事实:框不固定在光标上,而是尝试避开光标同时保持在光标附近。此外,框必须位于一个不会放大自身的位置,并且不能移出屏幕边缘。

此类中的代码有很好的文档记录(以免我混淆)。有关更多信息,我建议阅读代码及其注释。

Win32 调用

mdlWin32 模块包含有关捕获屏幕、捕获光标以及在这些操作后清理内存的信息。此处引用了诸如 BitBltGetCursorInfo 等系统调用以及用于保存返回数据的结构。总共,仅调用两个不同的系统 DLL(*user32* 和 *gdi32*)共七个例程。

关注点

有一种方法可以完全在 .NET 中完成此操作;然而,由于即使在框架 3.5 版本中也存在 bug,它无法正常工作。在 .NET 中有一个方法可以精确地完成我们想要的操作,称为 Graphics.CopyFromScreen。如果我们使用 SourceCopyCaptureBlt 调用该方法,我们可以一步完成整个重绘操作。也许在 .NET 4.0 中,这会起作用。作为参考,我在代码中添加了相关的注释。

历史

  • 2009-10-12:初始发布。
© . All rights reserved.