- Типы меню операционной системы windows
- Система меню Windows
- Управление меню
- Обозначения, принятые в меню
- Главное меню
- Способы вызова Главного меню:
- Контекстное меню
- Способы вызова контекстного меню:
- Строка меню окна
- Способы вызова строки меню
- Системное меню
- Способы вызова системного меню:
- Команды системного меню
- Операционная система Microsoft Windows 3.1 для программиста
- 1. Меню
- 1.1. Классификация типов меню
- 1.2. Создание меню при помощи шаблона
- Создание шаблона меню
- Подключение меню к окну приложения
- Подключение меню при регистрации класса окна
- Подключение меню при создании окна
- 1.3. Сообщения, поступающие от меню
- Сообщение WM_INITMENU
- Сообщение WM_INITMENUPOPUP
- Сообщение WM_COMMAND
- Сообщение WM_SYSCOMMAND
- 1.4. Приложение MENU
- 1.5. Функции для работы с меню
- Создание меню
- Добавление строк
- Изменение строк
- Удаление строк
- Активизация и блокирование строк меню
- Отметка строк
- Выделение строк
- Получение информации
- Идентификатор меню
- Идентификатор временного меню
- Проверка идентификатора меню
- Количество элементов в меню
- Идентификатор элемента меню
- Текст строки меню
- Флаги состояния элемента меню
- 1.6. Приложение DMENU
- 1.7. Системное меню
- 1.8. Плавающее меню
- 1.9. Использование плавающего меню в органе управления EDIT
- 1.10. Акселераторы
- Описание таблицы акселераторов
- Загрузка таблицы акселераторов
- Изменения в цикле обработки сообщений
- 1.11. Орган управления TOOLBAR
- 1.12. Приложение SMARTPAD
- 1.13. Графика в меню
- 1.14. Приложение GMENU
Типы меню операционной системы windows
Рис. SEQ Рис. \* ARABIC 1 . Основное меню Windows.
В операционной системе Windows используется несколько видов меню.
1. Основное меню (меню кнопки «Пуск») показано на рис.1. Оно вызывается щелчком по кнопке «Пуск» и вид его зависит от настроек пользователя. Его опции:
§ Завершение работы – завершениеработы , перезагрузки компьютера, входа под другим паролем
§ Выполнить – можно загрузить на выполнение программу, которая отсутствует в меню «Программы»
§ Справка и поддержка – можно получить справку по системе Windows
§ Найти – позволяет находить информацию на данном компьютере или в Интернете
§ Настройка – позволяет изменять параметры устройств подключенных к данному компьютеру
§ Документы – открывает список последних 15 документов, открывавшихся на данном компьютере под данным паролем
§ Программы – открывает список программ, которые установлены на данном компьютере, для загрузки.
Остальные опции меню говорят сами за себя.
Рис. 2 . Системное меню .
Системное меню (вызов – щелчок по пиктограмме окна в строке названия (левый рисуночек в синей строке окна)). Позволяет управлять окнами Windows, используя клавиатуру (если не видны кнопки правого верхнего угла окна (кнопки «Свернуть», «Развернуть», «Закрыть»)). Можно использовать, если мышь почему либо не работает.
Рис. 3. Вид командного меню приложения Word .
Командное меню приложения (во всех окнах приложений строка меню). Число и содержание опций командного меню разное у разных программ. Например, у программы текстового процессора Word это опции «файл», «правка», «вид», «вставка», «формат», «сервис», «таблица», «окно», «помощь».
Рис. 4. Командное меню объекта
4. Командное меню объекта (файл_правка_вид_?). Показано на рисунке 4 для окна «Мой компьютер»
Рис. 5. Инструментальное меню.
Пиктографическое меню . Можно встретить и другие названия: меню инструментов, инструментальное меню. Инструментальное меню по сути дублирует командное меню, но в отличие от него предоставляет прямой доступ к соответствующей опции. При использовании же командного меню пришлось бы сделать несколько щелчков, добираясь до нужной опции.
Рис. 6. Контекстное меню
6 . Контекстное меню (рис.6.) вызывается всегда правым щелчком мыши. Для каждого объекта контекстное меню имеет другой вид, поэтому его еще называют контекстно-зависимым. Этот вид меню, наверно, самый используемый. Практически все операции над объектами можно сделать, используя контекстное меню.
7. Всплывающее (распашное) меню (рис.7). Вызывается щелчком по соответствующей пиктограмме. Выбор подопций производится аналогично остальным видам меню.
Система меню Windows
Меню – набор объединенных по функциональному признаку пунктов, каждый их которых обозначает команду или подменю, которое можно открыть щелчком на пункте.
Если подменю имеется, то меню получается иерархическим (многоуровневым). Многоуровневые меню представляются на экране по-разному и в связи с этим делятся на горизонтальные (каскадные – открываются слева или справа) и вертикальные. Вертикальные меню в свою очередь подразделяются на ниспадающие и всплывающие.
При работе в Windows пользователю доступны меню четырех разновидностей:
- Главное меню системы (или меню Пуск);
- контекстное меню различных объектов;
- строка меню окна;
- системное меню окон.
Управление меню
Правила работы с меню и принятые в них обозначения идентичны.
Для перемещения по пунктам строки меню (или по ниспадающему меню) когда открыт любой из пунктов, достаточно передвигать указатель мыши или нажимать клавиши-стрелки.
Горизонтальные линии в меню не влияют на работу меню. Они служат только для визуального выделения групп команд со схожими функциями.
Для выполнения команды меню достаточно щелкнуть левой кнопкой мыши или нажать клавишу на выделенной команде.
Чтобы отказаться от меню, не выбирая никакой команды, достаточно щелкнуть мышью где-нибудь вне области меню или нажать клавишу (или ).
Обозначения, принятые в меню
Для всех меню Windows принята унифицированная система обозначений:
- Блеклый цвет в записи команды означает, что команда недоступна в данный момент (например, если не выделен объект для копирования, то команда Копировать недоступна).
- Если команда заканчивается многоточием (. ), значит, при выборе этой команды откроется диалоговое окно с запросом параметров.
- Помеченная галочкой (
) команда обозначает действующий режим (флажок). Выбор команды отменяет режим. Повторный выбор – восстанавливает режим.
- Стрелка (
) после имени команды означает, что при выборе этой команды появится подменю.
- Кружок (
) означает выбор одного из альтернативных режимов, которые представлены в соседних командах («переключатель»).
- Если возле имени команды указана клавиша или комбинацияклавиш, значит, данная команда может быть выполнена нажатием этих клавиш (их называют клавиши — акселераторы).
Главное меню
Главное меню – один из основных системных элементов управления Windows. При помощи Главного меню можно запустить все программы, установленные под управлением операционной системы или зарегистрированные в ней, открыть последние документы, с которыми выполнялась работа, получить доступ ко всем средствам настройки, а также к поисковой и справочной системам Windows. (Структуру Главного меню в стиле ХР см. в разделе Настройка Главного меню в стиле ХР, в классическом стиле – см. в [1, 2]). В классическом стиле Главного меню доступ к программ осуществляется с помощью пункта меню Программы, в стиле ХР – Все программы. Главное меню относится к иерархическим всплывающим каскадным меню.
Способы вызова Главного меню:
- щелчок на кнопке Пуск в Панели задач;
- нажатие клавиши
– ;
- сочетанием клавиш + .
Контекстное меню
Так называется меню, появляющееся после щелчка правой кнопкой мыши на объекте или элементе управления. Контекстным меню называется потому, что перечень пунктов в нем определяется типом объекта, на котором произошел щелчок, т.е. зависит от контекста.
В контекстном меню приведены все действия, которые можно выполнить над данным объектом. Более того, во всех контекстных меню любых объектов имеется пункт Свойства, который позволяет просматривать и изменять свойства объектов, то есть выполнять настройки программ, устройств и самой операционной системы. Контекстное меню относится к иерархическим всплывающим каскадным меню.
Способы вызова контекстного меню:
- щелчок правой кнопкой мыши на объекте или элементе управления;
- нажатие клавиши
– ;
- сочетанием клавиш + .
Строка меню окна
Окна папок и окна приложений имеют строку меню, расположенную под заголовком окна. Выбор пункта меню вызывает «ниспадающее» меню. Диалоговые и вторичные окна не имеют строки меню.
Если в нижней части меню находится кнопка , то в меню выведены не все команды, а только те, которые использовались последними. При нажатии на эту кнопку появятся все команды этого меню.
Способы вызова строки меню
Кроме того, сделать активной строку меню можно с помощью клавиатуры, нажав одну из клавиш:
Системное меню
Кроме обычной строки меню, все окна Windows имеют так называемое системное меню. Команды системного меню предназначены для выполнения действий по управлению окном в частности с помощью клавиатуры
Способы вызова системного меню:
- щелчок на системном значке, расположенном в левой части строки заголовка окна;
- сочетанием клавиш + ;
- контекстное меню строки заголовка.
Команды системного меню
Восстановить – соответствует кнопке восстановления размера.
Переместить – соответствует операции перетаскивания мышью. Команда доступна, если окно не максимизировано. При выборе этой команды в окне появляется перекрестная стрелка. Для перемещения окна следует нажимать клавиши управления курсором в нужном направлении или, нажав один раз клавишу-стрелку, просто переместить мышь. Закончить перемещение следует клавишей . Клавиша отменит перемещение и вернет окно на прежнее место экрана.
Размер – соответствует операции перетаскивания границы окна мышью. Выполняется аналогично предыдущей команде.
Свернуть – соответствует кнопке минимизации окна. Кнопка свернутого окна отображается в Панели задач.
Развернуть – соответствует кнопке максимизации окна. Разворачивает окно до максимального размера (на весь экран).
Закрыть – закрывает программу, т.е. приводит к тому же результату, что и двойной щелчок по кнопке системного меню.
Диалоговые окна не имеют кнопки системного меню (системного значка). Для его вызова используются только два последних способа. В этом случае меню состоит из двух пунктов: Переместить и Закрыть.
Copyright © 2008-2010
Ющик Е.В. All Rights Reserved
Операционная система Microsoft Windows 3.1 для программиста
1. Меню
В этой главе мы выполним классификацию типов меню , научим вас создавать, изменять и удалять меню в приложениях Windows.
Вы знаете, что меню используются в приложениях Windows для выбора отдельных команд или изменения режимов работы приложений. Программный интерфейс Windows обеспечивает сильную поддержку меню, так как меню — важный элемент пользовательского интерфейса.
Создавая меню в программах MS-DOS, вы были вынуждены либо приобретать специальные библиотеки функций или другие средства (C Tools, Turbo Vision, Vitamin C и т. п.), либо создавать свои функции для работы с меню.
Для того чтобы создать меню в приложении Windows, вам достаточно разработать его внешний вид и создать шаблон при помощи редактора Resource Workshop или аналогичного средства графического проектирования элементов пользовательского интерфейса. Шаблон меню следует записать в ресурсы приложения, после чего за работу меню отвечает операционная система Windows. Когда вы выбираете строку из меню, ваше приложение получает сообщение WM_COMMAND. Это сообщение содержит идентификатор выбранной строки.
Таким образом, при создании приложения, работающего с меню, задача программиста сводится к определению обработчика сообщения WM_COMMAND, поступающего от меню. Вы можете выбирать из меню при помощи мыши или клавиатуры, при этом сам процесс выбора (т. е. выделение строк меню, показ временных меню и т. п.) обеспечивается операционной системой Windows. Ваше приложение получает сообщение о том, что сделан выбор той или иной строки из меню, но для обеспечения работы приложения программисту нет необходимости знать, каким именно способом был сделан выбор.
Прежде чем приступить к описанию средств операционной системы Windows, предназначенных для работы с меню, мы расскажем о том, какие стандартные типы меню можно создать в приложениях Windows. Вы также можете создать свои собственные, нестандартные типы меню, работающие так, как это должно быть с вашей точки зрения. Однако нестандартные элементы диалогового интерфейса могут затруднить работу пользователя с приложением и вступить в противоречие с концепцией стандартного пользовательского интерфейса.
1.1. Классификация типов меню
При создании окна в приложении Windows вы можете указать, что окно должно иметь меню. Обычно меню создается в главном окне приложения. Такое меню мы будем называть меню приложения .
На рис. 1.1 показано главное окно стандартного приложения Paintbrush, имеющее меню.
Рис. 1.1. Меню приложения Paintbrush
На этом рисунке меню приложения Paintbrush располагается ниже заголовка окна. Меню содержит отдельные элементы, или строки («File», «Edit», «View», и т. д.), расположенные в полосе меню (menu bar ).
Строки меню могут быть использованы либо для выбора команд, либо для активизации дополнительных временных меню (pop-up menu ). Как правило, строки меню приложения используются только для активизации временных меню, но не для выполнения команд. Некоторые строки меню могут отображаться серым цветом. Это заблокированные строки, которые не могут быть выбраны.
Временное меню (рис. 1.2) появляется на экране после выбора строки в меню приложения.
Рис. 1.2. Временное меню
Временное меню содержит строки, расположенные в столбец. Для выбора строки из временного меню вы можете воспользоваться мышью или клавишами перемещения курсора по вертикали и . В последнем случае для завершения выбора следует нажать клавишу . Можно также воспользоваться клавишей и клавишей, соответствующей подчеркнутой букве в нужной строке.
Строки временного меню могут быть отмечены галочкой (рис. 1.2). Такие строки обычно используются как переключатели, изменяющие режим работы приложения. Например, если в меню «View» приложения Paintbrush выбрать строку «Cursor Position», слева от строки будет нарисована галочка, а в окне Paintbrush вы увидите текущие координаты курсора мыши. Если выбрать эту же строку еще раз, галочка пропадет. Режим отображения координат курсора будет выключен.
Мы уже говорили, что режимы работы приложения обычно задаются при помощи диалоговых панелей. Однако в простых случаях можно воспользоваться и строками меню.
Если выбор строки меню приводит к выполнению команды (например, команды создания документа, завершения работы приложения, копирования фрагмента документа в универсальный буфер обмена Clipboard и т. д.), строка меню содержит краткое название выполняемой команды, например, «New», «Copy», и т. д. Если же при выборе строки на экране появляется диалоговая панель, к слову справа добавляется многоточие (рис. 1.3). Последнее соглашение не является обязательным, однако вы должны ему следовать для обеспечения стандартного пользовательского интерфейса.
Рис. 1.3. Меню «File» приложения Paintbrush
Вы можете создавать многоуровневые меню . На рис. 1.4. мы привели внешний вид многоуровневого меню из приложения Borland Turbo C++ for Windows версии 3.1. Если из меню «Options» выбрать строку, отмеченную символом ««, на экране появится меню второго уровня.
Рис. 1.4. Многоуровневое меню
Можно использовать многократную вложенность меню. Однако мы не советуем вам увлекаться сложными многоуровневыми меню, так как ими трудно пользоваться. В частности, систему настройки параметров Borland Turbo C++ for Windows версии 3.1 трудно назвать удобной в использовании. В Borland C++ for Windows версии 4.01 используется более удобный способ, основанный на применении диалоговых панелей (рис. 1.5).
Рис. 1.5. Диалоговая панель настройки параметров в Borland C++ for Windows версии 4.01
При помощи динамически изменяемого списка «Topics» вам предоставляется возможность выбора нужной группы параметров. В правой части диалоговой панели отображаются переключатели и другие органы управления, соответствующей выбранной группе параметров. Если вы выберете другую группу параметров, вид правой части диалоговой панели изменится соответствующим образом. Такая система настройки параметров намного удобнее многоуровневых меню, использованных в предыдущих версиях Borland C++.
Каждое стандартное приложение Windows имеет системное меню , которое можно вызвать щелчком левой клавиши мыши по окну активизации системного меню, расположенному слева от заголовка окна либо при помощи комбинации клавиши и клавиши пробела (рис. 1.6).
Рис. 1.6. Системное меню приложения Paintbrush
Как правило, системное меню любого стандартного приложения содержит строки, показанные на рис. 1.6. С помощью системного меню вы можете минимизировать (строка «Minimize») или максимизировать («Maximize») главное окно приложения, восстанавливать размер этого окна («Restore»), перемещать окно («Move») или изменять его размер («Size»), закрывать окно («Close») и переключаться на другие приложения («Switch To. «). Ваше приложение может изменять системное меню, дополняя его новыми строками или горизонтальными разделительными линиями, удалять строки из существующего меню.
Приложение может создать меню в любом месте экрана. На рис. 1.7 показано меню внутри окна редактирования текста, созданное в среде разработки программ Borland C++ for Windows версии 4.01 щелчком правой клавиши мыши.
Рис. 1.7. Меню внутри окна приложения Borland C++ for Windows версии 4.01
Такое меню называют плавающим (floating menu ), подчеркивая тот факт, что меню может появится в любом месте экрана или окна приложения.
В некоторых случаях плавающие меню удобнее обычных. Вы можете создавать плавающее меню двойным щелчком левой клавиши мыши или щелчком правой клавиши мыши, а также любым другим аналогичным способом. Если плавающее меню появится вблизи курсора мыши, из него будет легче выбрать нужную строку, чем из обычного меню, так как не надо перемещать курсор в верхнюю часть экрана. Кроме того, создавая плавающее меню щелчком мыши, вы можете изменять внешний вид этого меню в зависимости от объекта, по изображению которого был сделан щелчок.
Это позволит реализовать объектно-ориентированный подход в работе пользователя с приложением — в зависимости от того, для какого объекта было создано плавающее меню, изменяется содержимое меню. Таким образом, для того чтобы выполнить какую-либо операцию над объектом, пользователю будет достаточно щелкнуть по нему мышью. Около объекта появится плавающее меню операций, определенных для данного объекта.
Меню не обязательно должно содержать только текстовые строки. Вы можете создать меню из графических изображений или из комбинации графических изображений и текста. На рис. 1.8 показано меню приложения MENU из примеров приложений, поставляющихся вместе с системой разработки приложений Microsoft SDK для Windows версии 3.1.
Рис. 1.8. Меню приложения MENU, содержащее графические изображения
Для создания меню с графическими изображениями можно использовать методы, аналогичные применяемым при создании органов управления, рисуемых родительским окном, или специальные функции из программного интерфейса Windows.
1.2. Создание меню при помощи шаблона
Для создания меню вы можете использовать три метода.
Во-первых, можно описать шаблон меню в файле ресурсов приложения (аналогично шаблону диалоговой панели, но с использованием других операторов). Этот способ больше всего подходит для создания статических меню, не меняющихся или меняющихся не очень сильно в процессе работы приложения.
Во-вторых, можно создать меню «с нуля» при помощи специальных функций программного интерфейса Windows. Этот способ хорош для приложений, меняющих внешний вид меню, когда вы не можете создать заранее подходящий шаблон. Разумеется, второй метод пригоден и для создания статических меню.
В-третьих, можно подготовить шаблон меню непосредственно в оперативной памяти и создать меню на базе этого шаблона.
Создание шаблона меню
Шаблон меню можно создать в текстовом виде либо при помощи приложения Resource Workshop, либо обычным текстовым редактором, например, входящим в состав Borland Turbo C++ for Windows. В любом случае перед сборкой приложения текстовое описание шаблона меню должно находиться в файле ресурсов с расширением имени .rc, указанном в проекте приложения (или в файле, включаемом в файл проекта оператором #include).
Описание шаблона меню имеет следующий вид:
Поле nameID используется для идентификации шаблона меню. Оно может указываться либо в виде текстовой строки, либо в виде числа от 1 до 65535.
Параметр load — необязательный. Он используется для определения момента загрузки меню в память. Если этот параметр указан как PRELOAD, меню загружается в память сразу после запуска приложения. По умолчанию используется значение LOADONCALL, в этом случае загрузка шаблона в память происходит только при отображении меню.
Параметр mem также необязательный. Он влияет на тип памяти, выделяемой для хранения шаблона, и может указываться как FIXED (ресурс всегда остается в фиксированной области памяти), MOVEABLE (при необходимости ресурс может перемещаться в памяти, это значение используется по умолчанию) или DISCARDABLE (если ресурс больше не нужен, занимаемая им память может быть использована для других задач). Значение DISCARDABLE может использоваться вместе со значением MOVEABLE.
Между строками BEGIN и END в описании шаблона располагаются операторы описания строк MENUITEM и операторы описания временных меню POPUP.
Оператор MENUITEM имеет следующий формат:
Параметр text определяет имя строки меню. Вы должны указать текстовую строку в двойных кавычках, например, «File». Текстовая строка может содержать символы &, \t, \a.
Если в текстовой строке перед буквой стоит знак &, при выводе меню данная буква будет подчеркнута. Например, строка «&File» будет отображаться как «File». Клавиша, соответствующая подчеркнутой букве, может быть использована в комбинации с клавишей для ускоренного выбора строки. Для того чтобы записать в строку сам символ &, его следует повторить дважды. Аналогично, для записи в строку меню символа двойной кавычки » его также следует повторить дважды.
Символ \t включает в строку меню символ табуляции и может быть использован при выравнивании текста в таблицах. Этот символ обычно используется только во временных и плавающих меню, но не в основном меню приложения, расположенном под заголовком главного окна.
Символ \a выравнивает текст по правой границе временного меню или полосы меню.
Параметр id представляет собой целое число, которое должно однозначно идентифицировать строку меню. Приложение получит это число в параметре wParam сообщения WM_COMMAND, когда вы выберете данную строку.
Необязательный параметр param указывается как совокупность атрибутов, разделенных запятой или пробелом. Эти атрибуты определяют внешний вид и поведение строки меню:
Атрибут | Описание |
CHECKED | При выводе меню на экран строка меню отмечается галочкой «
|
GRAYED | Строка меню отображается серым цветом и находится в неактивном состоянии. Такую строку нельзя выбрать. Этот атрибут несовместим с атрибутом INACTIVE |
HELP | Слева от текста располагается разделитель в виде вертикальной линии |
INACTIVE | Строка меню отображается в нормальном виде (не серым цветом), но находится в неактивном состоянии. Этот атрибут несовместим с атрибутом GRAYED |
MENUBREAK | Если описывается меню верхнего уровня, элемент меню выводится с новой строки. Если описывается временное меню, элемент меню выводится в новом столбце |
MENUBARBREAK | Аналогично атрибуту MENUBREAK, но дополнительно новый столбец отделяется вертикальной линией (используется при создании временных меню) |
Для описания временных меню используется оператор POPUP :
Между строками BEGIN и END в описании временного меню располагаются операторы описания строк MENUITEM и операторы описания вложенных временных меню POPUP.
Параметры text и param указываются так же, как и для оператора MENUITEM .
Для того чтобы создать в меню горизонтальную разделительную линию, используется специальный вид оператора MENUITEM :
Поясним сказанное выше на простом примере.
Скоро мы приведем исходные тексты приложения, имеющего меню (рис. 1.9). Это приложение называется, конечно, MENU.
Рис. 1.9. Главное окно приложения MENU, имеющего меню
Меню этого приложения состоит из строк «File», «Edit» и «Help». При выборе любой строки на экране появляется одно из трех временных меню.
Меню «File» (рис. 1.10) содержит строки, предназначенные для выполнения стандартных для приложений Windows команд, таких, как создание нового документа (или другого объекта) «New», загрузка документа «Open. «, и т. д. Обратите внимание, что после строк «Save as. » и «Printer setup. » располагаются горизонтальные разделительные линии.
Рис. 1.10. Меню «File»
На рис. 1.11 показано временное меню «Edit». Оно организовано в виде таблицы из двух столбцов. В левом столбце находятся названия команд («Undo», «Cut», «Copy», «Paste»), в правом — обозначения комбинаций клавиш, которые предназначены для ускоренного выбора строки меню.
Рис. 1.11. Меню «Edit»
Временное меню «Help» (рис. 1.12) содержит две неактивные строки («Index» и «Keyboard»), три неактивные строки, отображаемые серым цветом («Commands», «Procedures», «Using Help»), горизонтальную разделительную линию и обычную строку «About. «).
Рис. 1.12. Меню «Help»
Для того чтобы создать описанное выше меню, в приложении Menu Demo в файле ресурсов определен шаблон меню:
Шаблон меню начинается с оператора MENU, в котором определено меню с именем APP_MENU. Это меню состоит из трех временных меню, описанных оператором POPUP.
Для определения строк временных меню используется оператор MENUITEM. В качестве второго оператора используются константы, символическое имя которых имеет префикс CM_. Мы определили эти константы в файле menu.hpp, включаемом в файл описания ресурсов оператором #include (можно использовать любые целые неодинаковые значения):
Обратите внимание на определение временного меню «Edit». Для того чтобы организовать меню в виде таблицы из двух столбцов, мы использовали символ табуляции \t.
В описании временного меню «Help» используются атрибуты строк INACTIVE и GRAYED. Напомним, что строки с такими атрибутами являются неактивными, их невозможно выбрать. Разница между этими атрибутами заключается в том, что строка с атрибутом INACTIVE выводится нормальным цветом (как активная строка меню), а строка с атрибутом GRAYED выводится серым цветом.
Вы сможете легко подготовить описание шаблона меню при помощи текстового редактора в файле описания ресурсов, однако удобнее воспользоваться редактором ресурсов Resource Workshop. С помощью этого редактора вы можете создать шаблон меню и выполнить его тестирование, получив в результате текстовое описание шаблона, которое впоследствии можно редактировать. Именно так мы и поступили, создавая описанное выше меню.
Опишем кратко процесс создания шаблона меню при помощи приложения Resource Workshop.
Для того чтобы создать шаблон меню редактором ресурсов Resource Workshop, запустите его и из меню «File» выберите строку «New project. «. В появившейся на экране диалоговой панели выберите тип ресурса — файл .RC, вслед за чем нажмите на кнопку «OK». Если файл описания ресурсов проектируемого приложения уже существует, вы можете открыть его, выбрав из меню «File» строку «Open project. «.
Далее из меню «Resource» выберите строку «New. «. На экране появится диалоговая панель «New resource». В списке «Resource type» выберите строку «MENU» и нажмите кнопку «OK». В главном окне приложения Resource Workshop вы увидите несколько окон, предназначенных для проектирования шаблона меню (рис. 1.13).
Рис. 1.13. Проектирование шаблона меню
Окно «TEST MENU» предназначено для визуальной проверки проектируемого меню. С помощью этого окна в любой момент времени вы можете проверить работу созданного вами меню.
Окно MENU_1 содержит текстовое описание создаваемого меню. Первоначально меню состоит из одного временного меню «Pop-up», в котором определена одна строка «Item». Вы можете выбирать мышью строки описания элементов меню, при этом в левой части окна «MENU» вам будет предоставлена возможность изменить название, идентификатор и атрибуты соответствующего элемента.
Для добавления строки во временное меню в окне «MENU_1» выделите строку, после которой надо добавить новую. Затем из меню «Menu» выберите строку «New menu item». Можно добавить горизонтальную разделительную линию. Для этого из меню «Menu» выберите строку «New separator».
Если вам надо добавить новое временное меню, выделите строку «__EndPopup__» и выберите из меню «Menu» строку «New pop-up».
Для удаления строки или временного меню вам достаточно выделить соответствующую строку в окне «MENU_1» и нажать клавишу .
Для того чтобы изменить атрибуты строки меню выделите нужную строку в окне «MENU_1» и в левой части окна «MENU:MENU_1» укажите новые атрибуты.
В поле «Item text» вы можете изменить текст, соответствующей строке меню.
В поле «Item id» можно задать идентификатор строки меню. Это может быть любое целое число. Когда вы создаете меню при помощи Resource Workshop, идентификаторы строк меню присваиваются автоматически. Напомним, что идентификатор строки меню передается функции окна приложения в параметре wParam сообщения WM_COMMAND. Пользуясь этим идентификатором, приложение определяет строку, выбранную вами в меню, после чего выполняет необходимые действия в соответствии с логикой работы приложения.
С помощью группы переключателей «Item type» вы можете изменить тип выделенной вами в окне «MENU_1» строки, превратив обычную строку («Menu item») в разделительную линию («Separator»).
При помощи переключателя «Break before» можно определить для строк принудительный переход на новую строку или в новый столбец.
Если включен переключатель «No break», элементы меню располагаются как обычно, то есть строка нового временного меню добавляется в полосе меню с левой стороны, а новая строка временного меню располагается в нижней части меню.
Если включен переключатель «Menu bar break», строка названия временного меню располагается не слева, а внизу, образуя «второй этаж» полосы меню. Эта возможность используется редко.
Переключатель «Menu break» предназначен для размещения строки временного меню в другом столбце меню.
Переключатель «Help break» задает выравнивание названия временного меню по правой границе полосы меню. В приложениях, созданных для Windows версии 3.0, такое расположение использовалось для меню «Help». Однако в стандартных приложениях Windows версии 3.1 выравнивание меню «Help» по правой границе не выполняется.
С помощью переключателя «Initial state» вы можете задать начальное состояние элемента меню как активное («Enabled»), неактивное («Disabled») или неактивное с отображением серым цветом («Grayed»). Можно также указать, что строка меню должна быть отмечена галочкой. Для этого следует установить переключатель «Checked».
Меню «Menu» приложения Resource Workshop содержит строки «New file pop-up», «New edit pop-up» и «New help pop-up». Эти строки предназначены для автоматического создания стандартных меню «File», «Edit» и «Help», которые должны быть в любом стандартном приложении Windows. Мы воспользовались этими строками для создания меню в нашем приложении Menu Demo, упомянутом выше.
Выбрав из меню «Menu» строку «Check duplicates», вы можете проверить идентификаторы строк созданного вами меню. Если в меню есть строки с одинаковыми идентификаторами, на экране появится диалоговая панель с предупреждающим сообщением.
После завершения процесса формирования меню вы можете изменить имя меню в описании шаблона. Для этого из меню «Resource» выберите строку «Rename». На экране появится диалоговая панель «Rename resource», с помощью которой вы сможете изменить имя меню (рис. 1.14).
Рис. 1.14. Изменение имени меню
После того как вы измените имя меню и нажмете на клавишу «OK», на экране появится диалоговая панель с запросом о необходимости создания символической константы, соответствующей данному имени. В этой панели следует нажать на клавишу «No», так как наше приложение будет ссылаться на имя меню при помощи текстовой строки, а не константы.
Подключение меню к окну приложения
Теперь вы знаете, как создать шаблон меню. Следующий этап — подключение меню к окну приложения. Обычно меню определяется для класса окна при регистрации или для отдельного окна при его создании функцией CreateWindow.
Подключение меню при регистрации класса окна
Если при регистрации класса окна в поле lpszMenuName структуры типа WNDCLASS указать адрес текстовой строки, содержащей имя шаблона меню в файле ресурсов, все перекрывающиеся и временные окна, создаваемые на базе этого класса, будут иметь меню, определенное данным шаблоном. Дочерние окна (child window) не могут иметь меню.
Например, пусть в файле описания ресурсов шаблон меню определен под именем APP_MENU:
В этом случае для подключения меню при регистрации класса вы должны записать адрес текстовой строки «APP_MENU» в поле lpszMenuName структуры wc, имеющей тип WNDCLASS:
Вы можете использовать для идентификации шаблона меню целые числа (как и для идентификации ресурсов других типов). В этом случае необходимо использовать макрокоманду MAKEINTRESOURCE.
Например, пусть в файле описания ресурсов и в файле исходного текста приложения определена константа:
В этом случае ссылка на меню при регистрации класса окна должна выполняться следующим образом:
В своих приложениях мы будем пользоваться первым способом, так как он проще в реализации.
Когда для класса окна определено меню, все перекрывающиеся и временные окна, создаваемые на базе этого класса, будут иметь меню, если при создании окна функцией CreateWindow идентификатор меню указан как 0.
Подключение меню при создании окна
Если при регистрации класса окна было определено меню, вы можете создавать окна с этим меню, или можете указать для создаваемого окна другое меню. Для подключения меню, отличного от указанного в классе окна, вам необходимо задать идентификатор нужного меню при создании окна функцией CreateWindow. Короче говоря, окно может иметь меню, определенное в классе, или свое собственное.
Девятый параметр функции CreateWindow используется для подключения меню к создаваемому окну:
Значение параметра идентификатора меню может быть получено, например, от функции LoadMenu , определенной в программном интерфейсе Windows:
Параметр hInstance должен содержать идентификатор текущей копии приложения, полученный через соответствующий параметр функции WinMain.
Параметр lpszMenuName является указателем на строку символов, закрытую двоичным нулем, содержащую имя загружаемого шаблона меню. Если для идентификации шаблона меню используется целое число, необходимо сформировать этот указатель при помощи макрокоманды MAKEINTRESOURCE.
Функция LoadMenu возвращает идентификатор загруженного меню или NULL при ошибке.
Перед завершением своей работы приложение должно уничтожить загруженное меню функцией DestroyMenu :
В качестве единственного параметра функции DestroyMenu необходимо указать идентификатор уничтожаемого меню.
Функция DestroyMenu возвращает в случае успеха значение TRUE, при ошибке — FALSE.
1.3. Сообщения, поступающие от меню
Меню посылает сообщения в функцию создавшего его окна.
Сообщение WM_INITMENU посылается перед отображением меню и может быть использовано для инициализации. Сообщение WM_COMMAND посылается после того, как пользователь выберет одну из активных строк меню. Системное меню посылает в окно приложения сообщение WM_SYSCOMMAND, которое обычно не обрабатывается приложением (передается функции DefWindowProc). В процессе выбора строки из меню, когда курсор перемещается по строкам меню, функция окна, создавшего меню, получает сообщение WM_MENUSELECT. Перед инициализацией временного меню функция окна получает сообщение WM_INITMENUPOPUP.
Из всех этих сообщений наибольший интерес представляют сообщения WM_INITMENU, WM_INITMENUPOPUP, WM_COMMAND, WM_SYSCOMMAND.
Сообщение WM_INITMENU
Сообщение WM_INITMENU посылается окну, создавшему меню, в момент отображения меню. Это происходит, когда вы нажимаете на строку в полосе меню или активизируете временное меню при помощи клавиатуры.
Вместе с этим сообщением в параметре wParam передается идентификатор активизируемого меню. Параметр lParam не используется.
Если приложение обрабатывает сообщение WM_INITMENU, соответствующий обработчик должен вернуть нулевое значение. Обработка может заключаться в активизации или деактивизации строк меню, изменении состояния строк (отмеченное галочкой или не отмеченное) и т. п. Немного позже мы опишем функции, предназначенные для динамического изменения внешнего вида и состояния меню.
Сообщение WM_INITMENUPOPUP
Сообщение WM_INITMENUPOPUP посылается окну, когда операционная система Windows готова отобразить временное меню. Младшее слово параметра lParam содержит порядковый номер временного меню в меню верхнего уровня, старшее слово содержит 1 для системного меню или 0 для обычного меню.
Это сообщение можно использовать для активизации или блокирования отдельных строк временного меню.
Сообщение WM_COMMAND
Сообщение WM_COMMAND , как мы уже говорили, посылается функции окна приложения, создавшего меню, когда вы выбираете нужную вам строку. Параметр wParam содержит идентификатор строки, определенный в шаблоне меню.
Задача функции окна, обрабатывающей сообщения от меню, заключается в проверке значения параметра wParam и выполнении соответствующей функции.
Сообщение WM_SYSCOMMAND
Сообщение WM_SYSCOMMAND приходит в функцию окна приложения, когда пользователь выбирает строку из системного меню. Параметр wParam, как и для сообщения WM_COMMAND, содержит идентификатор строки меню, в данном случае, идентификатор строки системного меню. Параметр lParam не используется (за исключением идентификатора SC_HOTKEY).
Приведем список идентификаторов с кратким описанием.
Идентификатор | Описание |
SC_CLOSE | Удаление окна (строка «Close») |
SC_HOTKEY | Активизация окна, связанного с комбинацией клавиш, определенной приложением. Младшее слово параметра lParam содержит идентификатор активизируемого окна |
SC_HSCROLL | Свертка по горизонтали |
SC_KEYMENU | Выбор из меню при помощи комбинации клавиш |
SC_MAXIMIZE или SC_ZOOM | Максимизация окна (строка «Maximize») |
SC_MINIMIZE или SC_ICON | Минимизация окна (строка «Minimize») |
SC_MOUSEMENU | Выбор из меню при помощи мыши |
SC_MOVE | Перемещение окна (строка «Move») |
SC_NEXTWINDOW | Переключение на следующее окно |
SC_PREVWINDOW | Переключение на предыдущее окно |
SC_RESTORE | Восстановление нормального положения и размера окна |
SC_SCREENSAVE | Запуск приложения, предназначенного для предохранения экрана дисплея от преждевременного выгорания (screen-saver application), определенного в разделе [boot] файла system.ini |
SC_SIZE | Изменение размера окна (строка «Size») |
SC_TASKLIST | Запуск или активизация приложения Task Manager |
SC_VSCROLL | Свертка по вертикали |
При анализе параметра wParam учтите, что младшие четыре бита этого параметра могут принимать любые значения и должны игнорироваться:
Скоро мы расскажем вам о том, как можно добавлять строки в системное меню. При добавлении строк в системное меню вы должны указывать идентификатор строки. Этот идентификатор (с учетом сказанного выше относительно младших четырех битов) вы получите в параметре wParam сообщения WM_SYSCOMMAND при выборе добавленной вами строки.
Создав собственный обработчик для сообщений, приходящих от системного меню, вы можете блокировать отдельные или все строки этого меню. Для блокировки какой-либо строки соответствующий обработчик должен вернуть нулевое значение, как в приведенном выше фрагменте кода, блокирующем изменение размера окна.
1.4. Приложение MENU
Теперь, когда мы рассказали вам о том, как создать шаблон меню и само меню, приведем исходные тексты простого приложения, работающего с меню. Оно создает меню, описанное нами ранее в разделе «Создание шаблона меню». Вид главного окна приложения был представлен на рис. 1.9.
В листинге 1.1 приведен исходный текст основного файла приложения.
Листинг 1.1. Файл menu/menu.cpp
Функция WinMain регистрирует класс окна и создает на его базе главное окно приложения.
При регистрации класса окна указывается имя шаблона меню, определенного в файле описания ресурсов:
В остальном функция WinMain не имеет никаких особенностей.
Функция главного окна WndProc обрабатывает сообщение WM_COMMAND, поступающее от меню. Для всех идентификаторов, кроме CM_FILEEXIT, обработка сводится к выводу сообщения о том, что данная функция не реализована. Если вы из меню ‘File» нашего приложения выбираете строку «Exit», обработчик сообщения WM_COMMAND уничтожает главное окно приложения, вызывая функцию DestroyWindow. Это приводит к завершению работы приложения.
Идентификаторы строк меню описаны в файле menu.hpp (листинг 1.2), включаемом при помощи оператора #include в главный файл приложения и файл описания ресурсов.
Листинг 1.2. Файл menu/menu.hpp
Файл описания ресурсов (листинг 1.3) содержит определение шаблона меню с именем APP_MENU, описанный нами ранее.
Листинг 1.3. Файл menu/menu.rc
Проверяя работу приложения, обратите внимание на то, что хотя в строках временного меню «Edit» были указаны комбинации клавиш ускоренного выбора (например, для функции «Undo» указана комбинация клавиш «Ctrl+Z»), вы пока не можете их использовать. Это связано с тем, что мы пока не определили комбинации клавиш ускоренного выбора, а всего лишь записали их обозначение в строках меню. Мы еще вернемся к этому вопросу.
В листинге 1.4 приведен файл определения модуля, использованный при сборке приложения MENU.
Листинг 1.4. Файл menu/menu.def
1.5. Функции для работы с меню
В программном интерфейсе операционной системы Windows есть функции, специально предназначенные для работы с меню. С помощью этих функций приложение может создавать меню (даже не имея его шаблона), добавлять или удалять строки или временные меню, активизировать или блокировать отдельные строки меню, изменять состояние строк (отмеченное или не отмеченное) и т. д.
В этом разделе мы расскажем вам о том, как пользоваться такими функциями.
Создание меню
Даже если в файле описания ресурсов нет определения шаблона меню, приложение может создать меню «с нуля» для любого своего перекрывающегося или временного окна (но не для дочернего). Для создания пустого меню (то есть меню, не содержащего ни одной строки и ни одного временного меню) можно воспользоваться функцией CreateMenu :
Функция возвращает идентификатор созданного меню или NULL при ошибке.
Как правило, в меню верхнего уровня (в меню приложения) создаются временные меню. Для создания временного меню воспользуйтесь функцией CreatePopupMenu:
В дальнейшем вы можете добавить в меню верхнего уровня созданные функцией CreatePopupMenu временные меню или отдельные строки, вызвав функцию AppendMenu.
Перед завершением работы приложение должно удалить созданные описанным выше способом меню, для чего следует воспользоваться функцией DestroyMenu.
Для подключения к окну с идентификатором hwnd меню с идентификатором hmenu вы можете воспользоваться функцией SetMenu:
Перед вызовом этой функции вы должны загрузить меню и получить его идентификатор, например, при помощи функции LoadMenu.
Функция SetMenu возвращает TRUE при успешном завершении и FALSE при ошибке.
Добавление строк
Для добавления строк в созданные функциями CreateMenu и CreatePopupMenu пустые меню можно воспользоваться функцией AppendMenu :
Параметр hmenu указывает идентификатор меню, к которому добавляется строка или временное меню. Вы должны использовать значение, полученное от функций CreateMenu и CreatePopupMenu.
Параметр fuFlags определяет атрибуты создаваемого элемента меню. Можно указывать следующие значения (соответствующие символические константы описаны в файле windows.h):
Константа | Описание |
MF_BITMAP | Для изображения строки меню используется графическое изображение bitmap. Если указан этот параметр, младшее слово параметра lpszNewItem содержит идентификатор изображения |
MF_CHECKED | При выводе меню на экран строка меню отмечается галочкой « |
MF_DISABLED | Строка меню отображается в нормальном виде (не серым цветом), но находится в неактивном состоянии |
MF_ENABLED | Строка меню разблокирована и отображается в нормальном виде |
MF_GRAYED | Строка меню отображается серым цветом и находится в неактивном состоянии. Такую строку нельзя выбрать |
MF_MENUBREAK | Если описывается меню верхнего уровня, элемент меню выводится с новой строки. Если описывается временное меню, элемент меню выводится в новом столбце |
MF_MENUBARBREAK | Аналогично MF_MENUBREAK, но дополнительно новый столбец отделяется вертикальной линией (используется при создании временных меню) |
MF_OWNERDRAW | Строка меню рисуется окном, создавшем меню. Когда меню отображается в первый раз, функция этого окна получает сообщение WM_MEASUREITEM, в ответ на которое функция окна должна сообщить размеры области, занимаемой изображением строки меню. Рисовать изображение строки надо тогда, когда в функцию окна придет сообщение WM_DRAWITEM. Флаг MF_OWNERDRAW можно указывать только для временных меню |
MF_POPUP | С данным элементом меню связывается временное меню. Если используется этот флаг, параметр idNewItem должен содержать идентификатор временного меню, связанного с данным элементом |
MF_SEPARATOR | Используется для создания горизонтальной разделительной линии во временных меню. Если указан этот флаг, параметры lpszNewItem и idNewItem не используются |
MF_STRING | Элемент меню является строкой символов. Параметр lpszNewItem должен указывать на строку символов, закрытую двоичным нулем |
MF_UNCHECKED | При выводе меню на экран строка не отмечается галочкой « |
Вы можете указывать сразу несколько флагов, объединив их операцией логического ИЛИ, однако следует иметь в виду, что существует четыре группы взаимно несовместимых флагов:
MF_DISABLED, MF_ENABLED, MF_GRAYED |
MF_BITMAP, MF_OWNERDRAW, MF_STRING |
MF_MENUBREAK, MF_MENUBARBREAK |
MF_CHECKED, MF_UNCHECKED |
Назначение параметра idNewItem зависит от параметра fuFlags. Если значение параметра fuFlags не равно MF_POPUP, через idNewItem вы должны передать идентификатор создаваемой строки меню. Этот идентификатор будет записан в параметр wParam сообщения WM_COMMAND при выборе данной строки. Если же значение параметра fuFlags равно MF_POPUP, через параметр idNewItem вы должны передать функции AppendMenu идентификатор временного меню.
Назначение параметра lpszNewItem также зависит от параметра fuFlags. Если этот параметр равен MF_STRING, параметр lpszNewItem должен указывать на строку символов, закрытую двоичным нулем, если MF_BITMAP — младшее слово параметра lpszNewItem содержит идентификатор изображения, а если параметр fuFlags равен MF_OWNERDRAW, приложение должно передать через параметр lpszNewItem 32-битовое значение, идентифицирующее строку меню.
Еще одна функция, предназначенная для добавления элементов в меню, называется InsertMenu . Эта функция может добавить элемент в середину меню, сдвинув вниз уже существующие элементы.
Приведем прототип функции InsertMenu:
Параметры этой функции аналогичны параметрам функции AppendMenu, за исключением параметров idItem и fuFlags.
Параметр idItem определяет элемент меню, перед которым должен быть вставлен новый элемент. Интерпретация этого параметра зависит от значения параметра fuFlags.
В дополнение к возможным значениям параметра fuFlags, описанным нами для функции AppendMenu, вместе с функцией InsertMenu вы можете использовать еще два — MF_BYCOMMAND и MF_BYPOSITION.
Если указан флаг MF_BYCOMMAND, параметр idItem определяет идентификатор элемента меню, перед которым будет вставлен новый элемент.
Если указан флаг MF_BYPOSITION, параметр idItem определяет порядковый номер элемента меню, перед которым будет вставлен новый элемент. Для того чтобы добавить элемент в конец меню, для параметра idItem можно указать значение -1.
После внесения всех изменений в меню приложение должно вызвать функцию DrawMenuBar :
Эта функция перерисовывает полосу меню для указанного параметром hwnd окна. В качестве параметра функции следует передать идентификатор окна, создавшего меню.
Изменение строк
Для изменения строк (элементов) существующего меню вы можете воспользоваться функцией ModifyMenu :
Параметры этой функции идентичны параметрам функции InsertMenu.
Функция ModifyMenu заменяет указанный элемент меню на новый. При замещении временного меню оно уничтожается и все связанные с ним ресурсы освобождаются.
После того как вы изменили меню, не забудьте вызывать функцию DrawMenuBar, описанную выше.
В программном интерфейсе Windows версии 3.0 была определена функция ChangeMenu , предназначенная для изменения существующего меню. В версии 3.1 эта функция была заменена на следующие пять функций:
Функция | Описание |
AppendMenu | Добавление элемента в меню |
DeleteMenu | Удаление элемента из меню |
InsertMenu | Вставка элемента в меню |
ModifyMenu | Изменение элемента меню |
RemoveMenu | Удаление элемента меню без освобождения ресурсов, занимаемых этим элементом |
Новые приложения не должны пользоваться функцией ChangeMenu.
Удаление строк
Для удаления элементов меню, таких, как строки и временные меню, предназначена функция DeleteMenu :
Параметр hmenu определяет меню, из которого будет удален элемент.
Параметр idItem определяет удаляемый элемент, причем его интерпретация зависит от значения параметра fuFlags.
Если в параметре fuFlags указан флаг MF_BYCOMMAND, параметр idItem определяет идентификатор удаляемого элемента меню. Если указан флаг MF_BYPOSITION, параметр idItem определяет порядковый номер удаляемого элемента меню.
При удалении временного меню все связанные с ним ресурсы освобождаются.
Для отображения результата удаления меню следует вызвать функцию DrawMenuBar.
В программном интерфейсе Windows определена функция RemoveMenu , имеющая параметры, аналогичные параметрам функции DeleteMenu:
Эта функция удаляет указанный ей элемент из меню, но не уничтожает связанные с ним ресурсы, поэтому вы можете вновь воспользоваться удаленным элементом меню (если знаете его идентификатор, о том как получить идентификатор временного меню мы расскажем немного позже).
Напомним, что для уничтожения меню используется функция DestroyMenu :
В качестве параметра функции передается идентификатор уничтожаемого меню. Функция освобождает все ресурсы, связанные с уничтоженным меню.
Активизация и блокирование строк меню
Для изменения состояния элемента меню удобно использовать функцию EnableMenuItem :
Параметр hmenu указывает идентификатор меню, над элементом которого будет выполняться операция активизации или блокирования.
Параметр idItem определяет элемент меню, над которым выполняется операция. Интерпретация этого параметра зависит от значения параметра uEnable.
Параметр uEnable может принимать значения MF_DISABLED, MF_ENABLED или MF_GRAYED в комбинации с одним из значений: MF_BYCOMMAND или MF_BYPOSITION.
Для блокирования элемента меню необходимо использовать значение MF_DISABLED. Если заблокированный элемент меню нужно изобразить серым цветом, вместо MF_DISABLED используйте значение MF_GRAYED.
Для активизации заблокированного ранее элемента меню укажите значение MF_ENABLED.
Если в параметре fuFlags указан флаг MF_BYCOMMAND, параметр idItem определяет идентификатор элемента меню, состояние которого будет изменено. Если указан флаг MF_BYPOSITION, параметр idItem определяет порядковый номер элемента меню, состояние которого будет изменено.
Как и после выполнения других операций по изменению меню, после изменения состояния элемента меню необходимо вызвать функцию DrawMenuBar, которая отобразит внесенные изменения на экране.
Отметка строк
Вы знаете, что элементы временного меню могут быть отмечены галочкой. Для включения и выключения такой отметки можно использовать функцию CheckMenuItem :
Параметр hmenu указывает идентификатор меню, над элементом которого будет выполняться операция включения или выключения отметки.
Параметр idItem определяет элемент меню, над которым выполняется операция. Интерпретация этого параметра зависит от значения параметра fuCheck.
Параметр fuCheck может принимать значения MF_CHECKED или MF_UNCHECKED в комбинации с одним из значений: MF_BYCOMMAND или MF_BYPOSITION.
Для включения отметки элемента меню необходимо использовать значение MF_CHECKED. Для выключения отметки элемента меню укажите значение MF_UNCHECKED.
Если в параметре fuCheck указан флаг MF_BYCOMMAND, параметр idItem определяет идентификатор элемента меню, отметка которого будет изменена. Если указан флаг MF_BYPOSITION, параметр idItem определяет порядковый номер элемента меню, отметка которого будет изменена.
Выделение строк
Для выделения строк меню верхнего уровня, расположенных в полосе меню ниже заголовка окна, можно использовать функцию HiliteMenuItem :
Параметр hwnd должен содержать идентификатор окна, для которого выполняется операция выделения.
Через параметр hMenu необходимо передать идентификатор соответствующего меню верхнего уровня.
Параметр idItem определяет элемент меню, над которым выполняется операция выделения. Интерпретация этого параметра зависит от значения параметра fuHilite.
Параметр fuHilite может принимать значения MF_HILITE или MF_UNHILITE в комбинации с одним из значений: MF_BYCOMMAND или MF_BYPOSITION.
Для выделения строки меню необходимо использовать значение MF_HILITE. Для отмены выделения строки меню укажите значение MF_UNHILITE.
Если в параметре fuHilite указан флаг MF_BYCOMMAND, параметр idItem определяет идентификатор строки меню, для которого выполняется операция выделения или отмены выделения. Если указан флаг MF_BYPOSITION, параметр idItem определяет порядковый номер этой строки.
Получение информации
В программном интерфейсе операционной системы Windows существует несколько функций для получения различной информации о меню и о состоянии строк меню.
Идентификатор меню
С помощью функции GetMenu вы можете определить идентификатор меню, связанного с окном:
Идентификатор окна задается при помощи параметра hwnd.
Функция возвращает идентификатор меню или NULL, если окно не имеет меню. Дочернее окно не может иметь меню, однако в документации к SDK говорится, что если вы вызовете данную функцию для дочернего окна, возвращенное значение будет неопределено.
Идентификатор временного меню
Для определения идентификатора временного меню следует вызвать функцию GetSubMenu :
Эта функция для меню верхнего уровня с идентификатором hmenu возвращает идентификатор временного меню, порядковый номер которого задается параметром nPos. Первому временному меню соответствует нулевое значение параметра nPos.
Если функция GetSubMenu вернула значение NULL, то меню верхнего уровня не содержит в указанной позиции временное меню.
Проверка идентификатора меню
Для того чтобы убедиться, что идентификатор не является идентификатором меню, вы можете использовать функцию IsMenu :
Эта функция появилась в программном интерфейсе Windows версии 3.1.
Функция возвращает значение FALSE, если переданный ей через параметр hmenu идентификатор не является идентификатором меню. Можно было бы ожидать, что если функция IsMenu вернула значение TRUE, то проверяемый идентификатор является идентификатором меню, однако в описании функции сказано, что это не гарантируется.
Количество элементов в меню
Функция GetMenuItemCount возвращает количество элементов в меню верхнего уровня или во временном меню, заданном параметром hmenu:
Идентификатор элемента меню
Для получения идентификатора элемента меню, расположенного в указанной позиции, вы можете воспользоваться функцией GetMenuItemID :
Параметр hmenu задает меню, идентификатор элемента которого требуется определить. Порядковый номер элемента определяется параметром nPos, причем первому элементу соответствует нулевое значение. В случае ошибки (если параметр hmenu указан как NULL или указанный элемент является временным меню) функция GetMenuItemID возвращает значение -1. Если вы попытаетесь определить идентификатор горизонтальной разделительной линии (сепаратора), функция вернет нулевое значение.
Текст строки меню
С помощью функции GetMenuString вы можете переписать в буфер текстовую строку, соответствующую элементу меню.
Параметр hmenu определяет меню, для которого будет выполняться операция.
Параметр idItem определяет элемент меню, над которым выполняется операция. Интерпретация этого параметра зависит от значения параметра fuFlags.
Если в параметре fuFlags указан флаг MF_BYCOMMAND, параметр idItem определяет идентификатор строки меню, для которого выполняется операция. Если указан флаг MF_BYPOSITION, параметр idItem определяет порядковый номер этой строки.
Адрес буфера, в который будет выполняться копирование, задается параметром lpsz, размер буфера без учета двоичного нуля, закрывающего строку, — оператором cbMax. Символы, не поместившиеся в буфер, будут обрезаны.
Функция GetMenuString возвращает количество символов, скопированных в буфер, без учета двоичного нуля, закрывающего строку.
Флаги состояния элемента меню
Функция GetMenuState возвращает флаги состояния для заданного элемента меню:
Параметр hmenu определяет меню, для которого будет выполняться операция.
Параметр idItem определяет элемент меню, для которого будут получены флаги состояния. Интерпретация этого параметра зависит от значения параметра fuFlags.
Если в параметре fuFlags указан флаг MF_BYCOMMAND, параметр idItem определяет идентификатор строки меню, для которого выполняется операция. Если указан флаг MF_BYPOSITION, параметр idItem определяет порядковый номер этой строки.
Для временного меню старший байт возвращаемого функцией значения содержит количество элементов во временном меню, а младший — набор флагов, описывающих временное меню. Для меню верхнего уровня возвращаемое значение является набором флагов, описывающих указанный элемент меню:
Флаг | Описание |
MF_BITMAP | Для изображения строки меню используется графическое изображение bitmap |
MF_CHECKED | Строка меню отмечена галочкой « |
MF_DISABLED | Строка меню находится в неактивном состоянии |
MF_ENABLED | Строка меню разблокирована и отображается в нормальном виде. Этому состоянию соответствует возвращаемое функцией GetMenuState значение, равное нулю |
MF_GRAYED | Строка меню отображается серым цветом и находится в неактивном состоянии. Такую строку нельзя выбрать |
MF_MENUBREAK | Для меню верхнего уровня элемент меню выводится с новой строки. Для временного меню элемент выводится в новом столбце |
MF_MENUBARBREAK | Аналогично MF_MENUBREAK, но дополнительно столбец отделен вертикальной линией |
MF_SEPARATOR | Строка является горизонтальной разделительной линией во временных меню |
MF_UNCHECKED | Строка не отмечена галочкой « |
Если указанный элемент меню не существует, функция GetMenuState возвращает значение -1.
1.6. Приложение DMENU
В приложении DMENU, имитирующем работу с документами (например, с текстами), мы использовали большинство описанных выше функций, предназначенных для динамического создания и изменения меню. Проект этого приложения не включает файл описания ресурсов и, соответственно, не использует шаблон меню.
Сразу после запуска приложения в полосе меню определены два временных меню — «File» и «Help» (рис. 1.15). В меню «File» вы можете использовать строки «New» и «Open», предназначенные, соответственно, для создания нового документа или загрузки документа из файла. Кроме этих двух строк вы можете выбрать строку «Exit», завершающую работу приложения. Строка «Demo Version» заблокирована и отмечена галочкой. Так как мы еще не научились работать с принтером, строки «Print», «Page Setup» и «Printer Setup» заблокированы и отображаются серым цветом.
Рис. 1.15. Исходный вид меню приложения DMENU
Пока вы не создали новый документ или не загрузили документ, созданный ранее, строки «Close», «Save», «Save as. » заблокированы. Так как документ не загружен, его нельзя закрыть или сохранить, поэтому соответствующие строки в меню отображаются серым цветом.
После того, как вы выберете строку «New» или «Open», внешний вид меню приложения изменится (рис. 1.16).
Рис. 1.16. Изменения в меню приложения DMENU
Так как приложение DMENU рассчитано на «работу» с одним документом, после загрузки документа строки «New» и «Open» блокируются. Для их разблокирования вы должны закрыть документ, выбрав строку «Close». В этом случае меню приложения примет исходный вид, представленный на рис. 1.15.
После загрузки документа в меню «File» разблокируются строки «Close», «Save» и «Save as. «. Кроме этого, появляется новое временное меню «Edit», аналогичное меню «Edit» предыдущего приложения. Меню «Edit» присутствует в окне только тогда, когда загружен документ. Если документ не загружен, то редактировать нечего. В этом случае меню «Edit» не нужно.
Многие приложения Windows изменяют меню похожим образом. Внешний вид меню может зависеть от типа обрабатываемого документа, от используемых параметров и режимов (краткое меню, полное меню, расширенное меню и т. д.) или от текущего состояния документа.
Исходный текст главного файла приложения DMENU, реализующего описанный выше алгоритм изменения меню, представлен в листинге 1.5.
Листинг 1.5. Файл dmenu/dmenu.cpp
В приложении определены четыре глобальные переменные типа HMENU, предназначенные для хранения идентификаторов одного меню верхнего уровня (переменная hmenu) и трех временных меню (переменные hmenuFile, hmenuEdit, hmenuHelp).
Меню верхнего уровня создается в функции главного окна приложения во время обработки сообщения WM_CREATE. Созданное пустое меню подключается к главному окну приложения при помощи функции SetMenu:
Далее создаются два временных меню — «File» и «Help», для чего два раза вызывается функция CreatePopupMenu:
На данный момент все меню пустые. Прежде всего обработчик сообщения WM_CREATE добавляет к меню «File» несколько строк, вызывая соответствующее число раз функцию AppendMenu:
Обратите внимание на способ, которым в меню добавляется разделительная линия:
Если в качестве второго параметра функции AppendMenu указано значение MF_SEPARATOR, третий и четвертый параметр этой функции игнорируются.
Для того чтобы отметить галочкой строку «Demo Version», вызывается функция CheckMenuItem:
Аналогичным образом формируется меню «Help».
Далее сформированные временные меню «File» и «Help» добавляются к меню верхнего уровня при помощи функции AppendMenu:
В заключение вызывается функция DrawMenuBar, которая отображает внесенные изменения на экране:
После формирования меню от него в функцию окна начинают поступать сообщения WM_COMMAND.
Так как меню, которые вы создаете, занимают системные ресурсы, их необходимо уничтожать, если они больше не нужны. При завершении работы приложения мы удалим все созданные меню. Однако меню «Edit» может так и не быть создано, так как вы можете сразу после запуска завершить работу приложения. Для того чтобы определить, нужно ли удалять меню «Edit», мы при создании главного окна приложения записываем в переменную hmenuEdit, предназначенную для хранения идентификатора меню, значение NULL:
Если меню «Edit» будет создано, в переменную hmenuEdit будет записано значение соответствующего идентификатора. При завершении работы приложения мы проверим состояние этой переменной и, если ее содержимое отлично от значения NULL, уничтожим меню.
На многие из этих сообщений функция окна реагирует выводом сообщения о том, что данная функция не реализована. При выборе строки «About. » в меню «Help» на экран выводится диалоговая панель с сообщением о названии приложения и сведения о разработчике. Это стандартная реакция на выбор строки «About. » в меню «Help» любого приложения Windows.
Когда вы выбираете из меню «File» строки «New» или «Open», в функцию окна приложения приходит сообщение WM_COMMAND со значением парамера wParam, равным, соответственно, CM_FILENEW и CM_FILEOPEN. В ответ на эти сообщения создается новое временное меню «Edit», которое вставляется между временными меню «File» и временным меню «Help»:
Для вставки меню вызывается функция InsertMenu:
В качестве второго параметра этой функции передается значение 1. Так как в третьем параметре указан флаг MF_BYPOSITION, функция вставит меню перед временным меню с номером 1, т. е. перед меню «Help».
Затем в меню «File» разблокируются строки «Save», «Save as. «, «Close» и блокируются строки «New» и «Open»:
В заключение вызывается функция DrawMenuBar, отображающая внесенные в меню изменения.
Если вы выберите из меню «File» строку «Close», функция окна получит сообщение WM_COMMAND со значением параметра wParam, равным CM_FILECLOSE. Соответствующий обработчик уничтожает временное меню «Edit» (документ закрыт, редактировать нечего), и удаляет соответствующую строку из меню верхнего уровня:
После этого в меню «File» блокируются строки «Save», «Save as. «, «Close» и разблокируются строки «New» и «Open». Для этой цели вызывается функция EnableMenuItem. Для отображения внесенных изменений вызывается функция DrawMenuBar.
При завершении работы приложения мы проверяем содержимое переменной hmenuEdit. Если в момент завершения работы приложения меню «Edit» не существует, в этой переменной находится значение NULL. В этом случае мы не вызываем функцию DestroyWindow. Остальные меню уничтожаются всегда:
Несмотря на то, что при уничтожении окна все связанные с ним меню также уничтожаются, будет лучше, если ваше приложение удалит все созданные им объекты самостоятельно. Такое поведение отвечает правилам «хорошего тона» для приложений Windows, которые совместно используют многие системные ресурсы.
Идентификаторы строк меню описаны во включаемом файле dmenu.hpp (листинг 1.6).
Листинг 1.6. Файл dmenu/dmenu.hpp
Файл определения модуля приложения приведен в листинге 1.7.
Листинг 1.7. Файл dmenu/dmenu.rc
1.7. Системное меню
При необходимости вы можете изменить системное меню (рис. 1.6), добавив в него новые строки или горизонтальные разделительные линии.
Прежде всего вам надо получить идентификатор системного меню. Это можно сделать при помощи функции GetSystemMenu :
Параметр hwnd является идентификатором окна, к системному меню которого требуется получить доступ.
Параметр fRevert определяет действия, выполняемые функцией GetSystemMenu. Если этот параметр указан как FALSE, функция GetSystemMenu возвращает идентификатор используемой на момент вызова копии системного меню. Если же значение этого параметра равно TRUE, функция восстанавливает исходный вид системного меню, используемый в Windows по умолчанию и уничтожает все созданные ранее копии системного меню. В последнем случае возвращаемое значение не определено.
После того как вы получили идентификатор системного меню, вы можете использовать функции AppendMenu, InsertMenu или ModifyMenu для изменения внешнего вида системного меню.
Есть одна особенность, которую нужно учитывать при добавлении собственной строки в системное меню. Как мы уже говорили, младшие четыре бита в сообщении WM_SYSCOMMAND могут иметь любые значения. С учетом этого обстоятельства следует выбирать идентификатор для добавляемой в системное меню строки. Очевидно, что значение этого идентификатора должно быть больше 15 и не должно конфликтовать с идентификаторами других строк меню приложения.
Приложение SMARTPAD, которое мы рассмотрим немного позже, добавляет в системное меню разделительную линию и новую строку, а также блокирует строку «Close», предназначенную для удаления окна.
Вначале в этом приложении мы определяем идентификатор системного меню, вызывая функцию GetSystemMenu:
Далее к системному меню добавляется разделительная линия и строка «About. «, для чего используется уже знакомая вам функция AppendMenu:
В качестве идентификатора мы использовали значение 0x8880 (младшие четыре бита равны нулю):
Для блокирования строки «Close» мы вызываем функцию EnableMenuItem, указывая ей в качестве первого параметра идентификатор системного меню:
Обработчик сообщения WM_SYSCOMMAND, определенный в функции главного окна приложения SMARTPAD, проверяет значение параметра wParam на совпадение с идентификатором добавленной нами строки без учета младших четырех бит:
Для того чтобы заблокировать строку «Close», мы выполняем обработку сообщения WM_SYSCOMMAND с параметром wParam, равным SC_CLOSE (идентификатор стандартной строки «Close» в системном меню). Обработка заключается в возврате нулевого значения.
Так как ранее мы уже заблокировали эту строку при помощи функции EnableMenuItem, нет необходимости выполнять еще одну блокировку в обработчике сообщения WM_SYSCOMMAND. Мы сделали это исключительно для иллюстрации возможности блокировки строки системного меню при обработке сообщения WM_SYSCOMMAND.
1.8. Плавающее меню
При необходимости ваше приложение может создать временное плавающее меню , расположенное в любом месте экрана (рис. 1.7).
В приложении SMARTPAD мы создаем плавающее меню, когда пользователь нажимает в окне редактирования текста правую клавишу мыши. Процедура создания меню выглядит следующим образом:
Обработчик сообщения WM_RBUTTONDOWN, которое приходит, если вы нажимаете правую клавишу мыши, прежде всего преобразует координаты курсора мыши в экранные. Для этого он вызывает функцию ClientToScreen .
Далее при помощи функции CreatePopupMenu создается пустое временное меню. Это меню наполняется обычным образом с помощью функции AppendMenu, но оно не привязывается к главному меню приложения или какому-либо другому меню. Вместо этого создается плавающее меню. Для этого идентификатор созданного и наполненного временного меню передается функции TrackPopupMenu :
Эта функция выводит на экран плавающее меню и создает свой собственный цикл обработки сообщений, завершающий работу после выбора строки. Поэтому функция TrackPopupMenu не возвращает управление до тех пор, пока работа с меню не будет завершена либо выбором строки, либо отказом от выбора.
После этого созданное временное меню уничтожается:
Приведем прототип функции TrackPopupMenu :
Параметр hmenu должен содержать идентификатор отображаемого временного меню. Вы можете создать новое меню при помощи функции CreatePopupMenu или получить идентификатор существующего временного меню, вызвав функцию GetSubMenu.
Параметр fuFlags определяет расположение плавающего меню и клавиши мыши, с помощью которых должен выполняться выбор.
Для определения расположения меню вы можете указать один из трех флагов:
Флаг | Описание |
TPM_CENTERALIGN | Центровка относительно координаты, заданной параметром x |
TPM_LEFTALIGN | Выравнивание по левой границе относительно координаты, заданной параметром x |
TPM_RIGHTALIGN | Выравнивание по правой границе относительно координаты, заданной параметром x |
Дополнительно к перечисленным выше флагам вы можете указать один из двух флагов, определяющий клавишу мыши, предназначенную для выбора строки из плавающего меню:
Флаг | Описание |
TPM_LEFTBUTTON | Левая клавиша мыши |
TPM_RIGHTBUTTON | Правая клавиша мыши |
Параметр nReserved зарезервирован, для совместимости со следующими версиями операционной системы Windows его значение должно быть равно 0.
Параметр hwnd задает идентификатор окна, которое получит сообщение WM_COMMAND после того как пользователь сделает выбор из плавающего меню. В операционной системе Windows версии 3.1 это сообщение попадает в функцию указанного окна после того как функция TrackPopupMenu возвратит управление. В версии 3.0 сообщение WM_COMMAND попадало в функцию окна до возврата управления функцией TrackPopupMenu.
Параметр lprc является указателем на структуру типа RECT, определяющую координаты прямоугольной области, в которой пользователь может выполнять выбор из меню. Если сделать щелчок мышью за пределами этой области, плавающее меню исчезнет с экрана. Такие действия эквивалентны отказу от выбора. Если задать для этого параметра значение NULL, размеры и расположение указанной выше прямоугольной области будут совпадать с размерами плавающего меню.
1.9. Использование плавающего меню в органе управления EDIT
Как вы знаете, орган управления, созданный на базе предопределенного класса «edit», является простым редактором текста. В приложении SMARTPAD, которое будет описано немного позже, используется интересный прием, позволяющий вызвать на экран плавающее меню простым нажатием правой клавиши мыши внутри окна редактирования. Причем меню окажется как раз около курсора мыши, так что для работы с меню вам не придется передвигать мышь на большое расстояние.
Для редактора текста внутри операционной системы Windows определена функция окна, выполняющая всю работу по редактированию текста, выделению фрагментов текста, копирование выделенного фрагмента в универсальный буфер обмена Clipboard и т. д. Когда вы устанавливаете курсор мыши в окно редактирования и нажимаете правую клавишу мыши, сообщение WM_RBUTTONDOWN попадает в функцию окна редактора текста.
Однако функция родительского окна, создавшая редактор текста, получает только сообщение с кодом WM_COMMAND, да и то только при выполнении определенных операций с текстом. Поэтому сколько бы вы не нажимали правую кнопку мыши в окне редактора текста, родительское окно об этом никогда не узнает.
Как же нам быть? Ведь нам надо не только определить момент, в который пользователь нажал правую кнопку мыши, но и узнать текущие координаты курсора мыши, чтобы создать плавающее меню в нужном месте экрана (недалеко от курсора мыши).
Так как встроенная функция окна, используемая редактором текста, перехватывает сообщение WM_RBUTTONDOWN и «не выпускает» его наружу, нам надо вставить собственный обработчик сообщений перед стандартным для класса окна «edit».
Программный интерфейс Windows позволяет нам это сделать.
Определим в программе две переменные:
Эти переменные будут использоваться для хранения, соответственно, указателя на старую функцию окна редактора текста и указателя на новую функцию окна редактора текста.
Для получения адреса функции окна редактора текста мы воспользуемся функцией GetWindowLong :
Если в качестве второго параметра этой функции передать константу GWL_WNDPROC , функция вернет адрес функции окна, идентификатор которого задан первым параметром. Возвращенное функцией GetWindowLong значение мы сохраним в переменной lpfnEditOldWndProc, так как наша функция окна, встроенная до стандартной, после выполнения своей задачи должна вызвать стандартную функцию окна (иначе редактор текста не будет работать).
Итак, адрес старой функции окна мы узнали. Теперь надо подготовить новую функцию окна, которая, если пользователь нажмет на правую клавишу мыши, будет выводить на экран плавающее меню. Вот эта функция:
Обратите внимание, что после завершения работы новая функция окна вызывает старую функцию окна. Так как ваше приложение не может вызывать функцию окна непосредственно, мы вызываем старую функцию окна при помощи функции CallWindowProc .
Таким образом, мы сделали то, что нам нужно — новая функция окна обрабатывает сообщение от правой клавиши мыши, выводит плавающее меню и затем вызывает стандартную функцию окна текстового редактора.
Однако для того чтобы вместо стандартной функции окна вызывалась наша, ее необходимо подключить при помощи функции SetWindowLong :
Перед вызовом функции мы создаем переходник и сохраняем его адрес в переменной lpfnEditWndProc.
Сразу после возвращения управления из функции SetWindowLong наша новая функция окна включается в работу, пропуская через себя все сообщения, предназначенные для стандартной функции окна редактора текста.
Описанная выше методика обычно используется в тех случаях, когда нужно изменить поведение стандартного органа управления или любого стандартного окна Windows с известным идентификатором (зная который можно «добраться» до функции окна).
1.10. Акселераторы
Для ускорения доступа к строкам меню при помощи клавиатуры (а также для назначения тех или иных функций, не связанных с меню, комбинациям клавиш), используется так называемая таблица акселераторов (accelerator table ).
Таблица акселераторов находится в ресурсах приложения и определяет соответствие между комбинациями клавиш и значением параметра wParam сообщения WM_COMMAND, попадающего в функцию окна, когда вы нажимаете эти комбинации клавиш.
Например, вы можете определить, что комбинации клавиш соответствует значение wParam, равное CM_EDITCUT. В этом случае если нажать указанную выше комбинацию клавиш, в функцию окна попадет сообщение WM_COMMAND с параметром wParam, равным CM_EDITCUT.
Обычно комбинации клавиш, используемые для ускоренного выбора (или просто акселераторы) обозначаются в правом столбце меню (рис. 1.17).
Рис. 1.17. Акселераторы в меню «Edit»
Однако такое обозначение, сделанное при помощи символа \t в шаблоне меню не распознается Windows, а служит лишь для удобства пользователя. Для того чтобы комбинация клавиш стала работать как акселератор, она должна быть описана в таблице акселераторов. Кроме этого, приложение должно загрузить таблицу акселераторов из ресурсов приложения и изменить цикл обработки сообщений.
Описание таблицы акселераторов
Таблица акселераторов определяется в файле описания ресурсов приложения в следующем виде:
Для ссылки на таблицу акселераторов используется идентификатор Id, который не должен совпадать с идентификаторами других ресурсов приложения, таких как строки, диалоги и т. д.
Между операторами BEGIN и END располагаются строки описания акселераторов. Они имеют следующий формат (в квадратных скобках указаны необязательные параметры):
Поле Key определяет клавишу, которая будет использована для создания акселератора. Вы можете использовать символ в коде ASCII, заключенный в двойные кавычки (например, «F»), комбинацию символа ASCII со знаком ^ (например, «^S», что соответствует комбинации клавиш ), ASCII-код клавиши в виде целого значения, или виртуальный код клавиши (в символьном или цифровом виде).
Поле AccId соответствует значению параметра wParam сообщения WM_COMMAND, которое попадет в функцию окна при использовании акселератора.
Поле KeyTab может принимать значения ASCII или VIRTKEY. В первом случае поле Key определяет клавишу с использованием кода ASCII, во втором — с использованием кода виртуальной клавиши. По умолчанию используется значение ASCII.
Если указан параметр NOINVERT, при использовании акселератора соответствующая строка меню не выделяется. По умолчанию строка меню выделяется инвертированием цвета.
Если поле KeyTab содержит значение VIRTKEY, можно указывать параметры ALT, SHIFT или CONTROL. В этом случае для акселератора используется комбинация клавиши, указанной параметром Key, и клавиши ALT, SHIFT или CONTROL, соответственно.
Приведем пример описания таблицы акселераторов из приложения SMARTPAD:
Здесь описана таблица акселераторов APP_ACCELERATORS, в которой определены девять акселераторов, т. е. девять комбинаций клавиш ускоренного выбора.
Для того чтобы акселератор, состоящий из комбинации символьной клавиши (такой, как «N») и клавиши , работал вне зависимости от состояния клавиши , мы использовали виртуальные коды. Если бы мы использовали коды ASCII, наш акселератор активизировался бы только при использовании заглавных букв (мы могли бы указать строчные буквы, например, «n», в этом случае для активизации акселератора следовало бы использовать строчные буквы).
Из-за того что клавиша может находиться в любом состоянии, лучше работать с виртуальными кодами клавиш, не зависящих от того, являются буквы строчными или прописными.
Напомним, что коды виртуальных клавиш описаны в файле windows.h.
Загрузка таблицы акселераторов
Для загрузки таблицы акселераторов следует использовать функцию LoadAccelerators :
Параметр hInst определяет идентификатор копии приложения, из ресурсов которого будет загружена таблица акселераторов.
Параметр lpszTableName является указателем на строку, содержащую идентификатор таблицы акселераторов. Если для идентификации ресурса используется целое значение, оно должно быть преобразовано макрокомандой MAKEINTRESOURCE.
Функция LoadAccelerators возвращает идентификатор загруженной таблицы акселераторов или NULL при ошибке.
Загруженная таблица акселераторов автоматически уничтожается при завершении работы приложения.
Приложение SMARTPAD работает с таблицей акселераторов и загружает ее следующим образом:
Изменения в цикле обработки сообщений
Для использования акселераторов цикл обработки сообщений должен выглядеть следующим образом:
В этом фрагменте кода переменная haccel содержит идентификатор загруженной таблицы акселераторов. Если идентификатор не равен NULL, вызывается функция TranslateAccelerator . Эта функция ищет в очереди сообщений сообщения от клавиатуры, соответствующие определенным в ресурсах приложения акселераторам, преобразуя такие сообщения в сообщения WM_COMMAND и WM_SYSCOMMAND (если сообщение соответствует системному меню), передаваемые непосредственно в функцию окна, минуя очередь сообщений приложения .
Содержимое параметра wParam в последних двух сообщениях равно идентификатору, указанному в таблице акселераторов для данной комбинации клавиш.
Старшее слово параметр lParam содержит 1 для сообщений, которые пришли от акселераторов и 0 для сообщений, которые пришли от меню.
Приведем прототип функции TranslateAccelerator:
Параметр hwnd определяет идентификатор окна, для которого выполняется преобразование клавиатурных сообщений.
Параметр haccel должен содержать идентификатор загруженной при помощи функции LoadAccelerators таблицы акселераторов.
Последний параметр lpmsg является указателем на структуру типа MSG, в которую должно быть записано обрабатываемое сообщение.
Если функция TranslateAccelerator выполнила преобразование сообщения, она возвращает ненулевое значение. В противном случае возвращается 0. Обработанное сообщение не следует передавать функциям TranslateMessage и DispatchMessage.
1.11. Орган управления TOOLBAR
Только что вы узнали об акселераторах, используемых для упрощения работы с меню. В современных приложениях Windows широко используется еще один важный элемент пользовательского интерфейса, облегчающий работу с меню (и в некоторых случаях даже полностью заменяющий меню). Речь идет об органе управления, который часто называется Toolbar.
На рис. 1.18 показан Toolbar, расположенный под главным меню приложения Microsoft Word for Windows версии 2.0.
Рис. 1.18. Орган управления Toolbar в текстовом процессоре Microsoft Word for Windows версии 2.0
Toolbar с точки зрения пользователя представляет собой ни что иное, как набор кнопок с нарисованными на их поверхности пиктограммами. Каждая такая кнопка соответствует определенной строке в том или ином временном меню приложения. Например, самая левая кнопка на рис. 1.18 соответствует строке «New» из меню «File». Однако с кнопкой может быть связана и такая функция, для которой нет соответствия в меню приложения.
С точки зрения программиста орган управления Toolbar может представлять собой отдельный объект в виде дочернего окна с расположенными на нем кнопками или совокупность кнопок, созданных на поверхности главного окна приложения. Можно использовать и другие варианты построения Toolbar. К сожалению, в операционной системе Microsoft Windows версии 3.1 нет стандартного органа управления, способного выполнять функции Toolbar, поэтому программист должен создавать его самостоятельно.
Вы можете сделать Toolbar из стандартных кнопок, однако обычно используются кнопки, которые рисует родительское окно (т. е. имеющие стиль BS_OWNERDRAW).
В приложении SMARTPAD мы создали Toolbar как дочернее окно с расположенными на его поверхности кнопками стиля BS_OWNERDRAW. Когда пользователь нажимает на одну из кнопок, расположенных в окне Toolbar, в функцию родительского окна, создавшего Toolbar, приходит сообщение WM_COMMAND. Параметр wParam этого сообщения однозначно соответствует расположению кнопки в окне Toolbar.
Наш Toolbar создан как класс в терминах языка программирования C++. Вы можете изменять его, приспосабливая для ваших нужд, или определять на его основе новые классы. Например, можно сделать Toolbar, расположенный в окне приложения по вертикали, или создать для Toolbar отдельное перекрывающееся окно.
1.12. Приложение SMARTPAD
Для иллюстрации всего сказанного выше относительно использования меню и органа управления Toolbar мы приведем исходные тексты приложения SMARTPAD, которое реализует основные функции, связанные с редактированием текста (рис. 1.19).
Рис. 1.19. Главное окно приложения SMARTPAD
Так как мы пока еще не умеем работать с принтерами и шрифтами, первая версия нашего редактора текста несколько ограничена. Кроме того, пока не реализованы функции меню «Help». Тем не менее это приложение имеет Toolbar, использует акселераторы для доступа к основным функциям, модифицирует системное меню и по щелчку правой клавиши мыши создает в окне редактирования плавающее меню.
На примере этого приложения мы демонстрируем не только способы работы с различными типами меню, но и способ «перехвата» управления у функции окна органа управления класса «edit».
Орган управления Toolbar выделен в отдельный класс (в терминах языка программирования С++), исходные тексты которого находятся в двух файлах. Вы сможете с помощью этого класса без труда (почти) создавать в приложениях свой собственный Toolbar.
Основной файл приложения SMARTPAD приведен в листинге 1.8.
Листинг 1.8. Файл smartpad/smartpad.cpp
В области глобальных переменных среди прочих определений располагается определение указателя на класс Toolbar:
Через этот указатель (разумеется, после создания объекта и инициализации указателя) будет выполняться одна из операций, определенных для Toolbar, — создание кнопки в заданной позиции.
Отметим также переменную bNeedSave типа BOOL, которая используется как признак необходимости сохранения редактируемого текста в файле.
В массиве szCurrentFileName[128] хранится путь к редактируемому файлу. Эта информация используется для формирования заголовка главного окна приложения и для сохранения файла при помощи строки «Save» из меню «File» или кнопки в Toolbar с изображением дискеты.
С помощью строки «Read Only» меню «Options» вы можете запретить редактирование текста. При этом в глобальную переменную bReadOnly типа BOOL записывается значение TRUE.
Три глобальные переменные используются для хранения, соответственно, адреса функции диалога, появляющегося при выборе строки «About. » (рис. 1.20), адреса стандартной функции диалога редактора текста и новой функции диалога, необходимой для вывода плавающего меню.
Рис. 1.20. Диалоговая панель «About» приложения SMARTPAD
Функция WinMain инициализирует приложение обычным образом и загружает основное меню из ресурсов приложения, вызывая функцию LoadMenu. Далее создается главное окно приложения, идентификатор которого сохраняется в глобальной переменной hwndMain.
После отображения главного окна создается орган управления Toolbar :
Конструктору объекта Toolbar передается идентификатор копии приложения hInstance, идентификатор окна, в котором необходимо расположить Toolbar и функция которого будет получать сообщение WM_COMMAND, и константу TB_FIRST, определяющую значение параметра wParam сообщения WM_COMMAND для самой левой кнопки в органе управления Toolbar. Для второй кнопки слева значение этого параметра будет равно TB_FIRST + 1, для третьей TB_FIRST + 2, и т. д.
Далее функция WinMain создает все необходимые кнопки, вызывая метод InsertButton, определенный в классе Toolbar:
Первый параметр функции InsertButton определяет расположение кнопки в области, выделенной для ToolBar. Обратите внимание, что номера кнопок увеличиваются не монотонно. После кнопки с номером 2 следует кнопка с номером 4, а после кнопки с номером 7 следует кнопка с номером 9. Пропущенным номерам соответствуют пустые позиции в окне Toolbar.
Учтите, что параметр wParam сообщения WM_COMMAND, получаемого от Toolbar, зависит от номера позиции и от значения константы TB_FIRST, переданной конструктору при создании класса. Так как мы не создали кнопки с номерами 3 и 8, функция главного окна приложения никогда не получит сообщение WM_COMMAND с параметром wParam, равным TB_FIRST + 3 и TB_FIRST + 8.
Второй, третий и четвертый параметры функции InsertButton должны содержать идентификаторы изображений bitmap для кнопки в нормальном, нажатом и неактивном состоянии, соответственно.
После создания кнопок функция окна приложения будет получать от Toolbar сообщение WM_COMMAND.
Таким образом, использование класса Toolbar предельно просто. Вы должны создать объект класса Toolbar, указав идентификатор копии приложения, идентификатор главного окна приложения (или другого окна, которое будет содержать Toolbar). Затем вам надо вставить кнопки, вызвав несколько раз функцию InsertButton, которая является методом класса Toolbar. После этого орган управления Toolbar начинает работать, посылая в функцию окна сообщение WM_COMMAND.
Для установки ширины дочернего окна Toolbar определена функция SetWidth. Вы должны вызывать эту функцию в функции главного окна приложения при обработке сообщения WM_SIZE:
Класс Toolbar определен в файле toolbar.hpp, поэтому в исходный текст программы необходимо включить следующую строку:
После создания Toolbar функция WinMain загружает с помощью функции LoadAccelerators таблицу акселераторов, используемую для ускоренного доступа к строкам меню, после чего запускается цикл обработки сообщений. Для работы с акселераторами в цикле обработки сообщений вызывается функция TranslateAccelerators. Для получения символьных сообщений мы должны также вызывать в этом цикле функцию TranslateMessage.
Новая функция окна для редактора текста EditWndProc перехватывает сообщение WM_RBUTTONDOWN, возникающее в тот момент, когда пользователь нажимает правую кнопку мыши, и выводит плавающее меню.
Координаты курсора мыши передаются через параметр lParam. Эти координаты вычислены относительно верхнего левого угла внутренней области окна (client region). Так как функция TrackPopupMenu, создающая плавающее меню, использует экранные координаты, мы выполняем соответствующее преобразование с помощью функции ClientToScreen.
Если обработка сообщения от мыши завершена или пришло другое сообщение, предназначенное для функции окна редактора текста, новая функция окна EditWndProc передает сообщение без изменений стандартной функции окна через переходник lpfnEditOldWndProc:
Теперь рассмотрим работу функции главного окна приложения, которая называется WndProc.
При создании главного окна приложения управление получает обработчик сообщения WM_CREATE. Он создает стандартный редактор текста на базе предопределенного класса окна «edit».
Для того чтобы придать редактируемому тексту более привлекательный вид, изменяем шрифт, используемый редактором текста на шрифт ANSI с переменной шириной букв:
Подробное описание этой операции и сообщения WM_SETFONT мы отложим до главы, посвященной шрифтам.
Далее обработчик сообщения WM_CREATE создает переходник для новой функции окна редактора текста, определяет адрес старой (т. е. стандартной) функции окна редактора текста и подключает новую функцию окна. Этот процесс был описан раньше.
После этого устанавливается максимальная длина редактируемого текста, инициализируются флаги, устанавливается новый заголовок главного окна приложения.
Хотя в этом нет никакой необходимости, приложение SMARTPAD изменяет системное меню. Мы сделали это исключительно для иллюстрации методов работы с системным меню.
Сначала с помощью функции GetSystemMenu мы определяем идентификатор системного меню. Затем в системное меню добавляется горизонтальная разделительная линия и строка «About. «, при выборе которой на экране появляется диалоговая панель ‘About». Для добавления используется функция AppendMenu.
Мы также блокируем строку «Close» в системном меню, для чего вызываем функцию EnableMenuItem. Напомним, что все стандартные строки системного меню имеют идентификаторы, для которых в файле windows.h определены символические константы. В честности, строка «Close» имеет идентификатор SC_CLOSE.
Обработчик сообщения WM_SIZE устанавливает новую ширину дочернего окна Toolbar и новый размер редактора текста:
Обработчик сообщения WM_FOCUS передает фокус окну редактора текста, вызывая функцию SetFocus.
Для обработки сообщений от системного меню в функции главного окна приложения предусмотрен обработчик сообщения WM_SYSCOMMAND. Мы уже рассказывали вам об особенности этого сообщения — перед сравнением младшие четыре бита параметра wParam необходимо замаскировать.
Обработчик сообщения WM_SYSCOMMAND реагирует на добавленную нами в системное меню строку «About. » с идентификатором CM_SYSABOUT. Дополнительно мы перехватываем сообщение от строки «Close» и «изымаем» его, блокируя работу соответствующей строки.
Обработчик сообщения WM_COMMAND получился достаточно сложным, так как наше приложение имеет большое меню и Toolbar. Все основные выполняемые функции объясняются в комментариях, поэтому мы для экономии места остановимся только на некоторых моментах.
Обработка извещений от редактора текста выполняется аналогично тому, как это сделано в приложении TEDIT, описанном в предыдущем томе «Библиотеки системного программиста».
При выборе строки «Read Only» из меню «Options» инвертируется содержимое флага запрета редактирования bReadOnly. Если этот флаг находился в состоянии FALSE, редактору текста посылается сообщение EM_SETREADONLY с параметром WParam, равном TRUE, после чего содержимое флага меняется на TRUE. После этого строка «Read Only» отмечается галочкой при помощи функции CheckMenuItem.
Если выбрать эту строку еще раз, запрет редактирования отменяется, флаг запрета редактирования bReadOnly снова инвертируется, вслед за чем удаляется отметка в строке меню.
Практически после выполнения всех операций, отнимающих фокус ввода у текстового редактора, мы возвращаем фокус редактору, вызывая функцию SetFocus.
Обратите внимание на обработчик сообщения WM_QUERYENDSESSION. Это сообщение передается приложению перед завершением работы операционной системы Windows. Приложение может запретить завершение работы Windows, вернув нулевое значение, или разрешить, вернув значение 1. Наше приложение в ответ на это сообщение проверяет состояние флага bNeedSave. Если текст не был сохранен, на экран выводится соответствующий запрос. Если в ответ на этот запрос вы нажмете клавишу «Yes», текст будет сохранен в файле. После этого обработчик сообщения WM_QUERYENDSESSION возвращает 1, разрешая операционной системе завершить свою работу.
Файл smartpad.hpp содержит определения всех используемых в файле smartpad.cpp символических констант (листинг 1.9).
Листинг 1.9. Файл smartpad/smartpad.hpp
Обратите внимание на описание идентификатора строки «About. » системного меню:
Значение этого идентификатора должно отличаться от значений других идентификаторов строк меню, причем младшие четыре бита не должны участвовать в сравнении.
В файле smartpad.rc (листинг 1.10) описаны ресурсы приложения.
Листинг 1.10. Файл smartpad/smartpad.rc
В файле описания ресурсов определена таблица акселераторов APP_ACCELERATORS. Эта таблица устанавливает соответствие между виртуальными кодами клавиш, используемых для ускоренного выбора функций из меню и соответствующие идентификаторы.
В листинге 1.11 изображены файлы *.bmp, на которые есть ссылки в файле описания ресурсов.
Листинг 1.11. Файлы smartpad/*.bmp
Определение класса Toolbar, предназначенного для создания органа управления Toolbar, находится в файле toolbar.hpp (листинг 1.12).
Листинг 1.12. Файл smartpad/toolbar.hpp
В этом файле определен также класс TbMain, все члены которого описаны как статические. Такой класс можно использовать вместо набора глобальных переменных, что улучшает структуру программы.
В классе TbMain хранится идентификатор приложения hInst, три массива, в которых хранятся идентификаторы изображений bitmap для кнопок в исходном (hbmpUp), нажатом (hbmpDown) и заблокированном (hbmpGrayed) состоянии, идентификатор родительского окна, на поверхности которого создается Toolbar, идентификатор самой левой кнопки в окне Toolbar (nFirstId). Все перечисленные выше переменные должны быть доступны для методов класса Toolbar и для функции окна Toolbar.
В классе Toolbar определены переменные, предназначенные для хранения размеров родительского окна и окна Toolbar, имени класса Toolbar, идентификаторов кнопок, кода ошибки.
Метод GetRect предназначен для определения размеров дочернего окна Toolbar, на поверхности которого создаются кнопки. Этот метод вызывает функции GetRectLeft, GetRectTop, GetRectRight, GetRectBottom, определяющие соответственно расположение левой, верхней, правой и нижней границ дочернего окна.
Вы можете создать свой класс как дочерний для класса Toolbar и переопределить все или некоторые из перечисленных функций, создав, например, вертикальный Toolbar.
Метод RegisterWndClass регистрирует класс для дочернего окна Toolbar. Этот метод использует функцию GetBrush для определения кисти, используемой для закраски поверхности дочернего окна. В классе Toolbar используется светло-серая кисть. Создавая собственный класс на базе класса Toolbar вы можете переопределить функцию GetBrush и закрасить поверхность дочернего окна в любой цвет.
Метод CreateTbWindow создает дочернее окно Toolbar. Перед вызовом этого метода необходимо с помощью метода GetRect определить размеры и расположение дочернего окна органа управления Toolbar.
Для того чтобы при изменении размеров основного окна обеспечить соответствующее изменение размеров окна Toolbar, в классе Toolbar определен метод SetWidth. Единственный параметр nWidth должен содержать значение новой ширины окна. Метод SetWidth необходимо вызывать из функции главного окна приложения (или другого окна, на поверхности которого расположен Toolbar) при обработке сообщения WM_SIZE.
Если вы создаете вертикальный Toolbar, вы можете определить в своем классе, созданном на базе класса Toolbar, функцию SetHeight, изменяющую высоту дочернего окна Toolbar.
Для вставки в Toolbar кнопки вы должны вызвать метод InsertButton.
Параметр NPosition определяет расположение кнопки на поверхности Toolbar и идентификатор кнопки, передаваемый в родительское окно через параметр wParam сообщения WM_COMMAND. Идентификатор кнопки зависит от расположения кнопки в окне Toolbar и определяется при помощи следующего выражения:
Таким образом, самой левой кнопке в горизонтальном органе управления Toolbar соответствует идентификатор TbMain::nFirstId, значение которого вы задаете при вызове конструктора класса Toolbar:
Дополнительно вы должны указать конструктору идентификатор текущей копии приложения hInst и идентификатор родительского окна, на поверхности которого расположен Toolbar. Определение конструктора и деструктора класса Toolbar находится в файле toolbar.cpp (листинг 1.13).
Среди других методов, определенных в классе Toolbar, отметим метод GetBtnX. Этот метод используется для вычисления X-координаты кнопки в окне Toolbar в зависимости от ее номера. Если вы создаете свой Toolbar на базе класса Toolbar, вы можете использовать другой алгоритм размещения кнопок, переопределив эту функцию, а также функцию GetBtnY, предназначенную для вычисления Y-координаты кнопки.
По умолчанию для кнопок используются изображения bitmap размером 30 х 20 пикселов. Если вам нужны кнопки другого размера, переопределите методы GetBmpWidth и GetBmpHeight.
В файле toolbar.cpp (листинг 1.13) находятся определения некоторых методов класса Toolbar, членов класса TbMain и функции дочернего окна Toolbar.
Листинг 1.13. Файл smartpad/toolbar.cpp
Конструктор класса Toolbar сбрасывает признак ошибки errno, инициализирует члены класса TbMain, определяет размеры внутренней области родительского окна, размеры дочернего окна, регистрирует класс дочернего окна и создает само дочернее окно.
Работа деструктор заключается в уничтожении дочернего окна, для чего используется функция DestroyWindow.
Функция дочернего окна ToolbarWndProc обрабатывает сообщение WM_COMMAND, поступающее от кнопок, и формирует это же сообщение для дочернего окна. Кроме того, эта функция обеспечивает работу кнопок, для чего в ней предусмотрены обработчик сообщения WM_DRAWITEM. Этот обработчик вызывает функцию DrawButton, предназначенную для рисования кнопок.
Функция DrawButton рисует кнопку в нужном виде, выбирая идентификаторы соответствующих изображений bitmap из массивов, определенных в классе TbMain. Для рисования изображения вызывается функция DrawBitmap (листинг 1.14). Мы уже пользовались этой функцией.
Листинг 1.14. Файл smartpad/drawbmp.cpp
Файл определения модуля для приложения SMARTPAD приведен в листинге 1.15.
Листинг 1.15. Файл smartpad/smartpad.def
1.13. Графика в меню
До сих пор наши меню состояли только из текстовых строк и разделительных линий, однако вы можете сделать меню из произвольных графических изображений. Если вам не нравится стандартная отметка строк меню при помощи галочки, ее можно заменить на любое графическое изображение (небольшого размера).
Для того чтобы вместо строк в меню расположить графические изображения bitmap, эти изображения надо загрузить из ресурсов или создать другим способом, а затем идентификатор изображения указать в качестве последнего параметра функций AppendMenu или InsertMenu. Необходимо также использовать флаг MF_BITMAP :
Если вы загрузили bitmap при помощи функции LoadBitmap, не забудьте перед завершением приложения (или после удаления соответствующего меню) удалить bitmap функцией DeleteObject.
Для замены стандартного символа отметки строки меню (галочки) на другой предназначена функция SetMenuItemBitmaps:
Эта функция выполняет замену символа отметки для строки idItem меню hmenu.
Для параметра fuFlags можно использовать два значения — MF_BYCOMMAND и MF_BYPOSITION . Если указан флаг MF_BYCOMMAND, параметр idItem определяет идентификатор элемента меню, для которого выполняется замена символа отметки. Если указан флаг MF_BYPOSITION, параметр idItem определяет порядковый номер элемента меню.
Параметр hbmUnckecked представляет собой идентификатор изображения, которое будет расположено слева от неотмеченной строки меню, параметр hbmChecked — идентификатор изображения символа отметки.
Любой из последних параметров или оба можно указывать как NULL. В этом случае будет использовано изображение по умолчанию (т. е. слева от неотмеченной строки не будет никакого изображения, слева от отмеченной — галочка).
Однако есть небольшая тонкость. Вы не можете использовать для отметки строк меню изображения bitmap любого размера. Нужные размеры изображения необходимо определить при помощи функции GetMenuCheckMarkDimensions :
Младшее слово возвращаемого значения содержит ширину изображения, старшее — высоту:
Тонкость заключается в том, что на момент трансляции исходного текста приложения вы не можете знать требуемые размеры изображения. Так как на этапе сборки загрузочного модуля приложения размеры изображения неизвестны, вы (строго говоря) не можете просто загрузить соответствующие изображения bitmap из ресурсов приложения.
Выход заключается в том, чтобы в процессе инициализации приложения определить требуемые размеры изображения, вызвав функцию GetMenuCheckMarkDimensions, а затем подготовить нужные изображения bitmap в памяти. Однако, так как мы еще не рассказывали вам подробно об изображениях bitmap, в примере GMENU, приведенном в следующем разделе, мы для простоты (данная глава посвящена меню, а не изображениям bitmap) все-таки загрузили изображения размером 10 х 10 пикселов из ресурсов.
При создании строки меню вы можете указать константу MF_OWNERDRAW. В этом случае функция окна, работающая с данным меню, должна будет сама нарисовать строку меню. Можно нарисовать любое изображение.
Перед тем как отобразить меню, содержащее строки со стилем MF_OWNERDRAW , операционная система Windows посылает в функцию окна сообщение WM_MEASUREITEM . В ответ на это сообщение функция должна сообщить Windows размеры окна, необходимые для изображения строки меню.
Когда надо отобразить строку меню, Windows посылает в родительское окно сообщение WM_DRAWITEM . Вместе с этим сообщением передается вся информация, необходимая родительскому окну для того чтобы нарисовать строку меню.
Параметр lParam сообщения WM_MEASUREITEM содержит указатель на структуру MEASUREITEMSTRUCT , описанную в файле windows.h:
В этом же файле описаны ближний и дальний указатели на эту структуру:
Когда функция окна получает сообщение WM_MEASUREITEM, поле CtlType содержит значение ODT_MENU, в поле itemID находится идентификатор строки меню, а в поле itemData — 32-разрядное значение, переданное через параметр lpNewItem функций AppendMenu, InsetMenu, ModifyMenu. Поле CtlID не используется.
Получив сообщение WM_MEASUREITEM, функция окна должна, пользуясь значением указателя из lParam, записать в поле itemWidth ширину строки меню, а в поле itemHeight — высоту строки меню.
Параметр lParam сообщения WM_DRAWITEM содержит указатель на структуру DRAWITEMSTRUCT . Эта структура и соответствующие указатели описаны в файле windows.h следующим образом:
Приведем назначение отдельных полей структуры DRAWITEMSTRUCT при ее использовании для меню.
Имя поля | Описание |
CtlType | Тип органа управления. Для меню принимает значение ODT_MENU |
CtlID | Идентификатор органа управления. Для меню не используется |
itemID | Идентификатор строки меню |
itemAction | Действия, которые необходимо выполнить при изображении строки меню. Определен в виде отдельных битовых флагов: ODA_DRAWENTIRE — требуется перерисовать всю строку; ODA_FOCUS — этот бит устанавливается в 1, если строка меню получила или потеряла фокус ввода, новое состояние строки можно узнать, проанализировав содержимое поля itemState; ODA_SELECT — изменилось состояние строки меню, для уточнения состояния необходимо использовать поле itemState |
itemState | Вид, в котором необходимо изобразить строку меню. Определен в виде отдельных битовых флагов: ODS_CHECKED — выбрана строка меню; ODS_DISABLED — строка неактивна; ODS_FOCUS — строка получила фокус ввода; ODS_GRAYED — строка меню должна быть изображена серым цветом; ODS_SELECTED — строка выбрана |
hwndItem | Идентификатор меню |
hDC | Контекст устройства, который необходимо использовать для рисования строки меню |
rcItem | Прямоугольные границы, внутри которых необходимо нарисовать строку |
itemData | Содержит 32-битовое значение, полученное через параметр lpNewItem функций AppendMenu, InsetMenu, ModifyMenu |
1.14. Приложение GMENU
В заключение первой главы, посвященной меню, приведем приложение GMENU, которое демонстрирует использование графики в меню. Меню верхнего уровня приложения GMENU содержит временное меню «LineStyle», которое используется для выбора одного из стилей линии (рис. 1.21).
Рис. 1.21. Графические изображения bitmap в строках меню
В данном случае использование графики из-за большей наглядности предпочтительнее текстового описания внешнего вида линий, такого как «тонкая линия», «толстая линия», пунктирная линия» и «волнистая линия».
Мы также создали собственный символ для отметки строки меню в виде закрашенного кружка (рис. 1.22).
Рис. 1.22. Отметка строки меню при помощи графического изображения bitmap
Главный файл приложения GMENU приведен в листинге 1.16.
Листинг 1.16. Файл gmenu/gmenu.cpp
При обработке сообщения WM_CREATE приложение, наряду с другими инициализирующими действиями, загружает из ресурсов приложения все необходимые для меню изображения bitmap:
Для строки «Demo Version» мы используем созданные нами и описанные в ресурсах приложения изображения bitmap, для чего вызываем функцию SetMenuItemBitmaps :
Далее мы отмечаем указанную строку:
Затем мы переходим к формированию временного меню, содержащего графические изображения. Для этого в меню hmenuLineStyle, созданное ранее как пустое, мы добавляем четыре строки:
Как видно из рис. 1.21, для строки «Line Style» используется нестандартный шрифт. Точнее говоря, для этой строки мы использовали изображение bitmap, на котором написаны слова «Line Style»:
Перед завершением работы приложения мы удаляем все загруженные изображения bitmap для освобождения системных ресурсов:
Символические константы, использованные в приложении GMENU, описаны в файле gmenu.cpp (листинг 1.17).
Листинг 1.17. Файл gmenu/gmenu.hpp
Файл описания ресурсов приложения GMENU приведен в листинге 1.18. В нем находятся ссылки на изображения bitmap, используемые для отображения строк меню.
Листинг 1.18. Файл gmenu/gmenu.rc
В листинге 1.19 приведен внешний вид этих изображений.
Листинг 1.19. Файлы gmenu/*.bmp
linestyl.bmp | |
line2.bmp | |
line3.bmp | |
line3.bmp | |
line4.bmp | |
checked.bmp | |
uncheck.bmp |
Файл определения модуля приложения GMENU приведен в листинге 1.20.