为对话框的控件设置字体不是什么难事,根据MSDN的介绍,设置字体最好放在对话框接收到WM_INITDIALOG的时候,所以可以在OnInitDialog中调用::EnumChildWindows(m_hWnd, ::SetChildFont, (LPARAM)m_font)枚举控件,并为每个控件发送WM_SETFONT消息。其中回调函数可以简单得定义如下:
但是当这个对话框是一个继承于CFileDialog的自定义类CMyFileDialog时,会有什么不同吗?首先你会意识到属于CFileDialog的控件都没有得到更新。通过SPY查看窗口句柄,可以快速得发现问题所在。原来,CFileDialog模板上的控件并不属于CMyFileDialog,它们都是CFileDialog的子窗口,解决方法很简单,将EnumChildWindows改为::EnumChildWindows(GetParent()->m_hWnd, ::SetChildFont, (LPARAM)m_font)。重新运行来查看效果,会发现一个有趣的现象:
大多数控件都如我们预期改变了字体,但用于文件浏览的listview却没有。难道在执行OnInitDialog的时候,该窗口还没有创建?由于可以明确的是所有的窗口最终都将通过CreateWindowEx进行创建,故对该API进行跟踪。
1,首先在VS中填入.SRV*c:/symbol*http://msdl.microsoft.com/download/symbols为user32.dll获得调试PDB(关于如何获得和使用符号,查看这里)
2,为OnInitDialog设置函数断点并打印在输出窗口
3,添加函数断点{,,user32.dll}_CreateWindowExW@48
4,设置该断点触发时继续执行,并将CreateWindowEx:{*(void**)(@ESP+8)}打印到输出窗口中。其中ESP+8是传入CreateWindowEx的第二个参数lpClassName
通过调试,打印结果如下:
CreateWindowEx:0x771817ec string L"ComboLBox"
CreateWindowEx:0x77181800 string L"ComboBox"
CreateWindowEx:0x771817ec string L"ComboLBox"
CreateWindowEx:0x77181824 string L"Edit"
CreateWindowEx:0x771817ec string L"ComboLBox"
CreateWindowEx:0x0000c038
CreateWindowEx:0x77182ad8 _c_szToolbarClass
MyFileDialog::OnInitDialog(void)
CreateWindowEx:0x75efa3e0 string L"Auto-Suggest Dropdow"...
CreateWindowEx:0x75f0096c string L"SysListView32"
CreateWindowEx:0x77182a58 _c_szHeaderClass
CreateWindowEx:0x77181a38 string L"tooltips_class32"
CreateWindowEx:0x75f0093c string L"ScrollBar"
CreateWindowEx:0x75f0093c string L"ScrollBar"
CreateWindowEx:0x7d5a22d0 string L"SHELLDLL_DefView"
CreateWindowEx:0x7d59aef8 string L"SysListView32"
CreateWindowEx:0x77181a38 string L"tooltips_class32"
CreateWindowEx:0x7d59fa64 string L"tooltips_class32"
CreateWindowEx:0x76991b20
CreateWindowEx:0x77182ab4 _c_szSToolTipsClass
CreateWindowEx:0x77182ab4 _c_szSToolTipsClass
结果证实了推测,作为文件浏览窗口的SHELLDLL_DefView,它的创建将在OnInitDialog执行完之后进行。尽管我们将没有办法在OnInitDialog中直接完成设置字体的工作,但代码仍然可以放置在OnInitDialog中。我们可以使用PostMessage发送自定义消息,消息的目标函数执行设置字体的工作,这样消息函数将在所有的窗体创建完毕后得以触发。关于如何处理自定义消息,这里不在详细描述。