лекции / Shchupak_Yu._Win32_API_Razrabotka_prilozheniy_dlya_Windows
.pdfПалитры |
161 |
|
|
|
|
Системная палитра
Системная палитра является графическим объектом уровня операционной систе мы. Ранее уже говорилось о том, что диапазон цветов, которые одновременно вос производятся устройством, зависит как от аппаратной палитры, реализуемой ви деоадаптером, так и от настроек экрана.
Чтобы посмотреть или изменить настройки экрана, нужно щелкнуть правой кнопкой мыши на свободной части рабочего стола экрана, после чего появится всплывающее меню. В этом меню следует выполнить команду Свойства, что при ведет к отображению диалогового окна Свойства: Экран. В окне нужно выбрать вкладку Настройка и найти на ней групповое поле Цветовая палитра. Элемент уп равления типа COMBOBOX внутри этого поля позволяет выбирать количество одно временно отображаемых цветов на экране. Если у вас достаточно современный дисплей, то доступными, скорее всего, окажутся следующие установки:
256 цветов;
Hi Color (16 бит);
True Color (24 или 32 бит).
В256 цветном режиме каждый пиксел представлен в кадровом буфере видео адаптера одним байтом. Один байт позволяет закодировать до 256 разных цветов, одновременно отображаемых на экране. Точный состав цветов определяется па литрой видеоадаптера, которая предоставляется пользовательским приложени ям в виде системной палитры.
Системная палитра представляет собой таблицу из 256 структур типа PALETTEENTRY:
typedef struct { BYTE peRed; BYTE peGreen; BYTE peBlue; BYTE peFlags;
} PALETTEENTRY;
Структура PALETTEENTRY определяет цвет конкретного элемента в массиве по его компонентам RGB. Поле peFlags используется при создании логических палитр.
Приложение не имеет непосредственного доступа к системной палитре. Одна ко оно может получить текущее состояние системной палитры при помощи функ ции GetSystemPaletteEntries, имеющей следующий прототип:
UINT |
GetSystemPaletteEntries( |
|
HDC hdc, |
// дескриптор контекста устройства |
|
UINT iStartIndex, |
// начальный вход в таблицу |
|
UINT nEntries, |
// количество входов |
|
LPPALETTEENTRY lppe |
// указатель на массив структур PALETTEENTRY |
|
); |
|
|
Параметр lppe задает адрес массива, в который помещается информация о па литре. Если этот параметр равен NULL, то функция возвращает общее количество цветов в системной палитре.
Системную палитру можно условно разделить на две секции. Первая секция содержит фиксированные, или статические, цвета, а вторая — цвета, которые мо гут изменяться приложением при помощи логической палитры.
По умолчанию в системной палитре определена группа из 20 статических цве тов. Размещение статических цветов в системной палитре показано в табл. 3.1.
162 |
|
Глава 3. GDI. Палитры, растры, метафайлы |
|
|
|||
Таблица 3.1. Статические цвета в системной палитре |
|||
|
|
|
|
Индекс |
Значение RGB |
Öâåò |
Примечание |
|
|
|
|
0 |
0x00, 0x00, 0x00 |
Черный |
В любом режиме |
1 |
0x80, 0x00, 0x00 |
Темно-красный |
В любом режиме |
2 |
0x00, 0x80, 0x00 |
Темно-зеленый |
В любом режиме |
3 |
0x80, 0x80, 0x00 |
Темно-желтый |
В любом режиме |
4 |
0x00, 0x00, 0x80 |
Темно-синий |
В любом режиме |
5 |
0x80, 0x00, 0x80 |
Темно-малиновый |
В любом режиме |
6 |
0x00, 0x80, 0x80 |
Темно-голубой |
В любом режиме |
7 |
0xC0, 0xC0, 0xC0 |
Светло-серый |
В любом режиме |
8 |
0xC0, 0xDC, 0xC0 |
Денежный зеленый |
В режиме True Color |
9 |
0xA6, 0xCA, 0xF0 |
Небесный |
В режиме True Color |
246 |
0xFF, 0xFB, 0xF0 |
Очень светло-серый |
В режиме True Color |
247 |
0xA0, 0xA0, 0xA4 |
Средне-серый |
В режиме True Color |
248 |
0x80, 0x80, 0x80 |
Темно-серый |
В любом режиме |
249 |
0xFF, 0x00, 0x00 |
Красный |
В любом режиме |
250 |
0x00, 0xFF, 0x00 |
Зеленый |
В любом режиме |
251 |
0xFF, 0xFF, 0x00 |
Желтый |
В любом режиме |
252 |
0x00, 0x00, 0xFF |
Синий |
В любом режиме |
253 |
0xFF, 0x00, 0xFF |
Малиновый |
В любом режиме |
254 |
0x00, 0xFF, 0xFF |
Голубой |
В любом режиме |
255 |
0xFF, 0xFF, 0xFF |
Белый |
В любом режиме |
|
|
|
|
Стоит обратить внимание на необычное размещение статических цветов. Так, первая группа из десяти цветов располагается в начале таблицы, а вторая группа из десяти цветов — в конце таблицы. Это связано с тем, что наиболее употреби тельная растровая операция XOR часто используется для инвертирования цветов и последующего их восстановления. Поэтому важно обеспечить инвертирование цвета при помощи инвертирования значения индекса в цветовой таблице. Напри мер, инверсия нулевого значения индекса дает значение 255 (0xFF), при этом чер ный цвет трансформируется в белый. Позицию 1 занимает темно красный цвет RGB(0x80, 0x00, 0x00). Если инвертировать индекс, то он переходит в 254 (0xFE), что соответствует голубому цвету. Он не совсем совпадает с цветом, дополняющим темно красный цвет в цветовом пространстве RGB (RGB(0x7F, 0xFF, 0xFF)), но все же достаточно близок к нему.
Первые 8 цветов и последние 8 цветов никогда не изменяются, независимо от цветового режима. Реализация цветов с индексами 8, 9, 246, 247 зависит от режима. В таблице указаны RGB значения этих цветов для режима True Color. В 256 цветном режиме RGB значения этих цветов будут другими.
Чтобы увидеть, как выглядит системная палитра на экране, можно создать маленькую экспериментальную программу, код которой приведен в листинге 3.1.
Листинг 3.1. Проект SystemPalette
//////////////////////////////////////////////////////////////////////
// SystemPalette.cpp #include <windows.h> #include "KWnd.h"
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
Палитры |
163 |
|
|
|
|
//====================================================================
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
MSG msg;
KWnd mainWnd("System palette", hInstance, nCmdShow, WndProc, NULL, 0, 0, 524, 543);
while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg);
}
return msg.wParam;
}
//==================================================================== LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
HDC hDC; PAINTSTRUCT ps; RECT r0;
RECT rect;
HBRUSH brush;
int dW, dH, i, j; int index = 0;
PALETTEENTRY pal[256];
switch (uMsg)
{
case WM_PAINT:
hDC = BeginPaint(hWnd, &ps);
GetSystemPaletteEntries(hDC, 0, 256, pal);
GetClientRect(hWnd, &r0); dW = (r0.right - 4) / 16; dH = (r0.bottom - 4) / 16;
SetViewportOrgEx(hDC, 2, 2, NULL);
for (i = 0; i < 16; ++i)
for (j = 0; j < 16; ++j) {
SetRect(&rect, j*dW, i*dH, (j+1)*dW - 1, (i+1)*dH - 1); brush = CreateSolidBrush(RGB(pal[index].peRed,
pal[index].peGreen, pal[index].peBlue)); FillRect(hDC, &rect, brush); DeleteObject(brush);
index++;
}
EndPaint(hWnd, &ps); break;
case WM_PALETTECHANGED: InvalidateRect(hWnd, NULL, TRUE); break;
case WM_DESTROY: |
продолжение |
|
164 |
Глава 3. GDI. Палитры, растры, метафайлы |
|
|
Листинг 3.1. (продолжение)
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return 0;
}
//////////////////////////////////////////////////////////////////////
Основная работа происходит в блоке обработки сообщения WM_PAINT.
Здесь вызовом функции GetSystemPaletteEntries содержимое системной палитры копируется в массив pal.
Затем при помощи функции GetClientRectкоординаты клиентской области окна про граммы запоминаются в переменной r0, которая является структурой типа RECT. По скольку для клиентской области всегда r0.leftи r0.topравны нулю, то величины r0.right и r0.bottomпредставляют собой ширину и высоту клиентской области соответственно. При заданных в WinMain размерах основного окна клиентская область представляет собой квадрат 516 × 516 пикселов. Поэтому переменные dWи dH, определяющие разме ры и положение очередного маленького квадратика rect, заполняемого очередным цве том из системной палитры при помощи кисти brush, получают значение 32.
В блоке обработки сообщения WM_PALETTECHANGED вызывается функция InvalidateRect, которая, в свою очередь, заставляет систему послать оконной проце дуре сообщение WM_PAINT для обновления содержимого клиентской области.
Создайте соответствующий проект и откомпилируйте программу1. Если в на стройках экрана задан 256 цветный режим, то будет отображена картинка, пока занная на рис. 3.1. И снова приходится сожалеть, что на черно белом рисунке поте ряно много важной информации, характеризующей палитру, поэтому мы надеемся, что вы видите эту картинку на экране монитора2. Обратите внимание на размеще ние статических цветов. Десять из них находятся в начале таблицы, и еще десять —
вконце. Остальные 236 нестатических цветов более или менее равномерно распре делены в цветовом пространстве RGB, образуя несколько радужных последовательно стей с разной интенсивностью цветов. Теперь, не закрывая данную программу, запус тите на выполнение какое нибудь графическое приложение, например MS Paint. Вы увидите, что среди нестатических цветов произошли изменения. Это говорит о том, что приложение MS Paint перестроило логическую палитру по своим внутренним критериям.
Проведем другой эксперимент. Измените настройки экрана, переключившись
врежим True Color3. Окно программы System palette примет вид, показанный на рис. 3.2. Легко заметить, что статические цвета остались на своих местах, а неста тические исчезли. Точнее, нестатические цвета оказались заполненными значе ниями RGB(0x00, 0x00, 0x00). Дело в том, что в режиме True Color цветовая палит ра приложениям не нужна, поэтому система не заботится о ее заполнении.
1 Не забудьте добавить к проекту файлы KWnd.h и KWnd.cpp, код которых приведен в листинге 1.2.
2Данный проект можно создать самостоятельно или загрузить его исходный код из файлов к книге, которые можно найти на сайте издательства «Питер» (www.piter.com).
3 Предполагается, что ваш дисплей поддерживает этот режим.
Палитры |
165 |
|
|
|
|
Рис. 3.1. Системная палитра в 256-цветном режиме экрана
Рис. 3.2. Системная палитра в режиме True Color
166 |
Глава 3. GDI. Палитры, растры, метафайлы |
|
|
Логическая палитра
При работе с логической палитрой следует помнить, что все цвета в приложении, которые реализованы как значения типа COLORREF, должны быть определены с помощью одного из следующих макросов:
COLORREF PALETTEINDEX(WORD wPaletteIndex);
COLORREF PALETTERGB(BYTE bRed, BYTE bGreen, BYTE bBlue);
Макрос PALETTEINDEX получает индекс и возвращает 32 разрядное описание эле мента палитры. В контексте устройства оно используется как элемент логической палитры контекста.
Макросу PALETTERGB, как и макросу RGB, передаются значения красной, зеленой и синей составляющих искомого цвета. При использовании этих макросов в контексте устройства без логической палитры их возвращаемые значения ин терпретируются одинаково. Но если макрос PALETTERGB используется в контексте устройства с логической палитрой, то для указанных в нем RGB составляющих система ищет ближайшее совпадение в логической палитре, словно приложение указало индекс в палитре. Этот макрос используется чаще, так как он является очевидной заменой макроса RGB во всех функциях, требующих передачи значения типа COLORREF.
Логическая палитра по умолчанию
Ранее уже говорилось, что если приложение не создает явным образом логическую палитру, то в нем используется логическая палитра по умолчанию, содержащая толь ко 20 статических цветов из системной палитры.
Для экспериментов с логической палитрой по умолчанию создадим приложе ние, выводящее в свое окно 8 разных цветов (листинг 3.2).
Листинг 3.2. Проект ColorsWithDefaultPal
//////////////////////////////////////////////////////////////////////
// ColorsWithDefaultPal.cpp #include <windows.h> #include "KWnd.h"
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //==================================================================== int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
MSG msg;
KWnd mainWnd("Colors with default palette", hInstance, nCmdShow, WndProc, NULL, 0, 0, 800, 200);
while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg);
}
return msg.wParam;
}
//==================================================================== LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
HDC hDC; PAINTSTRUCT ps;
Палитры |
167 |
|
|
|
|
RECT r0; RECT rect[8]; int dW, dH, i;
static HBRUSH brush[8];
COLORREF rgbColor[8] = { RGB(128,0,0), RGB(192,0,0),RGB(255,0,0), RGB(255,192,0), RGB(176,250,133), RGB(245,197,137), RGB(255,128,128), RGB(255,128,255)};
switch (uMsg)
{
case WM_CREATE:
for (i = 0; i < 8; ++i)
brush[i] = CreateSolidBrush(rgbColor[i]); break;
case WM_PAINT:
hDC = BeginPaint(hWnd, &ps); GetClientRect(hWnd, &r0);
dW = r0.right / 8; dH = r0.bottom;
for (i = 0; i < 8; ++i) {
SetRect(&rect[i], i*dW, 0, (i+1)*dW, dH); FillRect(hDC, &rect[i], brush[i]);
}
EndPaint(hWnd, &ps); break;
case WM_DESTROY:
for (i = 0; i < 8; ++i) DeleteObject(brush[i]);
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return 0;
}
//////////////////////////////////////////////////////////////////////
Если ваш экран остался в режиме True Color, то программа выведет на экран окно, показанное на рис. 3.3.
Рис. 3.3. Использование палитры по умолчанию (режим True Color)
В окне слева направо представлены 8 цветов, закодированные в массиве rgbColor: темно красный, темновато красный, красный, оранжевый, салатный, бежевый, кремовый, сиреневый. Первые три цвета являются вариациями чистого красного
168 |
Глава 3. GDI. Палитры, растры, метафайлы |
|
|
цвета с разной интенсивностью, остальные цвета образованы подходящими комби нациями RGB составляющих цвета.
Теперь переключитесь в 256 цветный режим экрана и снова запустите про грамму. Вывод программы показан на рис. 3.4.
Рис. 3.4. Использование палитры по умолчанию (256-цветный режим)
Особенно заметно исказились оранжевый, салатный и бежевый цвета. Причи ной этого является использование только двадцати статических цветов из сис темной палитры. Поскольку для указанных трех цветов не нашлось ближайшего подходящего цвета, то система попыталась создать запрошенный цвет при помо щи смешения статических цветов.
Полутоновая палитра
Чтобы увеличить количество имеющихся цветов в палитре, можно воспользо ваться полутоновой палитрой. Для этого необходимо выполнить следующие шаги:
1.Создать полутоновую палитру (функция CreateHalftonePalette).
2.Выбрать созданную палитру в контекст устройства (функция SelectPalette).
3.Реализовать палитру при помощи функции RealizePalette.
Функция SelectPalette имеет следующий прототип:
HPALETTE |
SelectPalette( |
|
|
HDC hdc, |
|
// дескриптор |
контекста устройства |
HPALETTE hpal, |
// дескриптор |
логической палитры |
|
BOOL bForceBackground |
// режим (фоновый или основной) |
||
); |
|
|
|
Последний параметр функции определяет, в каком режиме — фоновом (TRUE) или основном (FALSE) — будет реализована палитра при вызове функции Realize Palette. Процесс реализации палитры в общих чертах был описан выше.
Следует уточнить, что в фоновом режиме функция RealizePalette пытается раз местить логическую палитру привязкой к уже существующим цветам в систем ной палитре, подыскивая ближайшее соответствие. Это размещение делается все гда, независимо от того, активно ли данное приложение.
Восновном режиме функция RealizePalette копирует логическую палитру
всистемную, за исключеним статических цветов, только тогда, когда приложе ние активно.
Влистинге 3.3 приведен код приложения, которое выполняет те же действия, что и предыдущее приложение, но работает с полутоновой палитрой. В нем пока зана также обработка сообщений WM_QUERYNEWPALETTE и WM_PALETTECHANGED.
Палитры |
169 |
|
|
|
|
Листинг 3.3. Проект ColorsWithHalftonePal
//////////////////////////////////////////////////////////////////////
// ColorsWithHalftonePal.cpp #include <windows.h> #include "KWnd.h"
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //==================================================================== int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
MSG msg;
KWnd mainWnd("Colors with halftone palette", hInstance, nCmdShow, WndProc, NULL, 0, 0, 800, 200);
while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg);
}
return msg.wParam;
}
//==================================================================== LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
HDC hDC; PAINTSTRUCT ps; RECT r0;
RECT rect[8]; int dW, dH, i;
COLORREF paletteColor[8] = { PALETTERGB(128,0,0), PALETTERGB(192,0,0), PALETTERGB(255,0,0), PALETTERGB(255,192,0), PALETTERGB(176,250,133), PALETTERGB(245,197,137), PALETTERGB(255,128,128), PALETTERGB(255,128,255)};
static HBRUSH brush[8]; static HPALETTE hPal; HPALETTE hOldPal;
switch (uMsg)
{
case WM_CREATE:
for (i = 0; i < 8; ++i)
brush[i] = CreateSolidBrush(paletteColor[i]); hDC = GetDC(hWnd);
hPal = CreateHalftonePalette(hDC); ReleaseDC(hWnd, hDC);
break;
case WM_PAINT: |
|
|
hDC = BeginPaint(hWnd, &ps); |
|
|
hOldPal = SelectPalette(hDC, hPal, FALSE); |
|
|
GetClientRect(hWnd, &r0); |
|
|
dW = r0.right / 8; |
|
|
dH = r0.bottom; |
|
|
for (i = 0; i < 8; ++i) { |
|
|
SetRect(&rect[i], i*dW, 0, (i+1)*dW, dH); |
|
|
FillRect(hDC, &rect[i], brush[i]); |
|
|
} |
продолжение |
|
|
170 |
Глава 3. GDI. Палитры, растры, метафайлы |
|
|
Листинг 3.3 (продолжение)
SelectPalette(hDC, hOldPal, TRUE); EndPaint(hWnd, &ps);
break;
case WM_QUERYNEWPALETTE: hDC = GetDC(hWnd);
SelectPalette(hDC, hPal, FALSE); if (RealizePalette(hDC))
InvalidateRect(hWnd, NULL, TRUE); ReleaseDC(hWnd, hDC);
break;
case WM_PALETTECHANGED: hDC = GetDC(hWnd);
SelectPalette(hDC, hPal, FALSE); if (RealizePalette(hDC))
InvalidateRect(hWnd, NULL, TRUE); ReleaseDC(hWnd, hDC);
break;
case WM_DESTROY: DeleteObject(hPal);
for (i = 0; i < 8; ++i) DeleteObject(brush[i]);
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return 0;
}
//////////////////////////////////////////////////////////////////////
Обратите внимание на следующие моменты:
Логическая палитра hPal создается в блоке обработки сообщения WM_CREATE, а реализуется как в блоке обработки сообщения WM_QUERYNEWPALETTE, так и в блоке обработки сообщения WM_PALETTECHANGED. Функция RealizePalette воз вращает количество цветов логической палитры, отображенных на системную палитру. Если это значение больше нуля, то вызывается функция InvalidateRect.
В блоке обработки сообщения WM_PAINT логическая палитра выбирается в кон текст устройства, после чего вызываются функции рисования.
После запуска этой программы в 256 цветном режиме экрана вы должны уви деть картинку, практически совпадающую по качеству передачи цветов с той, которая была в режиме экрана True Color (см. рис. 3.3).
Использование специализированной палитры
Бывают ситуации, когда применение полутоновой палитры не обеспечивает удов летворительной передачи всех требуемых цветов. Это характерно для приложений, которым необходимо отображать множество оттенков одного и того же цвета.
Нетрудно показать на примере предыдущего приложения, что оно не справит ся с выводом даже восьми оттенков одного, например зеленого, цвета. Для этого замените определение массива paletteColor следующим определением:
