如何获取Windows默认对话框字体并将CListCtrl的CHeaderCtrl设为粗体?
问题:设置CListCtrl表头为系统默认粗体字体时触发断言错误
需求
希望将CListCtrl的CHeaderCtrl(表头)设置为粗体显示,不自定义字体,而是使用当前电脑的系统默认字体,仅将默认字体改为粗体,询问是否可行。
当前错误
运行代码时触发Microsoft Visual C++运行时库断言错误:
Microsoft Visual C++ Runtime Library
Debug Assertion Failed!
Program: C:\Windows\SYSTEM32\mfc140ud.dll
File: D:\a_work\1\s\src\vctools\VC7Libs\Ship\ATLMFC\Src\MFC\wingdi.cpp
Line: 1113
错误发生在代码行:m_headerFont.CreateFontIndirect(&lf);
断点时LOGFONT参数值
lfHeight: -12 lfWidth: 0 lfEscapement: 0 lfOrientation: 0 lfWeight: 700 lfItalic: 0 '\0' lfUnderline: 0 '\0' lfStrikeOut: 0 '\0' lfCharSet: 1 '\x1' lfOutPrecision: 0 '\0' lfClipPrecision: 0 '\0' lfQuality: 0 '\0' lfPitchAndFamily: 0 '\0' lfFaceName: 0x00000004b38fc8cc L"Segoe UI"
示例代码
class CMFCtestDlg : public CDialogEx { CFont m_headerFont; //.... //... BOOL OnInitDialog(); } BOOL CMFCtestDlg::OnInitDialog() { //....... //....... CFont *pDefaultFont = pHeaderCtrl->GetFont(); LOGFONT lf{0}; if(pDefaultFont != nullptr && pDefaultFont->GetLogFont(&lf)) { // 如果字体是MS Shell Dlg,使用SystemParametersInfo获取系统字体 if(_tcscmp(lf.lfFaceName, _T("MS Shell Dlg")) == 0) { if(SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &lf, 0)) { lf.lfWeight = FW_BOLD; m_headerFont.CreateFontIndirect(&lf); pHeaderCtrl->SetFont(&m_headerFont); } } } }
解决方案
你的需求完全可行——基于系统默认字体生成粗体版本是合理的实现方式。断言错误的核心原因是LOGFONT结构体的lfPitchAndFamily字段未正确设置,MFC在创建字体时会校验该参数的合法性。
修复步骤:
- 保留原字体的PitchAndFamily属性:从默认字体获取LOGFONT时,不要覆盖
lfPitchAndFamily,或者在修改后确保该字段不为0。你的代码中当前lfPitchAndFamily是0,这不符合字体创建的要求。 - 移除不必要的特殊字体判断:
MS Shell Dlg是系统占位字体,直接使用GetLogFont获取的参数即可,无需额外调用SystemParametersInfo获取图标标题字体(这会覆盖原有的PitchAndFamily等关键参数)。
修正后的代码:
BOOL CMFCtestDlg::OnInitDialog() { // 原有初始化代码... CHeaderCtrl* pHeaderCtrl = m_listCtrl.GetHeaderCtrl(); if (pHeaderCtrl == nullptr) return CDialogEx::OnInitDialog(); CFont* pDefaultFont = pHeaderCtrl->GetFont(); LOGFONT lf{}; if (pDefaultFont != nullptr && pDefaultFont->GetLogFont(&lf)) { // 仅修改字体粗细为粗体,保留其他所有系统默认参数 lf.lfWeight = FW_BOLD; // 确保PitchAndFamily字段有效(如果原获取的值为0,可手动设置为DEFAULT_PITCH | FF_DONTCARE) if (lf.lfPitchAndFamily == 0) { lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; } if (m_headerFont.CreateFontIndirect(&lf)) { pHeaderCtrl->SetFont(&m_headerFont); } } return CDialogEx::OnInitDialog(); }
关键说明:
lfPitchAndFamily字段需要指定字体的间距和族类,不能为0。从系统字体获取的LOGFONT通常会自带有效值,但若因特殊情况为0,手动设置DEFAULT_PITCH | FF_DONTCARE即可兼容所有系统。- 无需针对
MS Shell Dlg做特殊处理,因为GetLogFont会自动解析该占位字体为实际使用的系统字体(比如你的环境中是Segoe UI)。 - 确保
m_headerFont是类成员变量(而非局部变量),否则字体对象会在函数结束后销毁,导致表头显示异常。
内容的提问来源于stack exchange,提问作者Michal Hadraba
相关产品推荐
相关产品推荐

