【发布时间】:2020-07-17 14:21:02
【问题描述】:
我正在尝试以某种方式实现单列 CListCtrl(或 CMFCListCtrl,没关系),有些行可能有复选框,有些可能没有(我不想同时使用 CListBox ,也不是 CCheckListBox,因为将来我打算使用多个列)。我正在使用LVS_EX_CHECKBOXES 样式,但这会强制每个项目都有一个复选框。然后我使用自定义绘制处理程序手动删除复选框,但是我无法将项目的文本移动到左侧,以便它取代已删除的复选框。
这是我的列表控件的样子:
但我需要它看起来像这样(item2 与左边框对齐,代替已擦除的复选框):
我像这样动态创建列表控件:
list->Create(WS_CHILD | WS_VISIBLE | WS_BORDER | LVS_REPORT | LVS_NOCOLUMNHEADER
rect, this, SOME_ID);
list->SetExtendedStyle(list->GetExtendedStyle() | LVS_EX_CHECKBOXES);
我的自定义绘图处理函数如下所示:
我像这样动态创建列表控件:
void MyCListCtrl::OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult)
{
*pResult = CDRF_DODEFAULT;
LPNMLVCUSTOMDRAW lpn = (LPNMLVCUSTOMDRAW)pNMHDR;
if (CDDS_PREPAINT == lpn->nmcd.dwDrawStage)
{
*pResult = CDRF_NOTIFYITEMDRAW; // get notification for every row (item)
}
else if (CDDS_ITEMPREPAINT == lpn->nmcd.dwDrawStage)
{
int row = lpn->nmcd.dwItemSpec;
if (row == 1) { // we are in the first row (item2)
lpn->nmcd.rc.left -= 20; // doesn't do anything
lpn->rcText.left -= 20; // doesn't do anything
// this erases checkbox from the current row
SetItemState(row, INDEXTOSTATEIMAGEMASK(0), LVIS_STATEIMAGEMASK);
}
}
}
有什么方法可以达到预期的效果吗?我是以正确的方式做的,还是在没有LVS_EX_CHECKBOXES 的情况下使用 CListCtrl 并自己在我想要的地方绘制复选框更好?如果是这样,怎么做?提前致谢。
【问题讨论】:
-
列表视图不包含复选框。它使用图像来模拟它们。
SetItemState调用不会“删除 [the] checkbox”,而是应用图像列表中索引 0 处的图像。这是一个完全透明的图像,与复选框图像的大小相同。 -
感谢指正。此图像列表中是否有任何图像,其大小为“0”,以便文本立即向左移动?或者我可以使用大小为 0 的“复选框”图像和“空”图像创建自己的
CImageList,如果可以,我在哪里可以找到这些图像?这行得通吗?我对 MFC 编程很陌生,很抱歉出现这样的问题。 -
A ListView 在使用其标准 复选框/图像功能时不支持您要查找的内容。所以禁用它,然后在需要的地方手动绘制你自己的复选框。这意味着您还必须处理鼠标事件来“切换”您的绘图
-
@RemyLebeau 谢谢。我可以以某种方式使用 CListCtrl 使用的相同图像吗?我的库中无法存储任何资源(如图像等)。
-
您可以使用DrawFrameControl 或DrawThemeBackground(如果您想匹配较新的视觉样式)来绘制您的控件位图。
标签: c++ winapi mfc win32gui clistctrl