Написанный ниже текст предназначен только для Windows XP (и ее продолжений)
Строго говоря, в этой статье описываются приемы работы с обновленным элементом библиотеки common controls 6.0 ImageList для обеспечения XP-интерфейса с использованием 32-битных битмапов.
Q: Что такое 32-битные картинки?
A: Для обеспечения нового интерфейса, в Windows XP были введены 32-битные изображения. По структуре они аналогичны битмапам типа TrueColor с 24-битным цветом. Однако, в них "базовая тройка" цветов каждой четырехбайтовой структуры RGBr (R - красный, G - зеленый, B - синий, r - резервный байт), описывающей точку в 24-х битных битмапах, заменена "базовой четверкой" RGBA, где резервный байт заменен действующим байтом, обозначающим т.н. "альфа-канал", т.е. этот байт обозначает прозрачность выбранной точки. При этом, значение 0x00 означает полностью прозрачную точку, а 0xFF - полностью непрозрачную точку.
Для обеспечения этой самой прозрачности в элемент ImageList библиотеки common controls Windows были внесены изменения. Однако эти самые изменения были внесены только в последнюю, шестую версию этой библиотеки. Для ее подключения к программе в Windows XP используется манифест.
- Как же использовать все эти нововведения в своей программе, - спросите вы.
Для начала нужно создать этот самый имаджлист.
Создание имаджлиста
При использовании Windows API нужно использовать функцию ImageList_Create
ImageList_Create(x, y, Константа_ILC_*, 0, 0); при использовании MFC это же самое создание будет выглядеть так:
CImageList m_ImageList; m_ImageList.Create(x, y, Константа_ILC_*, 0, 0); В данных примерах используется странный параметр - "Константа ILC_*" он означает, что здесь, в зависимости от нужд программы (и программиста) используются разные значения. А нужд у нас с вами может быть (аж!) целых два варианта.
Вариант 1. Мы используем в качестве изображения 32-х битную иконку.
В этом случае все просто - можно смело ставить в качестве параметов "ILC_COLOR32 | ILC_MASK", т.к. иконки всегда используют для отрисовки изображения маску.
Т.е. в этом случае можно написать (для иконок формата 16x16):
ImageList_Create(16, 16, ILC_COLOR32 | ILC_MASK, 0, 0); Вариант 2. Мы используем в качестве изображения 32-х битный битмап.
Этот случай немного сложнее. Однако, этого достаточно, чтобы его использовал в своих программах только Microsoft. На момент написания статьи (август 2002 года) я не видел ни одной программы, использующей 32-битные битмапы. Везде, изображения используются только в виде иконок.
Небольшое отступление. Обычно, битмапы при использовании в качестве изображений с использованием в качестве маски какого-либо цвета, которым закрашивается фон картинки. Обычно используется цвет Magenta - RGB(255, 0, 255), хотя можно использовать и любой другой.
В случае использования 32-х битных битмапов, маска абсолютно не нужна. Однако, вследствие того, что существуют режимы экрана, отличные от TrueColor, придется использовать два вида битмапов: с использованием цветовой маски и без нее. Поэтому, необходимо ввести функцию, проверяющую количество цветов экрана и, заодно, версию операционной системы. Вот они:
BOOL IsWinXP() { // Проверка операционной системы DWORD dwVersion = GetVersion();
// Get major and minor version numbers of Windows DWORD dwWindowsMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion))); DWORD dwWindowsMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion)));
// Check for Windows XP if ((dwVersion < 0x80000000) && // The OS is a NT family (dwWindowsMajorVersion >= 5) && (dwWindowsMinorVersion >= 1)) // Windows NT 5.1 is an Windows XP version return TRUE;
return FALSE; }
int ScreenBPP() { // Возвращает количество битов на точку в данном режиме int iRet; HDC hdc = GetDC(NULL); if (hdc != NULL) { iRet = GetDeviceCaps(hdc, BITSPIXEL); ReleaseDC(NULL, hdc); } return iRet; } И, наконец третья функция, объединяющая первые две:
BOOL Set32BPP() { return (IsWinXP() & (ScreenBPP() >= 32)); } Соответственно, если мы работаем в режиме TrueColor и в Windows XP мы используем 32-х битный битмап, а если нет - то, скажем, 256-цветный аналог.
Таким образом, создание имаджлиста выливается в следующий код:
ImageList_Create(16, 16, (Set32BPP())? 0 : ILC_MASK) | ILC_COLOR32, 0, 0); Добавление изображения в созданный имаджлист.
Теперь, после того, как мы создали имаджлист с нужными параметрами, надо добавить в него эти самые изображения. Продолжим разбиение на два варианта (какие это варианты, см. выше)
Вариант 1: Вот здесь-то и проявляется неудобство этого варианта для использования иконок в качестве, скажем, изображений для панели инструментов (toolbar), содержащей порой до нескольких десятков кнопок: каждую иконку надо загружать в имаджлист отдельной командой!
Приведу пример для загрузки трех иконок. В нем использована MFC. Для использования этого кода в чистом API надо заменить "m_ImageList.Add" на "ImageList_AddIcon":
HICON m_hImage; int n_Index;
// Добавляем иконки в имаджлист m_hImage = LoadIcon(NULL, IDI_ICON1); n_Index = m_ImageList.Add(m_hImage); // Иконка №0
m_hImage = LoadIcon(NULL, IDI_ICON2); n_Index = m_ImageList.Add(m_hImage); // Иконка №1
m_hImage = LoadIcon(NULL, IDI_ICON3); n_Index = m_ImageList.Add(m_hImage); // Иконка №2
Заметьте, что в этом случае иконки получают номера от нуля до двух.
Вариант 2: Несмотря на навороченное создание имаджлиста для этого варианта, все изображения сразу загружаются одной командой. Однако, при этом надо иметь как минимум два битмапа: один для варианта TrueColor с 32-х битным цветом и еще один - для варианта 256 и HiColor - цветных режимов.
// Загружаем битмапы CBitmap m_Bitmap;
if (Set32BPP()) m_Bitmap.LoadBitmap(IDB_BITMAPXP32); else m_Bitmap.LoadBitmap(IDB_BITMAP256); В этом случае, вы загружаете сразу столько изображений, сколько вам позволят ограничения системы.
При добавлении изображения в имаджлист необходимо помнить, что в случае 32-х битных изображений у нас в битмапе отсутствует маска и надо загрузить его соответствующим образом:
if (Set32BPP()) m_ImageList.Add(&m_ImageList, &m_ImageList); else m_ImageList.Add(&m_ImageList, RGB(255, 0, 255)); Опять-таки, в случае написания программы на чистом API код видоизменяется. Приведу его без разрыва на комментарий:
// Загружаем битмапы
HBITMAP hBmp; if (Set32BPP()) { hBmp = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAPXP32)); ImageList_Add(hImageList, hBmp, hBmp); } else { hBmp = LoadBitmap(hInsatnce, MAKEINTERESOURCE(IDB_BITMAP256)); ImageList_AddMasked(hImageList, hBmp, RGB(255, 0, 255)); } DeleteObject(hBmp); Теперь, для воспроизведения изображения нужно либо самим воспользоваться функциями прорисовки изображения, входящими в имаджлист, либо передать указатель (на класс имаджлиста в случае MFC) или хендл на сам имаджлист (API) в контрол, который сам воспользуется этими же функциями отрисовки.
Ну, вот в общем-то и все. Надеюсь, что я прояснил еще один вопрос, возникающий при программировании для Windows XP. Удачного программирования. |