报表模式ListView中ImageList使用PNG透明图的异常及图标间隙问题咨询
不同显示结果的根因
你碰到的不同透明区域显示效果,本质是三个核心问题共同导致的:
- ImageList创建标志缺失:仅指定
ILC_COLOR32不会让ImageList识别Alpha通道,必须额外添加ILC_ALPHA标志,否则ImageList会直接忽略32位位图的Alpha分量,仅绘制RGB部分。 - GDI+ GetHBITMAP的行为逻辑:
Bitmap::GetHBITMAP方法的第一个参数为透明区域填充色,当传入的颜色Alpha值为255(不透明)时,会直接将PNG的透明区域替换为该填充色,同时生成的HBITMAP所有像素的Alpha分量会被强制设为255。你代码中传入的Color(255,1,1)对应的是R=255、G=1、B=1的亮红色,所以生成的位图透明区域原生RGB就是红色。 - Alpha通道修改的影响:
- 第一段代码未修改Alpha通道,ImageList忽略Alpha直接绘制,如果你没开ILC_ALPHA,此时如果系统主题对ListView图标有默认白色背景填充,就会显示白色。
- 第三段代码手动将所有像素的Alpha分量设为0,ImageList如果没开ILC_ALPHA,就直接显示RGB部分的红色,所以透明区域显示红色。
- 第四段代码先调用
CalculateAlphaChannel(该函数通常会做预乘Alpha处理,将RGB值乘以Alpha比例),再把Alpha设为0,此时对应像素的RGB值也会被清零,所以显示黑色。
消除图标间隙并正确显示透明度的解决方法
图标之间的间隙未填充背景色,是因为你的自定义绘制逻辑仅处理了单个Item的绘制阶段,间隙区域不属于任何Item的绘制范围,不会被你的背景刷填充,按以下步骤修改即可:
- 修正ImageList创建参数,必须添加
ILC_ALPHA标志:
// cx、cy为图标尺寸,nInitial为初始图标数量,nGrow为扩容步长 HIMAGELIST himl = ImageList_Create(cx, cy, ILC_COLOR32 | ILC_ALPHA, nInitial, nGrow);
- 正确加载带Alpha的PNG,不要用GetHBITMAP填充不透明背景,直接保留原生Alpha通道:
Bitmap* bitmap = Bitmap::FromFile(pfilepath, false); HBITMAP hbmp; // 传入全透明色作为背景,避免覆盖PNG原生透明区域 bitmap->GetHBITMAP(Color(0, 0, 0, 0), &hbmp); delete bitmap; // GDI+生成的32位位图默认是预乘Alpha格式,符合ImageList要求,无需额外处理Alpha通道 ImageList_Add(himl, hbmp, NULL); DeleteObject(hbmp);
- 修改自定义绘制逻辑,在
CDDS_PREPAINT阶段先填充整个ListView客户区,覆盖间隙区域:
INT_PTR CGUIObjControl::ProcessCustomDraw(LPARAM lparam) { LPNMLVCUSTOMDRAW plvcd = (LPNMLVCUSTOMDRAW)lparam; switch (plvcd->nmcd.dwDrawStage) { case CDDS_PREPAINT: { if (GetBrush()) { // 先填充整个客户区,覆盖图标间隙和空白区域 RECT rcClient; GetClientRect(plvcd->nmcd.hdr.hwndFrom, &rcClient); FillRect(plvcd->nmcd.hdc, &rcClient, GetBrush()); } if (HasTextColor() || GetBrush()) { return CDRF_NOTIFYITEMDRAW; } break; } case CDDS_ITEMPREPAINT: { if (HasTextColor()) { plvcd->clrText = TextColor(); } plvcd->clrTextBk = BackgroundColor(); return CDRF_NEWFONT; } } return CDRF_DODEFAULT; }
内容的提问来源于stack exchange,提问作者user3161924
相关产品推荐
相关产品推荐

