在现代图形用户界面(GUI)设计中,半透明对话框为用户提供了一种更加美观和直观的交互方式。本文将介绍如何在C++和MFC环境中创建半透明对话框,以及如何在.NET环境中实现相似的功能。
从Windows NT 5.0开始,支持了分层窗口(Layered windows),这使得开发者能够创建具有复杂形状和alpha混合效果的窗口。然而,如何在这些分层窗口上显示标准控件成为了一个主要挑战。
在创建对话框时,首先通过CreateWindowEx函数创建一个假窗口,使用WS_EX_LAYERED、WS_EX_TRANSPARENT和WS_EX_NOACTIVATE样式。然后,通过SetLayeredWindowAttributes函数将真实窗口的alpha值修改为5,使得真实窗口几乎透明。
真实窗口负责处理用户输入事件和Windows消息,而假窗口负责呈现。假窗口始终保持与真实窗口相同的大小和位置。
当需要刷新呈现时,首先绘制背景图像,然后通过发送WM_PRINT消息捕获所有子控件,并在假窗口的相同位置绘制。特别是对于编辑控件,如EditBox/Editable ComboBox等,需要自己绘制光标。
当UI有更新时,需要刷新假窗口。在示例中,它递归地钩住所有子控件,并使用SetWindowLongPtr函数和GWLP_WNDPROC参数更改WNDPROC地址。
第一步是将/Src/*.*目录中的所有文件复制到项目中。
第二步是需要一个图像文件作为对话框的背景。最好选择支持alpha通道的PNG或TIFF格式。图像文件可以嵌入到资源中,也可以放置在磁盘上,这取决于自己的判断。
最后一步是将对话框基类从CDialog替换为CImgDialogBase。
// 从磁盘文件加载
CDemo2Dlg::CDemo2Dlg(CWnd* pParent /*=NULL*/)
: CImgDialogBase(CDemo2Dlg::IDD, CUtility::GetModulePath() + _T("background.png"), pParent) {
}
// 或从资源加载
CDemo3Dlg::CDemo3Dlg(CWnd* pParent /*=NULL*/)
: CImgDialogBase(CDemo3Dlg::IDD, IDB_PNG_DLG2, _T("PNG"), AfxGetResourceHandle(), pParent) {
}
第一步是将/Src/*.*目录中的文件复制到项目中。
第二步是需要一个图像文件作为对话框的背景。最好选择支持alpha通道的PNG或TIFF格式。
最后一步是将对话框基类从Form替换为ImageDlgBase。
public partial class Form2 : CoolImageDlg.ImageDlgBase {
public Form2() {
base.DlgBgImg = ImgDlgSample.Properties.Resources.DemoDlgBg2;
// ......
}
}
对话框的工作方式是,如果有一个像素需要更新,整个窗口将被刷新。因此,如果对话框非常大且复杂,或者有很多子控件,可能会导致性能问题。
有些控件不能与WM_PRINT一起工作;在这种情况下,控件将无法正确显示。换句话说,并非所有控件都受支持。
示例代码使用了Zoltan Csizmadia的GDI+辅助类。如果不想使用GDIPlus.dll,CxImage是另一个选择。