Программу-инструмент, которую вы используете для создания значков, курсоров и битовых образов часто называют редактором изображений (image editor), и он является одной из наиболее важных утилит разработчика в любой интегрированной среде разработки программ для Windows. Как значки, так и курсоры являются разновидностью битовых образов.
Битовый образ (bitmap) — это битовый массив, где один или более битов соответствуют каждому пикселю экрана. В монохромном битовом образе для каждого пикселя требуется один бит. (В простейшем случае 1 соответствует белому цвету, а 0 — черному. Тем не менее, битовые образы часто используются не только для создания простых рисунков, но и в логических операциях.) В цветном битовом образе для отображения цвета каждому пикселю соответствует несколько битов. Редакторы изображений обычно поддерживают создание монохромных и 16-цветных битовых образов. В 16-цветном битовом образе для каждого пикселя требуется 4 бита.
В Windows 95 имеется два размера значков — стандартный и маленький. На дисплеях VGA стандартный значок имеет размер 32 пикселя в ширину и 32 пикселя в высоту, а площадь маленького значка равна 16 квадратных пикселей. Маленький значок используется в левой части строки заголовка приложения для вызова системного меню, в панели задач системы в нижней части экрана, а также в списках программ меню Start. Значки, появляющиеся на рабочем столе, имеют стандартный размер. В программе Windows Explorer и меню Start пользователь может произвольно выбирать стандартный или маленький значок.
В программе можно получить горизонтальный (X) и вертикальный (Y) размеры значков и курсоров, используя функцию GetSystemMetrics с параметрами SM_CXICON и SM_CYICON (для стандартного значка), SM_CXSMICON и SM_CYSMICON (для маленького значка) и SM_CXCURSOR и SM_CYCURSOR для курсоров мыши. Для большинства дисплеев размеры стандартных курсоров и значков одинаковы.
Редактор изображений, включенный в состав программы Developer Studio, может создавать файл с расширением .ICO, содержащий один из трех различных образов значка:
• Стандартный: 16-цветный площадью 32 квадратных пикселя
• Монохромный: черно-белый площадью 32 квадратных пикселя
• Маленький: 16-цветный площадью 16 квадратных пикселей
Вам нет необходимости создавать значки во всех трех форматах. Сама Windows может создать из стандартного значка — маленький, просто исключив каждый второй столбец и строку. Для монохромных дисплеев (которые сейчас почти полностью устарели) Windows может приближенно изобразить значок, используя различные оттенки серого цвета.
Когда вы создаете образ значка в одном из трех представленных форматов, редактор изображений, фактически, сохраняет его в виде двух битовых образов — монохромной маски (mask) битового образа и монохромного или цветного изображения битового образа. Значки всегда прямоугольны, но маска позволяет значку представлять непрямоугольные изображения, т. е. вместо изображения всего значка, некоторые его части могут быть окрашены на экране цветом фона. Кроме этого значки могут содержать области, инвертирующие цвет фона.
При выводе значка на экран, Windows сначала использует поразрядную операцию AND экрана и первого битового образа. Пиксели экрана, соответствующие нулевым битам первого битового образа становятся нулевыми, т. е. черными. Пиксели экрана, соответствующие единичным битам остаются без изменения. Эта логика отражена в следующей таблице:
Бит маски
| Пиксели экрана
|
0 1
|
| 0 0
0 1
|
Далее, Windows выполняет поразрядную операцию исключающего OR изображения битового образа и экрана. Во втором битовом образе оставляет пиксель на экране без изменений; 1 во втором битовом образе инвертирует пиксель экрана. Эта логика представлена в следующей таблице:
Бит изображения
| Пиксели экрана
|
0 1
|
| 0 1
1 0
|
Используя нотацию языка С для этих операций, вывод на экран осуществляется в соответствии со следующей формулой:
Display = (Display & Mask) /\ Image
Для 16-цветного значка маска битового образа — монохромна и формируется указанным выше способом. Битовый образ изображения содержит 4 бита на пиксель для отображения 16 цветов. Все четыре бита устанавливаются в 1 для той области значка, в которой цвет фона инвертируется.
Получение описателя иконок
В файле описания ресурсов ссылка на файл иконки выглядит примерно так:
myicon ICON iconfile.ico
где ICONFILE.ICO — имя файла значка. В этой инструкции значку присваивается имя "myicon".
В редакторе ресурсов Microsoft Visual C++, вы можете задать имя иконки, ее идентификационный номер (ID_ICONn) с помощью диалогового окна "Свойства" ("Properties"), которое можно вызвать, кликнув правой клавишей мыши на идентификаторе нужной иконке.
В программе на С для получения описателя значка используется функция Loadlcon. В функции Loadlcon имеется два параметра. Первым является описатель экземпляра вашей программы, который в WinMain обычно называется hInstance. Этот описатель требуется для Windows, чтобы определить, в каком файле с расширением *.ЕХЕ содержится ресурс значка. Вторым параметром является имя значка из описания ресурсов, заданное в виде указателя на оканчивающуюся нулем строку. Возвращаемым значением функции Loadlcon является значение типа HICON, которое определяется в WINDOWS.H.
Имеется связь между именем значка в описании ресурсов и в инструкции, содержащей функцию Loadlcon вашей программы на С:
Описание ресурсов:
myicon ICON iconfile.ico
Исходный текст программы:
HICON hicon = Loadlcon (hInstance,''myicon");
Не беспокойтесь о том, в верхнем или нижнем регистре задано имя иконки. Компилятор преобразует в файле описания ресурсов имя иконки символы верхнего регистра и вставляет это имя в таблицу ресурсов в заголовке файла программы с расширением *.ЕХЕ. При первом вызове функции Loadlcon, Windows преобразует строку, заданную вторым параметром в символы верхнего регистра и отыскивает в таблице ресурсов файла с расширением *.ЕХЕ совпадающее с этой строкой имя.
Вместо имени вы также можете использовать число (16-разрядное беззнаковое WORD). Это число называется идентификатором (ID) значка. Ниже показано как это делается:
Описание ресурсов:
125 ICON iconfile.ico
Исходный текст программы:
hicon = Loadlcon (hInstance, MAKEINTRESOURCE (125));
MAKEINTRESOURCE (make an integer into a resourse string — преобразовать целое в строку ресурса) является макросом, определенным в заголовочных файлах Windows, который преобразует число в указатель, но со старшими 16 разрядами, установленными в нуль. Так Windows узнает, что второй параметр функции Loadlcon является числом, а не указателем на символьную строку.
Если, вы использовали идентификатор иконки, вы можете прочитать его при помощи этого идентификатора (фактически, это аналогично предыдущему случаю, с той разницей, что вы используете не числовое значение, а имя константы ID_ICONn, которая читается компилятором из файла ресурсов). Например,
hicon = Loadlcon (hInstance, MAKEINTRESOURCE (ID_ICON1));
Использование идентификаторов вместо имен иконок уменьшает размер файла с расширением .ЕХЕ и, вероятно, немного ускоряет работу функции Loadlcon. Больше того, если в вашей программе используется множество значков, то вы обнаружите, что проще хранить их идентификаторы в массиве.
Ранее мы уже использовали предопределенные значки:
Loadlcon (NULL, IDI_APPLICATION);
Поскольку параметр hinstance установлен в NULL, Windows узнает, что эта иконка является предопределенным. IDI_APPLICATION также определяется в заголовочных файлах Windows с использованием макроса MAKEINTRESOURCE:
#define IDI_APPLICATION MAKEINTRESOURCE (32512)
Предопределенные иконки и курсоры являются частью файла драйвера дисплея.
Использование иконок в программе
Хотя для обозначения программ Windows использует значки несколькими способами, во множестве программ для Windows значок задается только при определении класса окна:
wndclass.hlcon = Loadlcon(hinstance, "Myicon");
wndclass.hIconSm = Loadlcon(hinstance, "MySmIcon");
Вы можете в обеих инструкциях сослаться на один и тот же значок стандартного размера, и Windows при выводе маленькой иконки на экран просто приведет его к необходимому размеру. Если в дальнейшем вы захотите изменить значок программы, это можно сделать с помощью функции SetClassLong. Предположим, что у вас в описании ресурсов был второй значок:
anothericon ICON iconfi.l2.ico
С помощью следующей инструкции вы можете заменить этот значок значком "myicon":
SetClassLong ( hwnd, GCL_HICON, Loadlcon(hinstance, "anothericon") );
Маленькую иконку можно заменить с помощью GCL_HICONSM.
Если вы сохранили описатель иконки, возвращенный функцией Loadlcon, то вы также можете и нарисовать значок в рабочей области вашего окна:
DrawIcon (hdc,x, у, hicon);
Сама Windows использует функцию DrawIcon при выводе иконки вашей программы в соответствующее место. Windows получает описатель значка из структуры класса окна. Вы можете получить описатель тем же способом:
DrawIcon (hdc,x, у, GetClassLong(hwnd, GCL_HICON));
Использование альтернативных курсоров
Инструкции для задания курсора в файле описания ресурсов и для получения описателя курсора в вашей программе очень похожи на показанные ранее инструкции для иклнок:
Описание ресурсов:mycursor CURSOR cursflle.cur
Исходный текст программы: hCursor = LoadCursor (hinstance, "mycursor");
Другие способы, показанные для значков (использование идентификаторов и MAKEINTRESOURCE), также работают и для курсоров. В заголовочные файлы Windows включается определение typedef HCURSOR, которое вы можете использовать для хранения описателя курсора.
Вы можете использовать описатель курсора, полученный при вызове функции LoadCursor, при задании поля hCursor структуры класса окна:
wndclass.hCursor = LoadCursor (hinstance, "mycursor");
Это заставляет курсор мыши, если он оказывается в рабочей области вашего окна, превращаться в ваш пользовательский курсор.
Если вы используете дочерние окна, можно сделать так, чтобы курсор выглядел по-разному в разных окнах. Если в вашей программе определяются классы этих дочерних окон, то для каждого класса вы можете использовать свой курсор путем соответствующей установки поля hCursor в каждом классе окна. А если вы используете предопределенные дочерние элементы управления, то изменить поле hCursor класса окна можно с помощью функции:
SetClassLong(hwndChild, GCL_HCURSOR, LoadCursor(hinstance, "childcursor")) ;
Если вы разделяете рабочую область окна вашей программы на маленькие логические области без использования дочерних окон, то для изменения курсора мыши вы можете использовать функцию SetCursor.
SetCursor (hCursor) ;
Функцию SetCursor следует вызывать при обработке сообщения WM_MOUSEMOVE. В противном случае для перерисовки курсора при его движении Windows использует курсор, ранее заданный в классе окна.
Битовые образы: картинки в пикселях
Мы уже говорили об использовании битовых образов в значках и курсорах. В Windows также включен тип ресурсов с именем BITMAP.
Битовые образы используются в двух главных целях. Первая — рисование на экране картинок. Например, файлы драйверов дисплеев в Windows содержат массу крошечных битовых образов, которые используются для рисования стрелок в полосах прокрутки, галочек в раскрывающихся меню, изображений на кнопках изменения размеров окна, флажках и переключателях. Вы можете использовать битовые образы в меню и панелях инструментов приложений. В таких программах, как Paint, битовые образы используются для изображения графического меню.
Вторая цель использования битовых образов — создание кистей. Кисти, как вы уже знаете, являются шаблонами пикселей, которые Windows использует для закрашивания изображаемых на экране областей.
Для создания битовых образов и их описания используются те же средства, что и для иконок.
Для загрузки битового образа в программу используется функция LoadBitmap, которая аналогична функциям LoadIcon и LoadCusor. Ее возвращаемым значением является описатель битового образа:
HBITMAP hBitmap = LoadBitmap (hinstance, szAppName) ;
Этот описатель затем можно использовать для создания шаблонной кисти (pattern brush). Основой кисти является битовый образ:
HBRUSH hBrush = CreatePatternBrush (hBitmap) ;
Когда Windows закрашивает этой кистью область экрана, битовый образ повторяется по горизонтали и вертикали до заполнения ограничивающей области.
Главное отличие между битовыми образами и остальными ресурсами в их практической важности и может быть легко выражено так: битовые образы являются объектами GDI. Хороший стиль составления программ рекомендует, что битовые образы должны быть удалены из программы, если в них отпадает нужда, или если программа завершается.
DeleteObject((HGDIOBJ) hBrush) ;
DeleteObject((HGDIOBJ) hBitmap) ;
Символьные строки
Наличие ресурса для символьных строк может вначале показаться странным. Тем более, что не было никаких проблем при использовании привычных символьных строк, определенных в качестве переменных непосредственно в теле исходного текста нашей программы.
Ресурсы-символьные строки предназначены главным образом для облегчения перевода вашей программы на другие языки. Как будет рассказано далее, меню и окна диалога также являются частью описания ресурсов. Если вместо непосредственного использования строк в исходном тексте вашей программы, вы используете ресурсы - символьные строки, то весь текст вашей программы, окажется в одном файле — файле описания ресурсов. Если текст в файле описания ресурсов переводится, то все, что вам нужно сделать для иноязычной версии вашей программы, это перекомпоновать программу и добавить переведенные ресурсы в файл с расширением *.ЕХЕ. Этот способ намного безопасней, чем возня с исходными кодами вашей программы.
Использование ресурсов-символьных строк
Ресурсы - символьные строки определяются в описании ресурсов с помощью ключевого слова STRINGTABLE:
STRINGTABLE {
idl, "character string 1" id2, "character string 2" [определения остальных строк] }
В описании ресурсов может содержаться только одна таблица строк. Максимальный размер каждой строки — 255 символов. В строке не может быть управляющих символов языка С, за исключением \t (табуляция). Однако, символьные строки могут содержать восьмеричные константы:
Табуляция (Tab) \011
Перевод строки (Linefeed) \012
Возврат каретки (Carriage return) \015
Эти управляющие символы распознаются функциями DrawText и MessageBox.
Вы можете использовать функцию LoadString для копирования строки из ресурса в буфер в сегменте данных вашей программы:
LoadString (hinstance, id, szBuffer, iMaxLength);
Параметр id соответствует идентификатору, который предшествует каждой строке в файле описания ресурсов; szBuffer — это указатель на символьный массив, в который заносится символьная строка; iMaxLength — это максимальное число передаваемых в siBuffer символов. Идентификаторы строк, которые предшествуют каждой строке, обычно являются идентификаторами макроопределений, которые задаются в заголовочном файле. Многие программисты, программирующие под Windows, для идентификаторов строк используют префикс IDS_.
Ресурсы, определяемые пользователем
Ресурсы, определяемые пользователем (user-defined resourse) удобны для включения самых разнообразных данных в ваш файл с расширением *.ЕХЕ и получения доступа в программе к этим данным. Данные могут содержаться в любом выбранном вами формате — текстовом или бинарном. При загрузке данных в оперативную память возвращаемым значением функций Windows, которые используются для доступа к определяемым пользователем ресурсам, является указатель на данные. С этими данными вы можете делать все, что угодно. Вы вероятно решите, что этот способ хранения и доступа к разнообразным данным удобнее, чем альтернативный, при котором данные хранятся в других файлах и доступ к ним осуществляется через функции файлового ввода.
Например, предположим, что у вас есть файл PROGHELP.TXT, в котором содержится текст "подсказок" для вашей программы. Такой файл не должен быть в чистом виде ASCII-файлом: в нем также могут содержаться бинарные данные, например, указатели, которые могли бы помочь при ссылках на различные части этого файла. Следующим образом опишите ссылку на этот файл в вашем файле описания ресурсов:
helptext TEXT proghelp.txt
Имена helptext (имя ресурса) и TEXT (тип ресурса) в этом выражении могут быть любыми. Слово TEXT написано прописными буквами просто, чтобы сделать его похожим на слова ICON, CURSOR и BITMAP. To, что мы здесь делаем, является созданием ресурса вашего собственного типа, который называется TEXT.
В процессе инициализации программы (например, при обработке сообщения WM_CREATE), можно получить описатель этого ресурса:
hResource = LoadResource (hinstance, FindResource (hinstan.ce, "TEXT", "helptext")) ;
Переменная hResource определяется как имеющая тип HGLOBAL. Несмотря на свое имя, функция LoadResource фактически не загружает сразу ресурс в оперативную память. Используемые вместе, так как это было показано, функции LoadResource и FindResource по существу эквивалентны функциям Loadlcon и LoadCursor. Фактически, функции Loadlcon и LoadCursor используют функции LoadResource и FindResource.
Вместо имен и типов ресурсов можно использовать числа. Числа могут быть преобразованы в дальние указатели при вызове функции FindResource с использованием MAKEINTRESOURCE. Числа, используемые в качестве типа ресурса, должны быть больше 255. (Числа от 1 до 9 при вызове функции FindResource используются в Windows для существующих типов ресурсов.)
Когда вам необходимо получить доступ к тексту, вызывайте функцию LockResource:
pHelpText = LockResource (hResource) ;
Функция LockResource загружает ресурс в память (если он еще не был загружен), и возвращает указатель на него. После окончания работы с этим ресурсом, вы можете освободить оперативную память, вызвав функцию FreeResource:
FreeResource (hResource);
Даже если вы не вызовите функцию FreeResource, после завершения работы программы оперативная память все равно будет освобождена.