创建透明对话框的探索与实践

Windows编程中,创建一个允许在其透明区域进行绘图的对话框是一项具有挑战性的任务。Windows操作系统本身并不直接支持透明的CWnd对象。尽管如此,可以通过一些技巧和方法来实现这一功能。本文将探讨创建透明对话框时遇到的一些问题,以及如何使用StyleDialog来实现透明效果。

创建透明对话框的挑战

实现StyleDialog的关键特性之一是能够使用透明区域。这意味着可以在其上进行绘制、绘画,并添加控件。以下是一些常用的方法及其相关的缺点:

  • 在OnCtlColor中返回HOLLOW_BRUSH - 这种方法对于控件来说是可行的,因为应用程序控制背景。只要不移动对话框,这种方法也适用于对话框,但这使得它相对无用,因为它会导致子控件停止接收OnCtlColor消息。
  • 使用区域 - 这种解决方案效果相当不错;然而,不能使用透明区域。此外,由于不能对边框进行抗锯齿处理,边缘看起来有些粗糙。
  • 层叠窗口 - 这是唯一一种创建真正透明窗口的方法。这对于创建淡入淡出效果效果很好,但由于透明度适用于整个CWnd,不能有的部分透明,有的部分不透明。
  • 层叠CWnd- 这些解决方案看起来和行为最好,但它们不是通用的,也不能在透明区域上进行绘画。

StyleDialog设计考虑

在创建透明对话框时,需要克服的其他难题包括拖动窗口时的抖动问题,以及在应用程序不是活动窗口时保持正确的背景。为了克服这些问题,StyleDialog采用了以下设计规则:

  • 当应用程序不是活动应用程序时,显示一个替代背景。这克服了当应用程序可见但不是活动时,应用程序下方的背景发生变化的问题。
  • 在拖动应用程序时显示一个替代背景。实际上,StyleDialog可以在拖动时显示正确的背景,但是层叠窗口与抖动相关的问题是不可取的。

使用StyleDialog

StyleDialog通过使用不透明的层叠窗口,并利用它在屏幕外位图上被维护的事实,实现了透明效果。以下是使用StyleDialog的步骤:

  1. 在StyleDialog.h中配置使用
  2. // 如果不使用Style Toolkit,则注释掉此行 #define USE_STYLE_TOOLKIT // 如果不支持透明度,则注释掉此行 #define USE_LAYERED_WINDOWS
  3. 从StyleDialog派生一个对话框
  4. 像往常一样使用向导创建基于对话框的应用程序。将所有CDialog实例替换为StyleDialog。注意:在替换时跳过CAboutDlg,除非也希望它成为StyleDialog。对于子对话框,只需将它们声明为StyleDialog。请参阅演示程序以获取示例。

  5. 配置StyleDialog
  6. 在调用OnInitDialog或DoModal之前,请执行以下操作:

    // 在调用初始化函数之前配置StyleDialog SetTransparent(TRUE); SetControls(ALL_CONTROLS); SetTitle(_T("Style Dialog Demo"));

    SetTransparent启用透明度。默认情况下它被禁用,因为在未使用的情况下它会浪费带宽。SetControls告诉StyleDialog在有自定义框架时使用哪些控件。这在下面有更详细的描述。默认情况下没有控件。SetTitle是当使用自定义框架时在任务栏中显示的标题。默认为空字符串。

  7. 为对话框添加样式(可选)
  8. 使用AddBackGroundStyle(style)将样式加载到对话框中。

StyleDialog的最小实现

以下图片和代码来自演示程序的Dialog 3按钮。

StyleDialog dlg(IDD_DIALOG3); dlg.SetTransparent(TRUE); dlg.SetTitle(_T("Standard Frame")); dlg.DoModal();

此示例使用标准框架,并且不使用Style Toolkit。实际上,设置标题并不是必须的,但如果不做,它只会显示“Dialog”。

如果启用了透明度,StyleDialog将在不是活动应用程序或窗口正在移动时显示替代背景。替代背景将位于可能已在透明区域上绘制的任何内容下方。

默认情况下,替代背景将是桌面背景色的实心填充。这可以通过以下方式之一覆盖:

  • SetOpaqueColor(clr) - 将实心填充更改为另一种颜色。
  • AddOpaqueStyle(style) - 将填充更改为样式。

对话框2按钮演示了背景样式的使用。

此示例使用没有控件的自定义框架,以及带有半透明PNG图像的背景样式。

这显示了非活动状态。它使用相同图像的完全不透明版本作为不透明样式。

创建自定义框架

StyleDialog需要知道在创建自定义框架时客户矩形的大小应该是多少。这是进行标题栏区域的命中测试和支持重写函数GetClientRect()所需的。StyleDialog维护一个可以通过GetFrameRect获取的外部框架,以及可以通过GetClientRect获取的客户框架。请注意,Windows不将此视为客户矩形。在进行绘画或擦除时,应该使用GetFrameRect或CDialog::GetClientRect来获取Windows定义的客户矩形。

调用GetFrameRect()获取外部框架矩形,然后调整边框和标题栏大小,然后调用SetClientRect()。

使用资源编辑器并创建一个带有静态控件的客户矩形。这样做的好处是可以在设计对话框时调整标题和边框大小。使用静态图片控件,因为它没有偏移量。

将控件的ID设置为SytleDialog的一个关键字ID - IDC_SC_CLIENT。当StyleDialog在resource.h文件中检测到此ID时,它将自动创建客户矩形。

还有用于控件的关键字ID,如下面的图片所示。

如果StyleDialog看到任何控件ID,它将为它们创建StyleButton,并加载关联的图像。它还将为每个按钮创建预期的功能。

其他考虑事项

StyleDialog不支持最大化;实际上,它禁用了它。原则上,这个功能可以被支持,但没有计划在未来添加这个功能。

并没有真正计划支持带有透明子对话框的透明对话框;然而,它似乎工作得很好,演示程序实际上就是这样做的。

为了避免在打开子对话框时出现烧穿效果,可以禁用父对话框的透明度,然后再重新启用。然而,开启和关闭层叠窗口可能存在时间问题,因此请谨慎使用此功能。

问题

使用自定义框架时的最小化和恢复 - 如果点击任务栏图标,StyleDialog将进入正确的活动或非活动状态,但它不会最小化和恢复。认为这与系统菜单没有此功能有关,希望在未来的版本中修复这个问题。

VC6用户 - 如果注释掉层叠窗口功能,StyleDialog将按原样工作。层叠窗口将在Win2K SP3及更高版本上工作,但需要获取更新版本的winuser.h、user32.lib和user32.dll。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485