лекции / Shchupak_Yu._Win32_API_Razrabotka_prilozheniy_dlya_Windows
.pdfПиктограммы |
251 |
|
|
|
|
Предположим, что вы хотите использовать в своей программе пиктограмму, изображение которой находится в файле AnyIcon.ico. Для начала требуется ско пировать файл AnyIcon.ico в папку вашего приложения.
После этого выполните следующую последовательность действий:
В главном меню Visual Studio выполните команду Insert Resource. В появив шемся диалоговом окне Insert Resource выберите тип ресурса Icon и нажмите кнопку Import.
В появившемся диалоговом окне Import Resource убедитесь, что открыта папка вашего приложения, и щелкните на имени файла AnyIcon.ico. В результате бу дет открыто окно графического редактора с изображением импортируемой пик тограммы.
Назначьте идентификатор ресурсу пиктограммы в соответствии с п. 3 описан ного выше сценария.
Сохраните ресурс в проекте и выполните действия по модификации состава проекта, как это показано в пп. 5 и 6 описанного выше сценария. Изложенная процедура описывает использование графического редактора
врежиме импорта. Аналогично могут импортироваться и другие графические ре сурсы, например, курсоры и растровые изображения.
Просмотр и редактирование ресурсов приложения
Ресурсы приложения можно просматривать в двух разных режимах, вызывая со ответствующий графический редактор или открывая файл описания ресурсов в текстовом режиме.
Просмотр ресурса с вызовом соответствующего редактора
В окне Workspace перейдите на вкладку ResourceView и сделайте двойной щелчок мышью на идентификаторе интересующего вас ресурса. При этом будет открыт соответствующий редактор ресурса, и в его окне появится изображение, связан ное с этим ресурсом, как, например, показано на рис. 5.8. После этого ресурс мож но редактировать при помощи средств редактора. Если в определение ресурса были внесены изменения, то они должны быть сохранены при помощи команды меню
File Save.
Просмотр файла описания ресурсов в текстовом режиме
Закройте все окна тех редакторов ресурсов, которые открыты в настоящий мо мент. После этого в главном меню Visual Studio выполните команду File Open. В результате появится окно диалога Open (Открыть), внешний вид которого пока зан на рис. 5.9.
Убедитесь, что в текстовом поле Папка выбрано имя папки текущего проекта (в данном случае — Russia). Если это не так, то следует найти искомую папку в комбинированном списке Папка. Затем откройте комбинированный список Open as и выберите строку Text. После этого останется только щелкнуть на имени нуж ного файла (в данном примере Russia.rc). В результате в окне редактора Visual Studio появится текст файла описания ресурсов.
252 |
Глава 5. Ресурсы Windows-приложения |
|
|
Рис. 5.9. Диалоговое окно Open
Не приводя здесь полного текста файла Russia.rc, обратим ваше внимание на следующую строку:
IDI_TRICOLOUR |
ICON |
DISCARDABLE |
"tricol.ico" |
в которой содержится описание ресурса созданной пиктограммы.
Это так называемое однострочное описание ресурса. Оно применяется для опи сания пиктограмм, курсоров и битовых образов. Синтаксис подобного описания выглядит следующим образом:
имя_ресурса |
тип_ресурса |
DISCARDABLE |
имя_файла |
Имя_ресурса интерпретируется Windows либо как C строка с завершающим нулевым символом, либо как целочисленный идентификатор. Если имя_ресурса представляет собой ASCII изображение десятичного или шестнадцатеричного числа, то Windows воспринимает его как целочисленный идентификатор. В про тивном случае имя_ресурса интерпретируется как C строка, хотя формальных признаков строки (обрамляющих кавычек) у этого имени нет.
Похоже, что вариант C строки использовался в ранних версиях Windows, поскольку редакторы ресурсов Visual Studio в генерируемом ими коде всегда определяют имя ресурса в виде целочисленной константы. Так, если заглянуть в текст файла resource.h в проекте Russia, можно найти там следующую строку:
#define IDI_TRICOLOUR 101
То есть на самом деле после подстановки макроопределения описание пиктограм мы будет иметь следующий вид:
101 ICON DISCARDABLE "tricol.ico"
Таким образом, однострочное описание ресурса, находящееся в файле Russia.rc, связывает пиктограмму IDI_TRICOLOUR с графическим файлом tricol.ico, содержа щим два растровых изображения: стандартной и малой пиктограмм.
Атрибут DISCARDABLE (выгружаемый) использовался в ранних версиях Windows, позволяя системе освобождать занимаемую ресурсом оперативную па мять, когда возникали проблемы со свободной памятью. В Win32 он фактически игнорируется.
Пиктограммы |
253 |
|
|
|
|
Использование ресурса в приложении
Для получения дескриптора пиктограммы, относящегося к типу HICON, вызыва ется функция LoadIcon или LoadImage.
Беглое знакомство с функцией LoadIcon у нас уже состоялось в главе 1. Но здесь она будет рассмотрена более подробно. Функция LoadIcon загружает ресурс пик тограммы из выполняемого файла (.exe), ассоциированного с экземпляром при ложения hInstance:
HICON LoadIcon(HINSTANCE hInstance, LPCTSTR lpIconName);
В качестве второго параметра, определяющего имя ресурса, функция прини мает строку с завершающим нулевым символом. Ранее говорилось, что в файле описания ресурсов, подготовленном с помощью редактора ресурсов, имя_ресурса для пиктограммы представляет собой целочисленный идентификатор. Для реше ния проблемы преобразования целого числа в указатель на строку ресурса необ ходимо использовать макрос MAKEINTRESOURCE (make an integer into resource string), определенный в файле winuser.h следующим образом:
#define MAKEINTRESOURCE(i) (LPSTR)((DWORD)((WORD)(i)))
Этот макрос преобразует число в указатель, но при этом старшие 16 разрядов устанавливаются в нулевое значение. Так Windows узнает, что второй параметр функции LoadIcon является числом, а не указателем на символьную строку.
Например, для загрузки пиктограммы в программе Russia будет использовать ся следующий вызов:
LoadIcon(hInstance, MAKEINTRESOURCE(IDI_TRICOLOUR));
Если параметр hInstance имеет значение NULL, то функция LoadIcon исполь зуется для загрузки предопределенных пиктограмм. Возможные значения вто рого аргумента для предопределенных пиктограмм приведены в табл. 1.5 (гла ва 1). Эта возможность использовалась во всех предыдущих приложениях, так как в классе KWnd поле hIcon оконного класса wc инициализируется при помощи вызова LoadIcon(NULL, IDI_APPLICATION).
В случае успешного завершения функция LoadIcon возвращает дескриптор за груженной пиктограммы. В случае неудачи возвращается значение NULL. Если по каким то причинам LoadIcon не смогла загрузить указанную пиктограмму, то она загружает пиктограмму по умолчанию IDI_WINLOGO.
Обращаем ваше внимание на то, что функция LoadIcon предназначена для за грузки только стандартных пиктограмм. Поэтому не пытайтесь загрузить с ее по мощью малую пиктограмму (16 × 16). Иначе вас ждет горькое разочарование. Для загрузки пиктограмм других размеров используйте функцию LoadImage.
Функция LoadImage предназначена для загрузки изображений разных типов: пиктограмм, курсоров, битовых образов. Она имеет следующий прототип:
HANDLE LoadImage(HINSTANCE hinst, LPCTSTR lpszName, UINT uType, int cxDesired, int cyDesired, UINT fuLoad);
Второй параметр функции определяет загружаемое изображение. Если пара метр hinst не равен NULL и параметр fuLoad не содержит флаг LR_LOADFROMFILE, то параметр lpszName интерпретируется аналогично второму параметру функции
LoadIcon.
254 |
Глава 5. Ресурсы Windows-приложения |
|
|
Если параметр hinst равен NULL, а параметр fuLoad по прежнему не содержит флаг LR_LOADFROMFILE, то параметр lpszName специфицирует OEM изображение1. Идентификаторы OEM изображений определены в winuser.h и имеют следующие префиксы: OBM_ для растров, OIC_ для пиктограмм и OCR_ для курсоров.
Если параметр hinstравен NULL, а параметр fuLoadсодержит флаг LR_LOADFROMFILE, то lpszName задает имя файла, в котором хранится изображение загружаемого ре сурса.
Третий параметр, uType, определяет тип изображения и может принимать зна чения IMAGE_BITMAP, IMAGE_CURSOR и IMAGE_ICON.
Четвертый параметр, cxDesired, задает ширину изображения в пикселах. Если он равен нулю и параметр fuLoad содержит флаг LR_DEFAULTSIZE, то для вычисле ния ширины изображения функция использует значения метрики SM_CXICON или SM_CXCURSOR. Если же параметр равен нулю, а флаг LR_DEFAULTSIZE не использует ся, то функция использует фактическую ширину изображения.
Пятый параметр, cyDesired, задает высоту изображения в пикселах. Если он ра вен нулю и параметр fuLoad содержит флаг LR_DEFAULTSIZE, то для вычисления вы соты изображения функция использует значения метрик SM_CXICONили SM_CXCURSOR. Если же параметр равен нулю, а флаг LR_DEFAULTSIZE не используется, то функция использует фактическую высоту изображения.
Шестой параметр, fuLoad, позволяет указывать опции загрузки. Он может со держать один или несколько флагов, указанных в табл. 5.1 (приведены наиболее часто употребляемые флаги. Полный список см. в MSDN).
Таблица 5.1. Опции загрузки для функции LoadImage
Ôëàã |
Значение |
|
|
LR_DEFAULTCOLOR |
Флаг по умолчанию. Означает, что изображение не монохромное |
LR_CREATEDIBSECTION |
Если uType имеет значение IMAGE_BITMAP, то функция возвращает |
|
DIB-секцию |
LR_DEFAULTSIZE |
Влияет на интерпретацию четвертого и пятого параметров функции |
LR_LOADFROMFILE |
Влияет на интерпретацию второго параметра |
LR_MONOCHROME |
Изображение является черно-белым |
|
|
Вернемся к нашей программе Russia.
Чтобы обе загруженные пиктограммы — стандартная и малая — стали значка ми данного приложения, их дескрипторы должны быть присвоены полям hIcon и hIconSm структуры оконного класса главного окна приложения. Но так как в нашей программе главное окно создается при помощи объекта класса KWnd, то эти поля уже проинициализированы в конструкторе класса KWnd (см. текст файла KWnd.cpp). Поэтому решение заключается в модификации оконного класса при помощи функции SetClassLong. Модификация оконного класса производится всег да только в блоке обработки сообщения WM_CREATE, когда окно уже создано, но еще не показано на экране.
Новая редакция кода Russia.cpp приведена в листинге 5.2.
1 OEM — Original Equipment Manufacturers (производители оригинального оборудования).
Пиктограммы |
255 |
|
|
|
|
Листинг 5.2. Проект Russia (1-я редакция)
//////////////////////////////////////////////////////////////////////
// Russia.cpp #include <windows.h> #include "KWnd.h" #include "resource.h"
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //==================================================================== int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
MSG msg;
KWnd mainWnd("Russia today", hInstance, nCmdShow, WndProc, NULL, 0, 0, 400, 300);
while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg);
}
return msg.wParam;
}
//==================================================================== LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
HINSTANCE hInst;
HICON |
hIcon; |
// дескриптор стандартной пиктограммы |
HICON |
hIconSm; // дескриптор малой пиктограммы |
|
switch (uMsg)
{
case WM_CREATE:
hInst = GetModuleHandle(NULL);
hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_TRICOLOUR));
hIconSm = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_TRICOLOUR), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
SetClassLong(hWnd, GCL_HICON, (LONG)hIcon); SetClassLong(hWnd, GCL_HICONSM, (LONG)hIconSm); break;
case WM_DESTROY: PostQuitMessage(0); break;
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return 0;
}
//////////////////////////////////////////////////////////////////////
В блоке обработки сообщения WM_CREATE вызывается функция LoadIcon для загрузки стандартной пиктограммы и функция LoadImage для загрузки малой пик тограммы. Дескриптор экземпляра приложения hInst, который передается функ циям, определяется при помощи функции GetModuleHandle.
256 |
Глава 5. Ресурсы Windows-приложения |
|
|
Полученные дескрипторы hIcon и hIconSm передаются затем двум вызовам фун кции SetClassLong, которая модифицирует одноименные поля (hIcon, hIconSm)
вструктуре оконного класса mainWnd.wc главного окна приложения.
Втексте программы появилась также следующая директива:
#include "resource.h"
без которой имя IDI_TRICOLOUR было бы неизвестно компилятору.
После компиляции и запуска приложения на экран будет выведено окно про граммы с новой пиктограммой (рис. 5.10).
Рис. 5.10. Окно программы Russia (1-я редакция)
Курсоры
Курсоры — это изображения размером 32 × 32 пиксела, которые отмечают поло жение курсора (указателя) мыши. Курсоры во многом похожи на пиктограммы. Их главное отличие заключается в наличии активной точки (hotspot). Активной точкой называется пиксел, который принадлежит изображению курсора и отмечает его точное положение на экране в любой момент времени. В стандарт ном курсоре, имеющем вид стрелки, активная точка расположена в левом верх нем углу курсора.
Технологию использования в приложении курсоров, определенных програм мистом, продемонстрируем, продолжая разработку программы Russia.
В новой редакции программа будет изменять форму курсора мыши в зависи мости от того, в какой зоне клиентской области он находится. В основном курсор мыши будет иметь форму перекрестья, которая задается предопределенным кур сором IDC_CROSS. Но при приближении к верхней границе клиентской области курсор будет принимать форму стрелки, направленной вверх, а при приближе нии к нижней границе клиентской области — форму стрелки, направленной вниз. Кроме того, в окне программы будет отображаться информация о текущей пози ции курсора, связанной с его активной точкой. Таким образом, к проекту нужно добавить два ресурса курсоров с идентификаторами IDC_UP и IDC_DOWN.
Процедура создания нового курсора в графическом редакторе очень похожа на рассмотренную выше процедуру создания пиктограммы. На первом шаге в диалоговом окне Insert Resource вместо типа ресурса Icon выбирается тип Cursor. Вызванный графический редактор будет работать в режиме создания курсора.
На этапе рисования, после того как будет создано изображение курсора, необ ходимо определить его активную точку. Например, при создании курсора IDC_UP окно графического редактора с созданным изображением показано на рис. 5.11.
Курсоры |
257 |
|
|
|
|
Рис. 5.11. Результат рисования для курсора IDC_UP
В отличие от окна графического редактора, работающего в режиме создания пиктограммы, в этом окне есть кнопка Set Hotspot, располагающаяся на правом краю панели инструментов. Координаты активной точки отображаются слева от этой кнопки и по умолчанию равны (0, 0). Позиция активной точки указывается всегда относительно левого верхнего угла изображения.
Чтобы назначить активную точку, нужно нажать кнопку Set Hotspot, а затем щелкнуть мышью на том пикселе изображения, который должен стать активной точкой. Для нашего курсора это будет пиксел на верхнем окончании стрелки. После указанных действий надпись слева от кнопки примет вид Hot spot: 15, 0.
Аналогичные действия повторим и для курсора IDC_DOWN. Но теперь активной точкой будет пиксел на нижнем конце стрелки (рис. 5.12).
Рис. 5.12. Определение активной точки для курсора IDC_DOWN
Сохраните новые ресурсы в файле описания ресурсов, выполнив команду меню File Save. Если теперь открыть файл Russia.rc в текстовом режиме, то можно уви деть две новые строчки с определениями:
IDC_UP |
CURSOR |
DISCARDABLE |
"up.cur" |
IDC_DOWN |
CURSOR |
DISCARDABLE |
"down.cur" |
Завершив определение ресурсов с курсорами, займемся кодом программы. Необходимо определить дескрипторы используемых курсоров (типа HCURSOR)
и загрузить ресурсы при помощи функции LoadCursor, вызов которой аналогичен вызову функции LoadIcon.
258 |
Глава 5. Ресурсы Windows-приложения |
|
|
В нашей программе будут использоваться три курсора: hCursor для вывода пе рекрестья (предопределенный курсор IDC_CROSS), hCursorUp для вывода стрелки вверх (IDC_UP) и hCursorDown для вывода стрелки вниз (IDC_DOWN).
Курсор hCursor должен стать основным курсором приложения. Для этого нуж но модифицировать соответствующее поле оконного класса, вызвав следующую функцию:
SetClassLong(hWnd, GCL_HCURSOR, (LONG)hCursor);
Для динамического изменения формы курсора в зависимости от его местона хождения применяется функция SetCursor:
HCURSOR SetCursor(HCURSOR hCursor);
Функция делает текущим курсор, который передается ей в качестве парамет ра. При этом возвращается дескриптор предшествующего курсора.
Отслеживание положения курсора обычно осуществляется при обработке со общения WM_MOUSEMOVE. Параметр оконной процедуры lParam в этот момент со держит координаты текущей позиции курсора мыши x и y, которые размещаются в младшем и старшем словах параметра соответственно. Эта позиция определяет ся относительно левого верхнего угла клиентской области.
Вторая редакция файла Russia.cpp приведена в листинге 5.3.
Листинг 5.3. Проект Russia (2-я редакция)
//////////////////////////////////////////////////////////////////////
// Russia.cpp #include <windows.h> #include <stdio.h> #include "KWnd.h" #include "resource.h"
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //==================================================================== int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
MSG msg;
KWnd mainWnd("Russia today", hInstance, nCmdShow, WndProc, NULL, 0, 0, 400, 300);
while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg);
}
return msg.wParam;
}
//==================================================================== LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
HINSTANCE hInst; HICON hIcon, hIconSm;
static HCURSOR hCursor, hCursorUp, hCursorDown;
static int xPos, yPos; // координаты горячей точки курсора мыши static int wClient, hClient; // размеры клиентской области окна HDC hDC;
PAINTSTRUCT ps; char text[100]; RECT rect;
Курсоры |
259 |
|
|
|
|
SetRect(&rect, 10, 0, 200, 30);
switch (uMsg)
{
case WM_CREATE:
hInst = GetModuleHandle(NULL);
hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_TRICOLOUR));
hIconSm = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_TRICOLOUR), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
SetClassLong(hWnd, GCL_HICON, (LONG)hIcon); SetClassLong(hWnd, GCL_HICONSM, (LONG)hIconSm);
hCursor = LoadCursor(NULL, IDC_CROSS); SetClassLong(hWnd, GCL_HCURSOR, (LONG)hCursor); hCursorUp = LoadCursor(hInst, MAKEINTRESOURCE(IDC_UP));
hCursorDown = LoadCursor(hInst, MAKEINTRESOURCE(IDC_DOWN)); break;
case WM_SIZE:
wClient = LOWORD(lParam); hClient = HIWORD(lParam); break;
case WM_MOUSEMOVE:
xPos = LOWORD(lParam);
yPos = HIWORD(lParam); if (yPos < 16)
SetCursor(hCursorUp); if (yPos > hClient - 16)
SetCursor(hCursorDown); InvalidateRect(hWnd, &rect, TRUE); break;
case WM_PAINT:
hDC = BeginPaint(hWnd, &ps);
sprintf(text, "xPos = %d, yPos = %d\0", xPos, yPos); DrawText(hDC, text, -1, &rect, DT_LEFT); EndPaint(hWnd, &ps);
break;
case WM_DESTROY: PostQuitMessage(0); break;
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return 0;
}
//////////////////////////////////////////////////////////////////////
Ширина wClient и высота hClient клиентской области окна определяются прило жением при обработке сообщения WM_SIZE. Величина hClient используется затем в блоке обработки сообщения WM_MOUSEMOVE, чтобы определить область в нижней части окна, где курсор должен принять форму стрелки, указывающей вниз.
Вид окна работающей программы, когда курсор находится у верхнего края клиентской области, показан на рис. 5.13.
260 |
Глава 5. Ресурсы Windows-приложения |
|
|
Рис. 5.13. Программа Russia c курсорами, определенными программистом
Еще один момент, на который хотелось бы обратить ваше внимание, — это вы зов функции InvalidateRect в конце блока обработки сообщения WM_MOUSEMOVE:
InvalidateRect(hWnd, &rect, TRUE);
Этот вызов необходим, чтобы сделать недействительной, то есть требующей обновления, часть клиентской области. В результате указанного вызова система сгенерирует сообщение WM_PAINT. Обрабатывая это сообщение, приложение вы зывает функцию DrawText для отображения текста.
Чтобы исключить наложение нового текста на текст, оставшийся от предыду щего акта рисования, нужно стереть предыдущее изображение, прежде чем выво дить новое. Система Windows сделает это самостоятельно, выполняя вызов функ ции BeginPaint, но только при одном условии. «Виновница» генерации сообщения WM_PAINT — функция InvalidateRect — должна быть вызвана с третьим парамет ром, равным TRUE.
Также особое внимание следует обратить на второй аргумент в вызове функ ции InvalidateRect. Он указывает, что обновляемым регионом будет только неболь шой прямоугольник, в котором размещается текст. Если бы использовалось зна чение NULL, то перерисовке подверглась бы вся клиентская область. Вы не заметите разницы, пока большая часть окна занята фоном и в окне не отображаются другие растровые изображения. Во всех других случаях перерисовка всей клиентской области вызывает неприятное мерцание.
Растровые образы
В главе 3 уже достаточно подробно рассматривалось использование в Windows про граммировании растровых битовых образов или точечных рисунков. Там же отмеча лось, что DDB растры могут загружаться из ресурсов приложения. Фактически, пик тограммы и курсоры тоже являются особыми видами точечных рисунков.
Растровые образы чаще всего используются для решения двух классов задач. Прежде всего, с их помощью производится отображение на экране картинок. На пример, файлы драйверов дисплеев в Windows содержат множество небольших битовых образов, которые используются для рисования стрелок в полосах про крутки, галочек в раскрывающихся меню, изображений флажков, переключате лей и других служебных изображений.
