【问题标题】:ImageList Transparency on Listviews?Listviews上的ImageList透明度?
【发布时间】:2010-10-12 13:39:40
【问题描述】:

编辑:我提供了赏金,因为我怀疑否则我会得到任何答案。

最近我一直在使用列表视图,我决定为每个项目添加一个图标,指示它是输入还是输出。图标添加得很好,但它们不透明:

可以看出,图标显然不是透明的。我目前正在做这样的事情加载图标:

  hImageList = ImageList_Create(16, 16, ILC_MASK | ILC_COLOR32, 2, 2);
  if (hImageList != NULL)
  {
    iIN  = ImageList_AddIcon(hImageList, LoadIcon(hInstance, MAKEINTRESOURCE(101)));
    iOUT = ImageList_AddIcon(hImageList, LoadIcon(hInstance, MAKEINTRESOURCE(102)));
  }

我试过弄乱ImageList_CreateLoadIcon/LoadImage 的标志,但没有运气,老实说我已经没有想法了。

任何帮助将不胜感激。

【问题讨论】:

  • 你有你的资源可供我们处理吗?我看到一些人们正在测试你的代码的 cmets。我很想看看它,因为我在这方面做了很多工作......
  • 请查看我对stackoverflow.com/questions/6893351/… 线程的回答(答案2)。奥利克西

标签: windows winapi transparency


【解决方案1】:

首先,ImageList_ReplaceIcon 在将图标数据添加到图像列表时复制它。所以 HICON 需要在之后发布。

接下来,图像列表本身就是位图,而不是图标。而且您创建图像列表的方式使图标到位图的转换非常模糊。 ILC_COLOR32 意味着图像列表应创建为 32 位 dib 部分,通常包含通过嵌入的 alpha 通道的透明度信息。 ILC_MASK 表示内部位图是 DDB 位图,透明度信息存储为 1bpp 掩码位图。

解决问题的最快方法 - 带上你的两个图标:

  • 将它们合并为一个 32 像素宽 x 16 高像素的位图资源。用蒙版颜色填充背景:- 紫色或其他颜色。
  • 使用 ILC_COLOR|ILC_MASK 创建位图
  • 加载位图确保不使用 LR_TRANSPARENT。
  • 使用 ImageList_AddMasked 添加位图,传入一个表示遮罩颜色的 COLORREF。

或者,为了更好的视觉效果...

  • 将您的 PNG 数据导出为 32x16 32bpp 位图文件,其中包含预乘的 Alpha 通道数据。
  • 使用 ILC_COLOR32 值创建图像列表。
  • 带有 LR_CREATEDIBSECTION 的 LoadImage() 将位图加载为 32bpp dib 部分。
  • 使用 ImageList_Add() 添加图像

(最后一个选项有点棘手,因为支持写出 32 位 bmp 文件并带有适当预乘 alpha 通道的工具数量相当少)。


编辑添加以下代码示例。使用在开发环境中创建的 4bpp 位图效果很好:-

HWND hwndCtl = CreateWindowEx(0,WC_LISTVIEW,TEXT("ListView1"),WS_CHILD|WS_VISIBLE|WS_HSCROLL|WS_VSCROLL,0,0,cx,cy,hWnd,(HMENU)101,hModule,NULL);
HBITMAP hbm = (HBITMAP)LoadImage(hModule,MAKEINTRESOURCE(IDB_BITMAP1),IMAGE_BITMAP,0,0,0);
COLORREF crMask=RGB(255,0,255);
HIMAGELIST himl = ImageList_Create(16,16,ILC_COLOR|ILC_MASK,2,0);
ImageList_AddMasked(himl,hbm,crMask);
ListView_SetImageList(hwndCtl,himl,LVSIL_NORMAL);

【讨论】:

  • 我今天早些时候尝试了第一个选项,但我遇到了同样的问题。看完你的帖子后,我尝试了第二种方法,它完全没有区别。请看这个:pastebin.com/f5617ac8a
  • 当您提供 ILC_MASK|ILC_COLOR 时,您如何加载位图?您可能应该忽略 DIBSECTION 标志,并且还要注意将位图加载到 DDB 表面是有损的,因此描述文件中理想 RGB 值的 COLORREF 无法匹配 DDB 中的像素。使用纯色。
  • ...您完全忽略了对第二个选项发表任何评论。此外,我确实省略了第一个选项的 LR_CREATEDIBSECTION 标志。我的蒙版颜色是粉红色 (RGB(255, 0, 255)),所以不会有任何匹配。
  • 很遗憾,我无法在工作时下载您的 bmp 文件,并且有一个 websense 过滤器。也就是说,首先制作一个简单的 16 色位图。我无法评论第二个选项不起作用,因为它要复杂得多,而且它可能失败的地方不太明显。
  • 您的 32bpp argb 位图有紫色背景。如您的屏幕截图所示,背景显示为白色。这意味着,在掩码和 32bpp 的情况下,imagelist 项是正确的 - 对白色 bk。问题是 - 交替的灰色填充是如何完成的?
【解决方案2】:

您想让您的图标具有图标中其他任何地方都不使用的背景颜色,例如非常难看的紫色,然后使用 LoadImage(..., LR_LOADTRANSPARENT);标志说看 0,0 处的第一个像素并使所有颜色透明。

【讨论】:

  • 我已经尝试过了(第一个像素为 RGB(255, 0, 255))并引用了文档:LR_LOADTRANSPARENT 不会透明地加载图像。它创建了一个不透明的图像列表,该列表仅显示为透明,因为所有背景像素都已更改为 COLOR_WINDOW。
  • 啊,是的,这是有道理的。愚蠢的窗口和透明的图标。
【解决方案3】:

您的代码对我来说看起来不错,我总是使用 LoadImage 而不是 LoadIcon,但我怀疑这并不重要。您是否检查过图标确实有透明区域并且本身没有纯色背景?

我的 LoadImage 调用如下所示:

HICON hIcon = (HICON)LoadImage(hinstResources,MAKEINTRESOURCE(IDI_ICON),IMAGE_ICON,16,16,LR_DEFAULTCOLOR);

【讨论】:

【解决方案4】:

这里...按照建议创建一个 ImageList,将您的图标制作成一个位图,16 像素高,16*n 长,其中 n= 图标的数量...

将背景颜色设置为 255、0、255,就像您所做的那样。

然后,加载它,并将其添加到图像列表中,就像我在这里所做的那样:

 m_ImageList.Create(16, 16, ILC_COLOR16 | ILC_MASK, 7, 1);
 CBitmap bm;
 bm.LoadBitmap(IDB_SUPERTREEICONS);
 m_ImageList.Add(&bm, RGB(255, 0, 255));
 GetTreeCtrl().SetImageList(&m_ImageList, TVSIL_NORMAL);

当然,这是用 MFC 编写的,但如您所知,它只是 Win32 的包装器...

除此之外,您还必须使用自定义绘制控件,在该控件中,您可以在图标恰好位于的任何背景上绘制图标。据我所知,在这些控件中实际上没有任何神奇的“透明”颜色。

在自定义绘制的情况下,需要使用如下代码:

#define TRANSPARENT_COLOR (255,0,255)

UINT iBitmap = IDB_ICON_UP
CDC *dc = GetDC();
int x = 0, y = 0;

    CDC *pDisplayMemDC = new CDC;
    CDC *pMaskDC = new CDC;
    CDC *pMemDC = new CDC;
    CBitmap *pBitmap = new CBitmap;
    CBitmap *pMaskBitmap = new CBitmap;
    CBitmap *pMemBitmap = new CBitmap;
    int cxLogo, cyLogo;
    BITMAP bm;

    pBitmap->LoadBitmap(iBitmap);
    pDisplayMemDC->CreateCompatibleDC(dc);
    CBitmap *pOldBitmap = (CBitmap *)pDisplayMemDC->SelectObject(pBitmap);

    pBitmap->GetObject(sizeof(bm), &bm);
    cxLogo = bm.bmWidth;
    cyLogo = bm.bmHeight;

    pMaskBitmap->CreateBitmap(cxLogo, cyLogo, 1, 1, NULL);
    pMaskDC->CreateCompatibleDC(dc);
    CBitmap *pOldMask = (CBitmap *)pMaskDC->SelectObject(pMaskBitmap);
    COLORREF oldBkColor = pDisplayMemDC->SetBkColor(TRANSPARENT_COLOR);
    pMaskDC->BitBlt(0, 0, cxLogo, cyLogo, pDisplayMemDC, 0, 0, SRCCOPY);

    pMemBitmap->CreateCompatibleBitmap(dc, cxLogo, cyLogo);
    pMemDC->CreateCompatibleDC(dc);
    CBitmap *pOldMem = (CBitmap *)pMemDC->SelectObject(pMemBitmap);

    pMemDC->BitBlt(0, 0, cxLogo, cyLogo, dc,            x, y, SRCCOPY);
    pMemDC->BitBlt(0, 0, cxLogo, cyLogo, pDisplayMemDC, 0, 0, SRCINVERT);
    pMemDC->BitBlt(0, 0, cxLogo, cyLogo, pMaskDC,       0, 0, SRCAND);
    pMemDC->BitBlt(0, 0, cxLogo, cyLogo, pDisplayMemDC, 0, 0, SRCINVERT);
        dc->BitBlt(x, y, cxLogo, cyLogo, pMemDC,        0, 0, SRCCOPY);

    delete pMemDC->SelectObject(pOldMem);
    delete pMemDC;

    delete pMaskDC->SelectObject(pOldMask);
    delete pMaskDC;

    delete pDisplayMemDC->SelectObject(pOldBitmap);
    delete pDisplayMemDC;

此代码决定在哪里绘制图标,并拍摄背景快照,为图标创建蒙版,然后将其绘制在背景上,使其成为完全透明的背景...

希望能有所帮助。如果没有,请更详细地解释您想要实现的目标,以及您看到的或没有看到的...

【讨论】:

    猜你喜欢
    • 2010-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-20
    • 2018-12-29
    • 1970-01-01
    • 2016-09-01
    • 2015-12-17
    相关资源
    最近更新 更多