48065 (597378), страница 2
Текст из файла (страница 2)
LPSTR MAKEINTRESOURCE( nId );
Этот способ считается самым эффективным, тем более, что Вы можете применять символические имена для задания номеров. При необходимости чтения данных ресурса Вы должны его зафиксировать в памяти с помощью процедуры
LPVOID LockResource( hGlobResource );
и после доступа к данным разрешить его перемещение:
BOOL UnlockResource( hGlobResource );
(Это не отдельная процедура, а обычный GlobalUnlock). После использования ресурса его можно удалить с помощью процедуры:
BOOL FreeResource( hGlobResource );
Когда Вы применяете ресурсы какого-либо типа, предусмотренного Windows, то приходится применять несколько другие способы доступа к данным, связанные с необходимостью специальной обработки таких ресурсов. Можно выделить следующие основные типы ресурсов:
ACCELERATORS – таблица акселераторов клавиатуры; для загрузки применяется функция
HACCEL LoadAccelerators( hInstance, lpszAccName );
BITMAP – битмап, включенный в приложение для загрузки применяется функция
HBITMAP LoadBitmap( hInstance, lpszBitmapName );
CURSOR – ресурс, представляющий курсор мыши для загрузки применяется функция
HCURSOR LoadCursor( hInstance, lpszCursorName );
DIALOG – диалог с ресурсами типа DIALOG и с самими диалогами мы разберемся позже.
FONT – включение шрифтового ресурса о применении шрифтов мы говорили ранее. Включать ресурс этого типа в Ваше приложение следует специфическим способом, существенно отличающимся от остальных ресурсов.
ICON – иконка для загрузки применяется функция
HICON LoadIcon( hInstance, lpszIconName );
MENU – меню, которое может быть назначено к окну для загрузки применяется функция
HMENU LoadMenu( hInstance, lpszMenuName );
STRINGTABLE – таблица строк ресурс этого типа вообще не загружается целиком. Он представляет собой таблицу строк, имеющих идентификаторы, и обеспечивает доступ к конкретной строке по ее идентификатору. Реально ресурсу этого типа соответствует не блок данных в памяти, а, может быть, несколько - для каждых 16 строк (по порядку номеров) выделяется отдельный блок. Приложение может содержать только один ресурс этого типа, поэтому при описании таблицы строк в файле описания ресурсов ее имя не указывается - указывается только тип этого ресурса. Для доступа к строкам применяется функция
int LoadString( hInstance, idString, lpszBuff, nmaxCount );
Мы достаточно близко познакомились с ресурсами типа BITMAP и FONT; практически можно считать что мы знакомы и с ресурсами типа CURSOR и ICON, так как они описываются так‑же, как и BITMAP. Сейчас нам надо лучше разобраться с тремя новыми типами – ACCELERARTORS, MENU и DIALOG.
Акселераторы
Акселераторы представляют собой простейшее средство для связывания определенных комбинаций клавиш с конкретными действиями. Можно считать, что акселераторы представляют собой таблицу, в которой записываются нажимаемые клавиши и генерируемые ими сообщения.
Точнее, акселераторы генерируют только сообщение WM_COMMAND, указывая более подробную информацию в параметрах этого сообщения. Параметр wPar сообщения содержит идентификатор, назначенный клавише, а параметр lPar всегда равен 0x00010000L.
Для создания таблицы акселераторов Вы должны поместить в файле описания ресурсов соответствующий ресурс:
AccName ACCELERATORS [load-opt] [mem-opt]
BEGIN
key, id [, type] [, options]
...
END
параметры могут быть следующими:
key определяет назначаемую клавишу
id посылаемый код извещения
type тип клавиши ASCII, VIRTKEY или опущен
options указывает состояние специальных клавиш и некоторые действия: NOINVERT, ALT, SHIFT, CONTROL или опущен.
подробнее рассмотрим назначение акселераторов на примере:
“A”, 100 // послать извещение 100 при нажатии А
65, 100, ASCII // то же самое, ASCII код 65 соответствует А
“^A”, 101 // послать 101 при нажатии Ctrl-A
“A”, 101, CONTROL // то же самое
VK_SPACE, 102, VIRTKEY // послать 102 при нажатии Space
VK_SPACE, 103, VIRTKEY, SHIFT // послать 103 при нажатии Shift-Space
Несколько слов следует сказать о применении акселераторов в приложении. Сам факт загрузки акселератора в память еще не обозначает его применения. Для того, что бы сообщения от клавиатуры начали обрабатываться акселератором надо в главном цикле обработки сообщений включить специальлные средства для их трансляции.
int TranslateAccelerator( hWnd, hAccel, lpMSG );
Параметр hWnd указывает окно, которое будет получать извещения, hAccel задает хендл таблицы акселераторов, lpMSG - адрес структуры MSG, содержащей сообщение.
При обычном применении акселератора извлеченное из очереди сообщение передается в эту функцию. Если это сообщение клавиатуры и данное нажатие на клавишу транслируется акселератором, то указанное окно получает сообщение WM_COMMAND и процедура возвращает TRUE; во всех остальных случаях возвращается FALSE, говоря о том, что сообщение не было трансировано в другое. Считается, что если сообщение было обработано акселератором, то дальнейшая его обработка не требуется - то есть обычный процесс трансляции и диспетчеризации этого сообщения исключается. При этом главный цикл обработки сообщений приобретает следующий вид:
MSG msg;
HACCEL hAccel;
HWND hWnd;
...
hAccel= LoadAccelerators( hInstance, “AccName” );
...
while ( GetMessage( &msg, NULL, NULL, NULL ) ) {
if ( !hAccel || !TranslateAccelerator( hWnd, hAccel, &msg ) ) {
TranslateMessage( &msg );
DispatchMessage( &msg );
}
}
...
Загруженные акселераторы автоматически удаляются при завершении приложения.
Меню
Еще одна разновидность ресурсов, которую мы должны сейчас рассмотреть – меню. Меню, предоставляемое Windows имеет иерархическую организацию. Основное меню всегда представлено строкой в верхней части окна, из него могут “выпадать” вертикальные меню, связанные с конкретным пунктом, и так далее - причем все уровни меню, кроме верхнего, представлены вертикальными меню.
Меню может быть описано как с помощью ресурсов, так и программно, причем существующее меню всегда может быть изменено. При работе с меню наше приложение будет получать следующие сообщения:
WM_ENTERMENUIDLE когда меню было активизировано и находится в состоянии ожидания.
WM_MENUSELECT посылается окну, использующему меню, как извещение о выборе пункта меню.
WM_MENUCHAR информирует окно о том, что при работе с меню была нажата кнопка не соответствующая никакому пункту меню. Обрабатывая это сообщение Вы можете вернуть номер пункта меню который надо выбрать, указать Windows о том, что работа с меню закончена или потребовать короткий звуковой сигнал.
WM_COMMAND посылается окну, извещая его о выборе требуемого пункта меню. Параметр wPar содержит идентификатор пункта меню, а lPar равен 0L. Обычно при работе с меню обрабатывается только сообщение WM_COMMAND, остальные применяются в специальных случаях.
Сейчас мы можем подвести некоторый итог под применением сообщения WM_COMMAND, которое может быть получено от дочернего окна, акселератора или меню:
| wPar | LOWORD(lPar) | HIWORD(lPar) | |
| окно | Id | hWndChild | wCode |
| акселератор | Id | 0 | 1 |
| меню | Id | 0 | 0 |
При работе с системным меню вместо сообщения WM_COMMAND мы будем получать сообщения WM_SYSCOMMAND. При описании меню в ресурсе текст описания меню должен размещаться в файле описания ресурсов в следующей форме:
MenuName MENU [load-opt] [mem-opt]
BEGIN
определения пунктов меню 0-го уровня:
MENUITEM для определения пункта
POPUP для определения пункта, связанного с меню следующего уровня
BEGIN
определение пунктов меню 1-го уровня
...
END
END
Для определения пункта меню, связанного с меню следующего уровня мы должны использовать следующую форму записи:
POPUP text [, options]
BEGIN
...
END
Для задания обычного пункта меню, то есть посылающего WM_COMMAND при его выборе, мы должны использовать следующую форму записи:
MENUITEM text, id [, options]
В этих случаях приняты следующие обозначения:
text задает текст пункта меню в виде строки взятой в двойные кавычки, один из символов строки может предваряться символом &, который приводит к подчеркиванию этого символа и его автоматической интерпретации как акселератора.
id определяет идентификатор пункта меню
options указывает на некоторые возможные характеристики данного пункта меню:
CHECKED пункт меню отмечен галочкой. (невозможно для меню 0-го уровня)
INACTIVE пункт меню неактивен (его нельзя выбрать), но рисуется обычным способом
GRAYED пункт меню неактивен и нарисован серым цветом
MENUBREAK пункт меню размещен либо в новой строке (для уровня 0), либо в новом столбце.
MENUBARBREAK то же, что и MENUBREAK, но столбец (строка) отделяется сплошной чертой
HELP обозначает пункт меню, связанный с подсказкой.
Для использования меню совместно с окном мы можем воспользоваться любым удобным способом:
-
при регистрации класса окна мы можем указать имя требуемого ресурса. Тогда все окна этого класса при создании получат указанное меню.
-
мы можем указать хендл меню при создании окна, тогда это окно будет создано с указанным меню.
-
в любой момент мы можем вызвать функцию
BOOL SetMenu( hWnd, hMenu );
с помощью которой мы можем установить новое меню, заменить одно на другое или удалить имеющееся (указав hMenu=NULL).
Во время работы мы можем легко получить хендл меню, используемого данным окном:
HMENU GetMenu( hWnd );
и, зная хендл меню, столь же легко можем узнать хендл меню следующего уровня:
HMENU GetSubMenu( hMenu, nPos );
здесь параметр ‘nPos’ указывает номер пункта меню, связанного с меню следующего уровня.
Вы можете создать новое пустое меню, которое можно использовать как в качестве меню верхнего уровня, так и в качестве меню других уровней. Это определяется только его применением. Если Вы его добавите к другому меню, то оно будет POPUP меню, а если Вы его назначите окну, то оно будет меню верхнего уровня. Для создания нового меню предназначена функция
HMENU CreateMenu( void );
Кроме того мы можем узнать хендл системного меню данного окна:
HMENU GetSystemMenu( hWnd, FALSE );
с помощью которого мы можем добавить новые пункты к системному меню, изменить или удалить прежние. При коррекции меню можно использовать два разных способа задания пункта меню:
-
по его идентификатору (пункт, связанный с меню следующего уровня не имеет идентификатора, поэтому не может быть указан этим способом).
При выборе этого способа Вы должны указать флаг MF_BYCOMMAND при указании пункта меню.
-
по его номеру в меню. В этом случае Вы должны указать флаг MF_BYPOSITION при задании пункта.
При необходимости корректировать меню мы можем воспользоваться следующими функциями:
BOOL AppendMenu( hMenu, nFlags, idNew, lpszNewName );
BOOL InsertMenu( hMenu, idItem, nFlags, idNew, lpszNewName );














