Win32 Невозможно добавить пользовательский значок панели инструментов, имеющий прозрачность - PullRequest
0 голосов
/ 07 ноября 2019

Я использую этот код для добавления панели инструментов в окно с одной кнопкой, имеющей пользовательское изображение:

HWND hToolbar = CreateWindow(TOOLBARCLASSNAME, NULL,WS_CHILD | 
         TBSTYLE_FLAT|TBSTYLE_AUTOSIZE |TBSTYLE_LIST|CCS_BOTTOM, 0, 0, 0, 0,
         hwnd, NULL, ghInstance, NULL); //create the toolbar

SendMessage(hToolbar, WM_SETFONT, (WPARAM)hFontBold, 
      static_cast<LPARAM>(MAKELONG(TRUE, 0))); //set the font. there cannot be the problem

//↓↓↓↓↓**ILC_COLOR32 is specificied here but 32bit bmp is still not showing**//
auto hImagelist = ImageList_Create(32, 32,ILC_COLOR32|ILC_MASK,1, 0);
//↑↑↑↑↑**ILC_COLOR32 is specificied here but 32bit bmp is still not showing**//

HBITMAP bitmap = static_cast<HBITMAP>(ghInstance,
          MAKEINTRESOURCE(ID_IMG_SPAWN),// <- ID_IMG_SPAWN is my custom resource
          IMAGE_BITMAP, 32, 32, NULL));

ImageList_Add(hImagelist, bitmap, nullptr);
SendMessage(hToolbar, TB_SETIMAGELIST,static_cast<WPARAM>(0),(LPARAM)hImagelist);

В приведенном выше коде ID_IMG_SPAWN - это изображение bmp ресурса, которое я импортировал в Visual Studio,Тем не менее, Visual Studio выдавал ошибку, говоря, что он не распознал мой bmp, и bmp показывался пустым при запуске приложения.


Visual Studio сказал мне, что мой bmp не был распознан, см. Нижеошибка:

VS error message


При запуске приложения оно выглядит следующим образом:


Я узнал, что Visual Studio распознает ТОЛЬКО 24-битные BMP.

Итак, я преобразовал BMP в 24-битную и импортировал ее снова, изменил ILC_COLOR32 на ILC_COLOR24, что действительноработал. Нет ошибки, и мое изображение было показано на кнопке.

Однако я потерял свой альфа-канал. Поскольку 24-битное растровое изображение не поддерживает альфа-канал, мое изображение получило некрасивый квадратный фон.

Ответы [ 3 ]

2 голосов
/ 07 ноября 2019

Попробуйте что-то вроде этого (обратите внимание, что я использовал "BINARY" ресурс .. возможно, он будет работать и с другими, но не уверен .. Этот код работает с 32-битными растровыми изображениями, альфа-прозрачными PNG и JPEG):

#include <windows.h>
#include <gdiplus.h>

HBITMAP LoadBitmapFromResource(DWORD ResourceID, bool transparent = true)
{
    HANDLE hGlobal = NULL;
    ULONG_PTR GDIToken = 0;
    Gdiplus::Image* Img = NULL;
    Gdiplus::GdiplusStartupInput GDIStartInput = NULL;


    Gdiplus::GdiplusStartup(&GDIToken, &GDIStartInput, NULL);

    HRSRC hResource = FindResource(NULL, MAKEINTRESOURCE(ResourceID), "BINARY");
    if (!hResource) {return NULL;}

    HGLOBAL hFileResource = LoadResource(NULL, hResource);
    if (!hFileResource) {return NULL;}

    LPVOID lpFile = LockResource(hFileResource);
    if (!lpFile) {return NULL;}

    DWORD dwSize = SizeofResource(NULL, hResource);
    if (!dwSize) {return NULL;}

    void* data = LockResource(hFileResource);
    if (!data) {return NULL;}

    IStream* pStream = NULL;
    hGlobal = GlobalAlloc(GMEM_FIXED, dwSize);

    memcpy(hGlobal, data, dwSize);
    UnlockResource(hFileResource);
    FreeResource(hFileResource);

    if (CreateStreamOnHGlobal(hGlobal, true, &pStream) == S_OK)
    {
        Img = new Gdiplus::Image(pStream, false);
        pStream->Release();
        GlobalFree(hGlobal);
        hGlobal = NULL;

        HBITMAP hBitmap = NULL;
        static_cast<Gdiplus::Bitmap*>(Img)->GetHBITMAP(transparent ? Gdiplus::Color::Transparent : Gdiplus::Color(0, 0, 0), &hBitmap);

        delete Img;
        Gdiplus::GdiplusShutdown(GdiImage::GDIToken);
        GDIStartInput = NULL;
        GDIToken = 0;

        return hBitmap;
    }

    GlobalFree(hGlobal);
    hGlobal = NULL;
    Gdiplus::GdiplusShutdown(GdiImage::GDIToken);
    GDIStartInput = NULL;
    GDIToken = 0;

    return NULL;
}

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

