Прозрачность ImageList в списках просмотра? - PullRequest
3 голосов
/ 11 марта 2009

РЕДАКТИРОВАТЬ: Я предложил вознаграждение, так как я сомневаюсь, что я получу какие-либо ответы в противном случае.

В последнее время я работаю со списками и решил добавить значок для каждого элемента, указывающего, является ли он входным или выходным. Значки добавляются нормально, но они не прозрачные:

Example of icon not being transparent

Как видно, значки явно не прозрачные. В настоящее время я делаю что-то вроде этого загрузить значки:

  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 ]

12 голосов
/ 13 марта 2009

Сначала ImageList_ReplaceIcon копирует данные значка при добавлении его в список изображений. Таким образом, HICON должен быть освобожден впоследствии.

Далее, списки изображений изначально являются растровыми изображениями, а не значками. А способ создания списка изображений делает преобразование значка в растровое изображение очень неоднозначным. ILC_COLOR32 подразумевает, что список изображений должен быть создан как 32-битная секция dib, которая обычно содержит информацию о прозрачности через встроенный альфа-канал. Вместо этого ILC_MASK подразумевает, что внутренние растровые изображения являются растровыми изображениями DDB, а информация о прозрачности хранится как растровое изображение маски 1 бит на пиксель.

Самое быстрое решение вашей проблемы - возьмите две иконки:

  • Объедините их в один растровый ресурс шириной 32 пикселя и высотой 16 пикселей. Залейте фон маской цвета: - фиолетовый или что-то в этом роде.
  • Создание растрового изображения с помощью ILC_COLOR | ILC_MASK
  • Загрузите растровое изображение, убедившись, что НЕ используется LR_TRANSPARENT.
  • Добавьте растровое изображение, используя ImageList_AddMasked, передавая в COLORREF, который представляет цвет маски.

ИЛИ, для лучшего визуального эффекта ...

  • экспорт данных PNG в виде файла растрового изображения 32x16 32bpp, содержащего предварительно умноженные данные альфа-канала.
  • Создайте список изображений, используя значение ILC_COLOR32.
  • LoadImage () с LR_CREATEDIBSECTION для загрузки растрового изображения в виде секции dib 32bpp.
  • Добавьте изображение с помощью ImageList_Add ()

(последний вариант довольно сложен, так как количество инструментов, поддерживающих запись 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);
0 голосов
/ 19 марта 2009

Здесь ... Создайте 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;

Этот код решает, где нарисовать значок, и делает снимок фона, создает маску для значка, а затем рисует его на фоне, давая ему полностью прозрачный фон ...

Надеюсь, это немного поможет. Если нет, пожалуйста, объясните более подробно, что вы пытаетесь сделать, и что вы видите, или что вы НЕ видите ...

0 голосов
/ 13 марта 2009

Ваш код выглядит нормально для меня, я всегда использую LoadImage вместо LoadIcon, но я подозреваю, что это не имеет значения. Вы проверили, что значки действительно имеют прозрачные области и не имеют сплошного фона?

Мои вызовы LoadImage выглядят так:

HICON hIcon = (HICON)LoadImage(hinstResources,MAKEINTRESOURCE(IDI_ICON),IMAGE_ICON,16,16,LR_DEFAULTCOLOR);
0 голосов
/ 11 марта 2009

Вы хотите, чтобы у ваших значков был цвет фона, который больше нигде не использовался в значке, например очень уродливый фиолетовый, а затем используйте LoadImage (..., LR_LOADTRANSPARENT); Флаг говорит: посмотрите на первый пиксель в 0,0 и сделайте все, что цвета прозрачными.

...