MFC ListCtrl修改行高触发DrawItem断言错误,寻求解决方案
解决MFC ListCtrl使用OnMeasureItem后触发DrawItem断言错误的问题
问题根源
当你为ListCtrl设置LVS_OWNERDRAWVARIABLE样式(触发OnMeasureItem调用的前提)时,MFC要求必须重载DrawItem函数实现自绘逻辑。默认的CListCtrl::DrawItem仅包含ASSERT(FALSE),因此会触发错误。
解决步骤
1. 确认ListCtrl样式
确保你的ListCtrl是报表视图(LVS_REPORT),并且已开启LVS_OWNERDRAWVARIABLE样式:
// 在对话框OnInitDialog中添加 CListCtrl* pList = (CListCtrl*)GetDlgItem(IDC_LISTCTRL); pList->SetStyle(pList->GetStyle() | LVS_OWNERDRAWVARIABLE); // 可选:添加全选样式 pList->SetExtendedStyle(pList->GetExtendedStyle() | LVS_EX_FULLROWSELECT);
2. 重载DrawItem函数
- 在对话框类的头文件(
.h)中声明:
afx_msg void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
- 在消息映射文件(
.cpp)中添加:
BEGIN_MESSAGE_MAP(ShipInfoDlg, CDialog) // 其他消息映射 ON_WM_DRAWITEM() END_MESSAGE_MAP()
3. 实现DrawItem的自绘逻辑
以下是适配报表视图的完整实现,支持行选中状态区分、多列文本绘制:
void ShipInfoDlg::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) { if (lpDrawItemStruct->CtlID != IDC_LISTCTRL) { CDialog::DrawItem(lpDrawItemStruct); return; } CListCtrl* pList = (CListCtrl*)GetDlgItem(IDC_LISTCTRL); ASSERT_VALID(pList); CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC); RECT rcItem = lpDrawItemStruct->rcItem; // 绘制背景 if (lpDrawItemStruct->itemState & ODS_SELECTED) { pDC->FillSolidRect(&rcItem, GetSysColor(COLOR_HIGHLIGHT)); pDC->SetTextColor(GetSysColor(COLOR_HIGHLIGHTTEXT)); pDC->SetBkColor(GetSysColor(COLOR_HIGHLIGHT)); } else { pDC->FillSolidRect(&rcItem, GetSysColor(COLOR_WINDOW)); pDC->SetTextColor(GetSysColor(COLOR_WINDOWTEXT)); pDC->SetBkColor(GetSysColor(COLOR_WINDOW)); } // 绘制每列文本 int nRow = lpDrawItemStruct->itemID; int nColCount = pList->GetHeaderCtrl()->GetItemCount(); RECT rcCol; for (int nCol = 0; nCol < nColCount; ++nCol) { pList->GetColumnRect(nCol, rcCol); rcCol.top = rcItem.top; rcCol.bottom = rcItem.bottom; CString strText; pList->GetItemText(nRow, nCol, strText); // 左对齐、垂直居中绘制文本 pDC->DrawText(strText, &rcCol, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS); } // 绘制行分隔线(可选) pDC->MoveTo(rcItem.left, rcItem.bottom - 1); pDC->LineTo(rcItem.right, rcItem.bottom - 1); }
4. 更简单的替代方案(固定行高)
如果不需要可变行高,仅需统一修改所有行的高度,可直接使用SetItemHeight,无需启用自绘:
CListCtrl* pList = (CListCtrl*)GetDlgItem(IDC_LISTCTRL); LOGFONT lf; pList->GetFont()->GetLogFont(&lf); int nHeight = (lf.lfHeight < 0) ? -lf.lfHeight + 10 : lf.lfHeight + 10; pList->SetItemHeight(-1, nHeight); // -1表示设置所有行的高度
内容的提问来源于stack exchange,提问作者Hunni
相关产品推荐
相关产品推荐

