自定义字体对话框的实现

在开发绘图应用程序时,经常需要为用户提供字体选择的功能,但并不希望用户能够修改字体大小,因为应用程序会自动管理字体大小。本文将介绍如何通过自定义字体对话框来实现这一需求。

在设计绘图应用程序时,希望提供一个字体对话框,但不希望用户能够修改字体大小。这是因为应用程序会自动管理字体大小,用户手动修改可能会破坏设计。面对这种情况,有两个选择:

  • 重写整个字体对话框。
  • 对现有字体对话框进行“黑客”操作。

考虑到字体预览功能的重要性,选择了第二种方法。

黑客操作

如果能够获取到要操作的窗口句柄,那么问题就变得非常简单。只需要添加几个本地函数调用,例如:

[DllImport("user32.dll")] static extern IntPtr GetDlgItem(IntPtr hDlg, int nIDDlgItem); [DllImport("user32.dll")] static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); const int SW_HIDE = 0;

每个UI组件都有一个固定的ID,可以使用Spy++工具来识别它们。对于字体大小,这些ID分别是1090和1138;因此,可以通过调用以下代码来隐藏不需要的组件:

ShowWindow(GetDlgItem(dialogHandle, 1090), SW_HIDE); ShowWindow(GetDlgItem(dialogHandle, 1138), SW_HIDE);

寻找对话框句柄

关键问题在于如何识别对话框句柄。本文提供了三种可能的解决方案,其中两种虽然流行,但各有问题。

  • 使用FindWindow:在对话框显示后,使用FindWindow()本地调用来找到字体对话框。在显示对话框之前,启动一个计时器,如果找到对话框则停止。这种方法的问题包括:
    • 计时器的间隔应该是多少?如果选择的时间太长,用户可能会看到不需要的UI元素,然后这些元素会消失。
    • FindWindow需要窗口标题作为输入参数。如果Windows不是英文版,字体对话框的标题就不是"Font"。
    • 如果找不到正确的对话框,它将一直运行下去。
  • 使用GetActiveWindow:假设当前活动的窗口就是字体对话框;再次,在显示对话框之前启动一个计时器,并希望字体对话框在计时器第一次触发时是活动窗口。同样,正确的计时器间隔是未知的,如果字体对话框不是最顶层的,可能会向另一个应用程序发送命令。

最佳解决方案:采用本文描述的方法:

在.NET中自定义OpenFileDialog。

从这个示例中移除了所有不需要的代码,得到了一个简单的解决方案。应该使用FontDialogEx类而不是FontDialog。它的ShowDialog方法创建了一个名为DummyForm的虚拟、不可见的表单。不可见性是通过设置名为UFLAGSHIDE的标志来实现的。DummyForm等待直到它被激活,这可以在其重写的WndProc(ref Message m)函数中找到。

protected override void WndProc(ref Message m) { if (mWatchForActivate && m.Msg == (int)Win32.WM_ACTIVATE) { mWatchForActivate = false; mFontDialogHandle = m.LParam; mNativeDialog = new FontDialogNative(m.LParam, mFileDialogEx); } base.WndProc(ref m); }
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485