пользователей: 30398
предметов: 12406
вопросов: 234839
Конспект-online
РЕГИСТРАЦИЯ ЭКСКУРСИЯ

Команды. Реализация обработки команд с помощью ClassWizard.

Команды

Что такое команда? Это сообщение специального типа, которое формируется в тех случаях, когда пользователь выбирает пункт меню, щелкает на кнопке или каким-либо другим способом дает системе понять, что ему что-то от нее нужно. В прежних версиях Windows и выбор из меню, и щелчок на кнопке формировали сообщение WM_COMMAND. Наступили новые времена, и теперь только выбор из меню порождает сообщение WM_COMMAND, а щелчок на кнопке или выбор в списке порождает сообщение WM_NOTIFY с кодом извещения от элемента управления.

Все сообщения команд содержат в качестве первого параметра идентификатор ресурса — выбранный пункт меню или кнопку, на которой щелкнули. Этот идентификатор ресурса присваивается в соответствии со стандартом на форматы подобного рода идентификаторов, например для пункта Save As меню File идентификатор будет иметь вид ID_FILE_SAVE.

Получать сообщения могут только объекты классов-наследников CWnd, а все объекты классов, порожденных от CCmdTarget, включая CWnd и CDocument, могут получать команды и извещения. Это означает, что класс, который наследует CDocument, может иметь карту сообщений, причем в ней не должно быть ни одного компонента, соответствующего сообщению, а только компоненты для команд и извещений. Тем не менее этот фрагмент программы по-прежнему называется картой сообщений.

Вам придется позаботиться о правильном выборе классов, которые будут обрабатывать все события, которые могут произойти в разрабатываемом приложении. Если пользователь изменяет размеры окна, посылается сообщение WM_SIZE, и вам, возможно, понадобится изменить масштаб изображения или выполнить еще что-нибудь с представлением в приложении. Если пользователь выбирает некоторый пункт меню, формируется команда, а это означает, что класс документа должен что-то сделать в ответ на нее.

Обновление команд

Рассмотрим, как программа выполняет блокировку определенных пунктов меню или кнопок в соответствии с контекстом задачи. Этот процесс назван обновлением команд (command updating).

Представьте себе на минуточку, что вы разрабатываете приложение и у вас возникла идея блокировать некоторые команды меню, чтобы показать, что они в данный момент недоступны. Реализовать эту прекрасную идею можно двумя способами.

Один состоит в том, чтобы организовать огромную таблицу, элементами которой будут все имеющиеся в приложении пункты меню, каждому из которых сопоставлен флаг. Состояние флага — TRUE или FALSE — указывает, доступен ли этот пункт меню. Как только возникает необходимость вывести меню на экран, можно быстренько просмотреть таблицу и все сразу станет ясно. При любой операции, которая может повлечь за собой изменения в статусе какого-либо пункта меню, таблица обновляется. Все это в совокупности называется подходом непрерывного обновления (continuous-updating approach).

Другой подход состоит в том, чтобы, не имея такой таблицы, перед каждым выводом меню на экран анализировать все условия, которые влияют на возможную блокировку. Он называется подходом обновления по требованию (update-on-demand approach). Именно такой подход и реализован в Windows.

Когда наступает время выводить на экран меню, конкретные объекты "знают", нужно ли блокировать связанный с ними пункт меню. Например, объект класса документа знает, был ли он модифицирован после последнего сохранения, и решает, стоит ли блокировать пункт Save меню File. Объект класса представления знает, есть ли выделенный фрагмент текста, и может решить, как поступить с пунктами Cut и Copy меню Edit. Все это означает, что комплексная задача блокировки пунктов меню в соответствии с контекстом приложения распределяется между различными объектами приложения, а не возлагается на главную вызывающую подпрограмму WndProc().

Подход, реализованный в MFC, состоит в том, чтобы использовать небольшой объект класса CCmdUI (класс интерфейса с командами пользователя — command user interface) и предоставить ему возможность перехватывать любые сообщения ON_UPDATE_COMMAND_UI. Организовать такой перехват можно, добавив (или предоставив возможность ClassWizard добавить) макрос ON_UPDATE_COMMAND_UI в карту сообщений. Объект класса CCmdUI также используется для блокировки или разблокировки командных кнопок и других элементов управления.

Класс CCmdUI имеет следующие функции-члены.

•Enable(). Принимает аргумент TRUE или FALSE. Блокирует элемент интерфейса пользователя, если передан аргумент FALSE, в противном случае делает элемент доступным.

•SetCheck(). Включает или выключает элемент управления.

•SetRadio(). Включает или выключает элемент управления как принадлежащий к группе зависимых переключателей, из которых только один может быть включен.

•SetText(). Устанавливает текст надписи пункта меню или кнопки, если элемент управления — кнопка.

•DoUpdate(). Формирует сообщение.

Как правило, выбор, какая из перечисленных функций-членов нужна вам для определенных целен, очевиден. Ниже приведена упрощенная версия карты сообщений объекта класса CWhoisView, производного от CFormView, который выводит информацию на экран для пользователя. Соответствующая экранная форма имеет несколько текстовых полей, и пользователь может вставлять текст в одно из них. Карта сообщений содержит компонент перехвата обновления для команды ID_EDIT_PASTE, что в тексте программы выглядит следующим образом:

BEGIN_MESSAGE_MAP(CWhoisView, CFormView)

…ON_UPDATE_COMMAND_ID(ID_EDIT_PASTE, OnUpdateEditPaste)

…END_MESSAGE_MAP()

Функция OnUpdateEditPaste(), которая перехватывает обновление, выглядит следующим образом:

void CWhoisView::OnUpdateEditPaste(CCmdUI * pCmdUI)

(зн) pCmdUI->Enable(::IsCIipboardFormatAvailable(CF_TEXT)); зн

Здесь вызывается функция API ::IsCIipboardFormatAvailable(), которая проверяет, есть ли текст в системном буфере Clipboard. Дело в том, что другое приложение может загрузить из Clipboard изображение или другую нетекстовую информацию, но данное приложение такими возможностями не располагает. Поэтому, если в Clipboard содержится не текст, текстовое поле в экранной форме блокируется. Большинство функций обновления команд выглядит аналогично— они вызывают Enable() c аргументом, который формируется в результате вызова некоторой функции, возвращающей TRUE или FALSE, или— другой вариант— аргумент является просто логическим выражением.

Как ClassWizard помогает перехватывать команды и их обновления

В диалоговом окне ClassWizard в списке Object IDs выделено имя класса. Ниже имеются идентификаторы всех ресурсов (меню, панелей инструментов, элементов управления и т.д.), которые могут формировать команду или сообщение при условии, что объект данного класса присутствует на экране. Если вы выделите один из них, то список связанных с ним сообщений Messages станет значительно короче.

С каждым идентификатором ресурса связаны только две строки в списке сообщений — COMMAND и UPDATE_COMMAND_UI. Выбор первой позволяет добавить в класс функцию, которая будет обрабатывать либо ту команду меню, которую выбрал пользователь, либо щелчок на кнопке, т.е. в конечном счете обрабатывать команду. Выбор второй позволяет добавить в класс функцию, которая задает состояние пункта меню, кнопки или любого другого элемента управления перед тем, как операционная система соберется вывести его на экран, т.е. выполнить обновление команды. (Строка COMMAND выведена полужирным шрифтом, поскольку в классе CShowStringApp перехват этой команды уже запрограммирован.)

Если вы считаете нужным ввести новую функцию для перехвата команды или обновления, щелкните на кнопке Add Function. Это включит в процесс разработки еще один этап — ClassWizard предоставит вам возможность изменять имя функции, которое он сформировал по стандартной схеме. Эта возможность оставлена для самых привередливых, поскольку стандартная схема формирования имени, как правило, не вызывает возражений даже у опытных программистов, давно имеющих дело с MFC. Имя функции обработки команды начинается с On. Оставшаяся часть формируется следующим образом— удаляется ID и символы подчеркивания из идентификатора ресурса, а каждое слово пишется строчными литерами, кроме первого символа. Имена обработчиков обновления команд начинаются с OnUpdate, а далее используется то же преобразование идентификатора ресурса. Например, функция, которая перехватывает команду от ID_APP_EXIT, будет называться OnAppExit, а функция, которая обновляет ID_APP_EXIТ, будет называться OnUpdateAppExit.

Далеко не каждая команда нуждается в обработчике обновления. Объект класса фрейма окна выполняет некоторую работу в части блокировки элементов управления самостоятельно, безо всяких указаний на то со стороны разработчика. Пусть, скажем, у вас есть меню Network (Сеть), а в нем — пункт Sent (Послать). Команда этого пункта меню перехватывается объектом класса документа. Если же в приложении не открыт ни один документ, этот пункт меню будет заблокирован главным окном приложения, причем блокировка организуется безо всяких усилий с вашей стороны. Для многих команд этого вполне достаточно, т.е. команда блокируется, если объект, который должен ее обрабатывать, не существует. Для других же, которые могут иметь смысл, только в случае, если что-то выбрано или выделено, схема блокировки значительно сложнее. Вот здесь и нужно участие разработчика в программировании процесса обновления команды.


18.01.2020; 20:05
хиты: 55
рейтинг:0
для добавления комментариев необходимо авторизироваться.
  Copyright © 2013-2024. All Rights Reserved. помощь