Есть другие способы без GDIPlus, ноэто делает для длинного поста ..

0 голосов
/ 09 ноября 2019

Я узнал, что Visual Studio распознает ТОЛЬКО 24 бит / с.

Нет, это неправильно. Visual Studio поддерживает 32-битные битовые карты с предварительным умножением .

32-битное растровое изображение имеет 8 бит для ALPHA, оно способно создавать плавный эффект.


Чтобы правильно отобразить 32-разрядное растровое изображение, необходимо:

  • указать ILC_COLOR32

  • изменить ресурс ID_IMG_SPAWN на32-битное растровое изображение с предварительно умноженным альфа .

  • создать раздел DIB для вашего растрового изображения при загрузке

(требование формата Win32 очень строго)


В: Как создать раздел DIB для растрового изображения?

A: Укажите LR_CREATEDIBSECTION в последнем параметре LoadImage.

Объяснение:

LoadImage((HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE),MAKEINTRESOURCE(ID_IMG_SPAWN), IMAGE_BITMAP,32, 32,NULL)

Это ваш код функции LoadImage. См. MSDN документ LoadImage , чтобы создать раздел DIB, все, что вам нужно, это указать LR_CREATEDIBSECTION в последнем параметре LoadImage.


Q: Какполучить BMP с предварительно умноженным альфа?

A: Pixelformer может помочь вам преобразовать ваш альфа-канал в файл BMP с предварительно умноженным альфа.

Шаги

  1. Откройте свое изображение (любой формат) в Pixelformer и выберите «Экспорт» из меню

Выберите A8: R8: G8: B8 (32 бит / с) и Предварительно умноженное альфа , затем нажмите Ok.

Тогда вы можете сохранить файл BMP! Импортируйте этот файл BMP в ресурсы Visual Studio, заменив предыдущий 24-битный BMP.


Тогда вам больше не нужно использовать ImageList_AddMasked (что делает изображение четким), потому что выуже есть узнаваемая альфа в вашем 32-битном BMP. Итак, прямое использование ImageList_Add.

Хорошо, после манипуляций, описанных выше, ваш код должен быть таким:

// Create the toolbar
HWND hToolbar = CreateWindow(TOOLBARCLASSNAME,NULL,
     WS_CHILD | TBSTYLE_FLAT | TBSTYLE_AUTOSIZE | TBSTYLE_LIST | CCS_BOTTOM,
     0, 0, 0, 0, hwnd, NULL, ghInstance, NULL);

// Set the font (this cannot be the problem)
SendMessage(hToolbar, WM_SETFONT, (WPARAM)hFontBold,
     static_cast<LPARAM>(MAKELONG(TRUE, 0)));

auto hImagelist =
ImageList_Create(32, 32,ILC_COLOR32 /*DON'T NEED THE MASK. CHANGED TO ILC_COLOR32.*/, 1, 0);

HBITMAP bitmap = static_cast<HBITMAP>(LoadImage((HINSTANCE)GetWindowLong(hwnd,
      GWL_HINSTANCE), MAKEINTRESOURCE(ID_IMG_SPAWN), IMAGE_BITMAP,
      32, 32, LR_CREATEDIBSECTION  /*THIS IS IMPORTANT*/   ));

ImageList_Add(hImagelist, bitmap, NULL);
SendMessage(hToolbar, TB_SETIMAGELIST, static_cast<WPARAM>(0), (LPARAM)hImagelist);

Это работало нормально, как показано ниже.


На эти вопросы, на которые я ответил выше, вполне достаточно, чтобы решить эту проблему. Вы можете задаться вопросом "Что означает растровые изображения DIB?"«Что такое Преумноженная Альфа?». Это глубокие темы.

Чтобы узнать битовые карты DIB и Предварительно умноженная альфа , см. Ссылки.

0 голосов
/ 07 ноября 2019

Если вы используете Visual Studio 2010 или выше (я думаю), вы можете использовать PNG-файлы. Как указано здесь .

...