Pergunta

EDITAR: Eu ofereci uma recompensa, já que duvido que receba respostas.

Ultimamente, tenho trabalhado com ListViews e decidi adicionar um ícone para cada item indicando se é entrada ou saída. Os ícones acrescentam bem, mas não são transparentes:

Example of icon not being transparent

Como pode ser visto, os ícones claramente não são transparentes. Atualmente, estou fazendo algo assim, os ícones:

  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)));
  }

Eu tentei mexer com as bandeiras para ImageList_Create & LoadIcon/LoadImage Mas não tive sorte e, para ser sincero, fiquei sem idéias.

Qualquer ajuda será muito apreciada.

Foi útil?

Solução

Primeiro, o ImageList_replaceicon copia os dados do ícone ao adicioná -los a uma lista de imagens. Portanto, o hicon precisa ser liberado depois.

Em seguida, os listradores imageieis são nativamente bitmaps, não ícones. E a maneira como você está criando sua lista de imagens torna a conversão do ícone em bitmap muito ambíguo. O ILC_COLOR32 implica que a lista de imagens deve ser criada como uma seção DIB de 32 bits, que normalmente contém informações de transparência por meio de um canal alfa incorporado. O ILC_MASK implica que os bitmaps internos são bitmaps DDB, com as informações de transparência armazenadas como um bitmap de máscara de 1BPP.

A solução mais rápida para o seu problema - pegue seus dois ícones:

  • Mescre -os em um único recurso de bitmap com 32 pels de largura por 16 alta. Encha o fundo com uma cor de máscara:- roxo ou algo assim.
  • Crie o bitmap usando ILC_COLOR | ILC_MASK
  • Carregue o bitmap, certificando -se de não usar lr_transparent.
  • Adicione o bitmap usando o imageList_addmasked Passando em um ColorRef que representa a cor da máscara.

Ou, para um melhor efeito visual ...

  • Export seus dados PNG como um arquivo de bitmap de 32x16 32bpp contendo dados de canal alfa pré-multiplicado.
  • Crie a lista de imagens usando o valor ILC_COLOR32.
  • LoadImage () com lr_createdibSection para carregar o bitmap como uma seção DIB de 32bpp.
  • Adicione a imagem usando imageList_add ()

(A última opção é complicada como o número de ferramentas que suportam os arquivos BMP de 32 bits com canais alfa pré -multiplicados adequadamente é bastante baixa).


Editado para adicionar o seguinte exemplo de código. Usando um bitmap de 4bpp criado no ambiente de desenvolvimento, isso funciona ótimo:-

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);

Outras dicas

Você deseja fazer com que seus ícones tenham uma cor de fundo que não seja usada em nenhum outro lugar do ícone, como um roxo realmente feio, e depois use o loadImage (..., lr_loadtransparent); A bandeira diz olhar para o primeiro pixel em 0,0 e fazer tudo o que é transparente.

Seu código parece bom para mim, eu sempre uso o LoadImage em vez do loadicon, mas suspeito que isso não importa. Você verificou se os ícones realmente têm áreas transparentes e não têm um fundo sólido?

Minhas chamadas de carregamento parecem:

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

Aqui ... Crie uma lista de imagelestos, como sugerido, transforme seus ícones em um bitmap, 16 pixels de altura, por 16*n de comprimento, onde n = o número de ícones ...

Defina a cor de fundo para 255, 0, 255, como você fez.

Em seguida, carregue -o e adicione -o à lista de imagens como eu fiz aqui:

 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);

Claro, isso foi escrito no MFC, mas como você sabe, é apenas um invólucro para o Win32 ...

Fora disso, você terá que ir a um controle personalizado, no qual desenhe o ícone sobre qualquer fundo que o ícone esteja sentado. Não há realmente nenhuma cor "transparente" mágica, que eu conheço, em qualquer um desses controles.

No caso de um sorteio personalizado, você precisa usar o código como o seguinte:

#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;

Este código decide onde desenhar o ícone e tira um instantâneo do fundo, cria uma máscara para o ícone e depois o desenha sobre o fundo, dando -lhe um fundo totalmente transparente ...

Espero que ajude um pouco. Caso contrário, explique com mais detalhes o que você está tentando fazer acontecer, e o que você está vendo, ou o que não está vendo ...

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top