Смекни!
smekni.com

Подклассы окон (стр. 2 из 4)

HRSRC FindResource( hInstance, lpszName, lpszType );

HGLOBAL LoadResource( hInstance, hrSrc );

Первая функция позволяет получить промежуточный хендл описания ресурса, а вторая - загрузить ресурс память и получить хендл глобального блока памяти, содержащего ресурс. Если Вы декларировали ресурс как LOADONCALL, то физическое размещение ресурса в памяти произойдет не при вызове функции LoadResource, а при непосредственном обращении к ресурсу.

Если для задания имен ресурса или типа вы использовали текст, то параметры lpszName и lpszType являются указателями на соответствующие строки; если же используются номера, то вы можете их указывать двумя способами - передав строку, начинающуюся на #, например, “#123”, либо разместив в младшем слове адреса нужный номер, а старшем 0. Последний механизм реализуется с помощью макроса:

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 обозначает пункт меню, связанный с подсказкой.

Для использования меню совместно с окном мы можем воспользоваться любым удобным способом:

1) при регистрации класса окна мы можем указать имя требуемого ресурса. Тогда все окна этого класса при создании получат указанное меню.

2) мы можем указать хендл меню при создании окна, тогда это окно будет создано с указанным меню.

3) в любой момент мы можем вызвать функцию

BOOL SetMenu( hWnd, hMenu );

с помощью которой мы можем установить новое меню, заменить одно на другое или удалить имеющееся (указав hMenu=NULL).

Во время работы мы можем легко получить хендл меню, используемого данным окном:

HMENU GetMenu( hWnd );