Графический интерфейс GDI в Microsoft Windows© Александр Фролов, Григорий ФроловТом 14, М.: Диалог-МИФИ, 1993, 288 стр. 3.2. Выбор цвета без использования палитрыПриложения, которые не хотят ничего знать про палитры, могут указывать логический цвет изображений, составляя его из RGB-компонент, указывая их количественный состав. Однако, если видеоконтроллер не работает в режиме True Color, для вывода на экран будут использованы только статические цвета или смешанные цвета, состоящие из статических цветов. В результате полученный на экране физический цвет может не соответствовать запрошенному логическому цвету. Как указать цветМногие функции программного интерфейса GDI (например, функции, создающие перья и кисти) требуют в качестве одного из своих параметров ссылку на используемый цвет. Цвет указывается при помощи переменной, имеющей тип COLORREF : HBRUSH WINAPI CreateSolidBrush(COLORREF clrref); Тип COLORREF определен в файле windows.h следующим образом: typedef DWORD COLORREF; В простейшем случае цвет можно определить с помощью макрокоманды RGB , комбинирующей цвет из отдельных компонент: #define RGB(r,g,b) \ ((COLORREF)(((BYTE)(r) | \ ((WORD)(g)<<8)) | \ (((DWORD)(BYTE)(b))<<16))) Эта макрокоманда упаковывает отдельные цветовые компоненты в двойное слово, причем (что важно) старший байт этого слова должен быть равен нулю (рис. 3.2).
Рис. 3.2. Представление цвета, полученное с помощью макрокоманды RGB В файле windows.h определены также макрокоманды, извлекающие из переменной типа COLORREF, упакованной с помощью макрокоманды RGB, отдельные цветовые компоненты: #define GetRValue (rgb) ((BYTE)(rgb)) #define GetGValue (rgb) ((BYTE)(((WORD)(rgb)) >> 8)) #define GetBValue (rgb) ((BYTE)((rgb)>>16)) Как мы уже говорили, в зависимости от текущего цветового разрешения Windows может предоставить приложению приближенный цвет, который максимально соответствует запрошенному логическому цвету. Функция GetNearestColor возвращает для запрошенного логического цвета clrref физический цвет, составленный только из компонент чистого цвета: COLORREF WINAPI GetNearestColor(HDC hdc, COLORREF clrref); Через параметр hdc необходимо передать идентификатор контекста отображения. Системные цветаКак выбрать цвета для объектов приложения? Самый простой (и самый плохой) способ заключается в том, что в исходном тексте приложения вы указываете цвета как комбинации RGB-компонент. Очевидный недостаток этого способа заключается в том, что пользователь не сможет изменить эти цвета. Даже если у вас идеальный вкус и вы сможете подобрать превосходную цветовую гамму, следует учитывать, что ваше приложение может быть запущено на монохромном мониторе, где отдельные цвета преобразуются в градации серого цвета. В результате некоторые элементы изображения могут стать плохо различимыми или пропадут вовсе. Более удачный способ заключается в использовании так называемых системных цветов. Системные цвета - это цвета, с помощью которых операционная система Windows рисует отдельные элементы окон и органов управления. Приложение Control Panel, которое входит в состав Windows, позволяет вам изменять системные цвета, обеспечивая приемлемую цветовую палитру практически для любого типа видеомонитора. Для того чтобы узнать цвет той или иной системной компоненты экрана Windows, вы можете вызвать функцию GetSysColor : COLORREF WINAPI GetSysColor(int nDspElement); В качестве единственного параметра следует передать этой функции идентификатор компоненты:
Ваше приложение может выбрать для использования некоторые из системных цветов, при этом пользователь сможет влиять на внешний вид вашего приложения с помощью Control Panel, настраивая цвета на свой вкус. Вы можете создать приложение, изменяющее системные цвета. Для этого обратите внимание на функцию SetSysColors : void WINAPI SetSysColors( int cDspElements, const int FAR* lpnDspElements, const COLORREF FAR* lpdwRgbValues); Параметр cDspElements определяет количество элементов, для которых изменяются цвета. Параметр lpnDspElements представляет собой указатель на массив идентификаторов элементов изображения, список которых приведен выше. Перед вызовом функции вам надо подготовить также массив из cDspElements элементов, содержащих новые значения для цветов, передав функции адрес этого массива через параметр lpdwRgbValues. Внесенные изменения сохраняются только до очередного перезапуска операционной системы Windows. После вызова этой функции все запущенные приложения получают сообщение WM_SYSCOLORCHANGE , которое информирует их об изменении системных цветов. Windows также перерисовывает на экране все видимые окна. Сообщение WM_SYSCOLORCHANGEКак мы только что сказали, сообщение WM_SYSCOLORCHANGE посылается всем активным окнам верхнего уровня при изменении системных цветов. В ответ на это сообщение приложения, которые создают свои перья и кисти на базе системных цветов, должны удалить эти перья и кисти, а затем создать их заново. Так как после изменения системных цветов все активные окна получают сообщение WM_PAINT, обработчик сообщения WM_SYSCOLORCHANGE не должен ничего перерисовывать в окне. Сообщение WM_SYSCOLORCHANGE не имеет параметров, поэтому значения, передаваемые через wParam и lParam следует проигнорировать. Функция ChooseColorВ составе DLL-библиотеки commdlg.dll есть функция ChooseColor , которая предназначена для выбора цвета . Эта функция выводит на экран диалоговую панель (рис. 3.3), с помощью которой пользователь может выбрать цвет из основного набора цветов "Basic Color" и дополнительного "Custom Colors". Возможность использования цветовых палитр при выборе не обеспечивается, так что с помощью этой функции можно выбирать только чистые статические или смешанные цвета.
Рис. 3.3. Диалоговая панель для выбора цвета Если нажать на кнопку "Define Custom Colors...", внешний вид диалоговой панели изменится (рис. 3.4).
Рис. 3.4. Расширенная диалоговая панель Пользуясь правой половиной диалоговой панели, пользователь сможет добавить новый цвет в набор "Custom Colors" и затем выбрать его из этого набора. Функция ChooseColor описана в файле commdlg.h: BOOL WINAPI ChooseColor(CHOOSECOLOR FAR* lpcc); Перед вызовом функции следует заполнить структуру CHOOSECOLOR, передав функции ее адрес через параметр lpcc. В случае успешного выбора цвета функция возвращает TRUE. Если пользователь отказался от выбора или, если произошла ошибка, возвращается значение FALSE. Структура CHOOSECOLOR и указатель на нее описаны в файле commdlg.h: typedef struct tagCHOOSECOLOR { DWORD lStructSize; HWND hwndOwner; HWND hInstance; COLORREF rgbResult; COLORREF FAR* lpCustColors; DWORD Flags; LPARAM lCustData; UINT (CALLBACK* lpfnHook)(HWND, UINT, WPARAM, LPARAM); LPCSTR lpTemplateName; } CHOOSECOLOR; typedef CHOOSECOLOR FAR *LPCHOOSECOLOR; Опишем назначение и правила использования отдельных полей этой структуры. Поле lStructSize заполняется перед вызовом функции. Оно должно содержать размер структуры в байтах. Поле Flags также заполняется до вызова функции. В него следует записать флаги инициализации, влияющие на использование других полей этой структуры.
В поле hwndOwner перед вызовом функции следует записать идентификатор окна, создавшего диалоговую панель, или NULL. В последнем случае нельзя использовать флаг CC_SHOWHELP. Поле hInstance заполняется в тех случаях, когда приложение использует свой собственный шаблон диалоговой панели (вместо стандартного шаблона, расположенного в ресурсах DLL-библиотеки). В этом случае перед вызовом функции в это поле следует записать идентификатор модуля, содержащего шаблон диалоговой панели. В поле Flags необходимо указать флаги CC_ENABLETEMPLATE или CC_ENABLETEMPLATEHANDLE. В поле lpTemplateName следует записать адрес текстовой строки идентификатора ресурса шаблона диалоговой панели (если этот шаблон используется). Поле rgbResult предназначено для передачи приложению цвета, выбранного пользователем. Если записать в это поле значение NULL, сразу после вывода диалоговой панели выбора цвета по умолчанию будет выбран черный цвет. Вы, однако, можете использовать для начального выбора любой другой цвет, записав его в это поле и указав флаг CC_RGBINIT. Перед вызовом функции вы должны подготовить массив из 16 двойных слов, содержащих цвета для использования в меню "Custom Colors". Адрес этого массива следует передать через параметр lpCustColors. Поле lCustData используется для передачи данных функции фильтра (если она определена). Адрес функции фильтра передается через параметр lpfnHook. Для использования функции фильтра следует указать флаг CC_ENABLEHOOK. |