3

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

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

图标不透明的示例

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

  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_Create& LoadIcon/的标志,LoadImage但没有运气,老实说我已经没有想法了。

任何帮助将不胜感激。

4

4 回答 4

13

首先,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() 添加图像

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


编辑添加以下代码示例。使用在开发环境中创建的 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);
于 2009-03-13T08:36:11.890 回答
0

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

于 2009-03-10T23:02:54.700 回答
0

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

我的 LoadImage 调用如下所示:

HICON hIcon = (HICON)LoadImage(hinstResources,MAKEINTRESOURCE(IDI_ICON),IMAGE_ICON,16,16,LR_DEFAULTCOLOR);
于 2009-03-13T05:00:10.007 回答
0

在这里...按照建议创建一个 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;

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

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

于 2009-03-18T22:03:54.063 回答