Простые типы 3 страница

9.4. Как мастер СlassWizard помогает перехватывать сообщения
Читать карту сообщений в листинге программы совсем непросто, но зато ее очень просто формировать с помощью ClassWizard. В Visual C++ версии 6.0 существуют два способа включения компонента в карту сообщений — с помощью главного диалогового окна СlassWizard и с помощью одного из новых диалоговых окон, которые вставляют в программу обработчики сообщений или виртуальные функции. В этом разделе представлены подобного рода диалоговые окна для приложения ShowString.

9.4.1. Вкладки диалогового окна ClassWizard
Для того чтобы вывести на экран диалоговое окно мастера ClassWizard, нужно выбрать из меню View ClassWizard или нажать <Ctrl+W>. СlassWizard имеет диалоговое окно с несколькими вкладками. На рис. 1.1 показана вкладка Message Maps (Карты сообщений). В верхней ее части имеется два раскрывающихся списка. В одном — Project — представлен проект, над которым вы в настоящее время работаете (в данном случае— ShowString), в другом
— Class name— класс, карта сообщений которого редактируется (в данном случае— CShowStringApp). Информация о карте сообщений этого класса выведена в других полях вкладки.
Ниже этих однострочных полей расположена пара многострочных окон. В том, что слева, перечислены сам класс и все команды, которые может сформировать пользовательский интерфейс. Сами команды будут рассмотрены ниже в этой же главе, в разделе Команды. Когда в левом окне выделено имя класса, в правом перечислены все сообщения Windows, которые этот класс мог бы перехватывать. Кроме того, там же перечислены виртуальные функции, которые отвечают за обработку стандартных (наиболее распространенных) сообщений.

Рис 1.1 ClassWizard значительно упрощает программированиеперехвата сообщений
В правой верхней части окна находятся четыре кнопки, пользуясь которыми, можно включить новый класс в проект, новую функцию — в существующий класс, для того чтобы перехватывать выделенное в левом окне сообщение, удалить функцию, которая ответственна за обработку выделенного сообщения, или вывести на экран текст этой функции. Типовая методика следующая — нужно выбрать класс, сообщение и щелкнуть на кнопке Add Function с тем, чтобы добавить функцию, которая будет ответственна за обработку заданного сообщения. Ниже перечислены операции, которые будут выполнены после щелчка на Add Function.
• В конец файла текста программы включается заготовка ("скелет" — skeleton) функции.
• В файл текста программы, в ту его часть, где размещена карта сообщений, включается новый компонент карты.
• В файл заголовка также включается новый компонент карты сообщений.
• Обновляются списки сообщений и функций-членов в окнах вкладки.

После включения новой функции щелчок на Edit Code позволит наполнить созданную ClassWizard заготовку функции содержанием соответственно тому, как планируется обрабатывать данное сообщение. Того же результата можно достичь, сделав двойной щелчок на имени функции в списке Member Functions.
Этот список находится ниже окон списков Object IDs и Messages. В нем перечислены функции-члены текущего класса, которые связаны с определенными сообщениями. В данном случае имеются две такие функции.
• InitInstance(). Перегружает виртуальную функцию класса CWinApp — базового класса для CShowStringApp. Эта функция помечена символом V в списке, что означает — виртуальная функция (Virtual function).
• OnAppAbout(). Перехватывает команду ID_APP_ABOUT; помечена символом W в списке, что означает — сообщение окна (Window message).
Функция InitInstance() вызывается после запуска приложения. Вам нет необходимости углубляться в подробности ее работы— ClassWizard просто напоминает, что эта функция уже перегружена для данного приложения.
И наконец, ниже окна списка Member Functions выведено сообщение, напоминающее о назначении выделенного сообщения. В данном случае текст Called to implement wait cursors (Вызывается для установки курсора ожидания) — это описание виртуальной функции DoWaitCursor().

9.4.2 Добавление обработчиков сообщений Windows
В Visual C++ начиная с версии 5.0 предлагается новый способ перехвата сообщений. Вместо того чтобы вызвать ClassWizard и затем не забыть найти правильное имя класса в раскрывающемся списке, нужно просто щелкнуть правой кнопкой мыши на имени класса в окне ClassView и затем выбрать пункт Add Windows Message Handler (Добавление обработчиков сообщений Windows) контекстного меню. Диалоговое окно, которое в результате появится на экране, показано на рис. 1.2.
В этом диалоговом окне не показаны виртуальные функции, которые перечислены в главном окне ClassWizard. Глядя на это окно, легко сообразить, что данный класс перехватывает команду ID_APP_ABOUT, но не перехватывает обновление команды (command update). О командах и обновлениях команд будет более подробно рассказано далее в этой же главе. Для того чтобы добавить новую виртуальную функцию, нужно сделать двойной щелчок на имени класса в ClassView и выбрать пункт Add New Virtual Function (Добавление новой виртуальной функции) контекстного меню. Диалоговое окно, которое в результате появится на экране, показано на рис. 1.3.
На рис. 1.3 видно, что в классе CShowStringApp уже перегружена виртуальная функция InitInstance(), но существуют и другие виртуальные функции, которые можно перегрузить. Как и на вкладке, сообщение в самом низу окна напоминает вам о назначении каждой функции. Сам же текст сообщения— Called to implement wait cursors (Вызывается для установки курсора ожидания) — тот же, что и на вкладке (см. рис. 1.1).

Рис.1.2 Диалоговое окно New Windows Message and
Event Handlers – это новое средство организации для перехвата сообщений в проекте

Рис 1.3 Диалоговое окно New Virtual Override упрощает реализацию виртуальных функций в проекте

9.4.3 Какой класс должен перехватывать сообщение
Главный фокус в работе с картой сообщений и обработкой сообщений — решить, на какой класс возложить ответственность за перехват и обработку. Принять верное решение вы не сможете до тех пор, пока не будете четко представлять себе, для кого предназначены раз
личные сообщения и команды типичного приложения. Обычно приходится выбирать что-
нибудь из приведенного ниже списка. t

• Активное представление (вид)
• Документ, представленный в нем
• Фрейм (рамка окна), который содержит активное представление
• Объект-приложение

9.5. Список сообщений
Существует почти 900 различный сообщений, так что их исчерпывающий список просто не уместился бы в этой главе. Поскольку обычно для организации перехвата сообщений в приложении используется ClassWizard, представленный в нем список будет значительно короче (ведь в него отбираются только те сообщения, которые подходят для выбранного класса). Отнюдь не каждое окно может получить то или иное сообщение. Например, только класс, являющийся наследником CListBox. может получить сообщение типа LB_SETSEL, которое заставляет элемент управления типа список передвинуть подсветку на некоторый элемент списка. Префикс в имени сообщения указывает тип окна, для которого предназначено сообщение или которое его породило. Эти префиксы перечислены в табл. 1.1.

Таблица 1.1. Префиксы сообщений и типы окон

Какая разница, скажем, между ВМ- и BN-сообщением? ВМ-сообщение — это сообщение, на-правленное объекту-кнопке, например "Действуй так, как будто на тебе щелкнули". А ВМ-сообщение — это сообщение с кодом извещения, поступающего от объекта-кнопки окну, в котором эта кнопка находится и которое является "владельцем" кнопки. Это сообщение может, например, гласить: "Ой, на мне щелкнули!". То же самое справедливо для всех другихмодификаций сообщений, префиксы которых завершаются литерой М или N в приведенной выше таблице.
Иногда префикс не заканчивается буквой М. Например, СB — это префикс для сообщений от объекта— поля со списком, в то время как CBN является префиксом сообщения с кодом извещения, которое поле со списком передает окну-владельцу Например, CBN_SELCHANGE —это сообщение от поля со списком, извещающее "родителя" о том, что пользователь выбрал другой элемент списка.

9.6 Команды
Что такое команда? Это сообщение специального типа, которое формируется в тех случаях, когда пользователь выбирает пункт меню, щелкает на кнопке или каким-либо другим способом дает системе понять, что ему что-то от нее нужно. В прежних версиях Windows и выбор из меню, и щелчок на кнопке формировали сообщение WM_COMMAND. Наступили новые времена, и теперь только выбор из меню порождает сообщение WM_COMMAND, а щелчок на кнопке или выбор в списке порождает сообщение WM_NOTIFY с кодом извещения от элемента управления. Команды и коды извещений проскакивают через операционную систему точно так же, как и любые другие сообщения, но только до тех пор, пока не попадут в функцию OnWndMsg(). Здесь заканчиваются владения Windows, и в дело вступают средства маршрутизации команд, имеющиеся в MFC.
Все сообщения команд содержат в качестве первого параметра идентификатор ресурса — выбранный пункт меню или кнопку, на которой щелкнули. Этот идентификатор ресурса присваивается в соответствии со стандартом на форматы подобного рода идентификаторов, например для пункта Save As меню File идентификатор будет иметь вид ID_FILE_SAVE.
Маршрутизация команд— это механизм, используемый функцией OnWndMsg() для передачи команд и кодов извещения объектам, которые не могут получать сообщения. Получать сообщения могут только объекты классов-наследников CWnd, а все объекты классов, порожденных от CCmdTarget, включая CWnd и CDocument, могут получать команды и извещения. Это означает, что класс, который наследует CDocument, может иметь карту сообщений, причем в ней не должно быть ни одного компонента, соответствующего сообщению, а только компоненты для команд и извещений. Тем не менее этот фрагмент программы по-прежнему называется картой сообщений.
Каким же образом все-таки команды и извещения передаются классу? Посредством механизма маршрутизации команд. Функция OnWndMsg() вызывает CWnd::OnCommand() или CWnd::OnNotify(). Функция OnCommand() исследует всю подноготную команды (например, не нужно ли будет заблокировать этот пункт меню после того, как пользователь его выбрал, но перед тем, как соответствующий фрагмент программы будет выполнен) и затем вызывает OnCmdMsg(). Функция OnNotify() анализирует другие условия и затем также вызывает OnCmdMsg(). Функция OnCmdMsg() является виртуальной, а это означает, что различные классы, для которых предназначены различные команды, имеют разные реализации этой функции. Фрейм пересылает команду представлению или документу, который он (фрейм) содержит.
Вот так выполняется процесс, начинающийся как сообщение и заканчивающийся функцией-членом объекта, который не является окном, и, таким образом, не может в действительности перехватывать сообщения.
Зачем вам все это знать? Даже если вы не знаете, как происходит маршрутизация, вам придется позаботиться о правильном выборе классов, которые будут обрабатывать все события, которые могут произойти в разрабатываемом приложении. Если пользователь изменяет размеры окна, посылается сообщение WM_SIZE, и вам, возможно, понадобится изменить масштаб изображения или выполнить еще что-нибудь с представлением в приложении. Если пользователь выбирает некоторый пункт меню, формируется команда, а это означает, что класс документа должен что-то сделать в ответ на нее.

9.7. Обновление команд
Наша краткая экскурсия по подземельям MFC, в которых мы попробовали познакомить вас с тем, как связываются действия пользователя с текстом программы, завершается. Остался последний зал, в котором можно будет узнать, как программа выполняет блокировку определенных пунктов меню или кнопок в соответствии с контекстом задачи. Этот процесс назван обновлением команд (command updating).
Представьте себе на минуточку, что вы разрабатываете приложение и у вас возникла идея блокировать некоторые команды меню, чтобы показать, что они в данный момент недоступны. Реализовать эту прекрасную идею можно двумя способами.
Один состоит в том, чтобы организовать огромную таблицу, элементами которой будут все имеющиеся в приложении пункты меню, каждому из которых сопоставлен флаг. Состояние флага — TRUE или FALSE — указывает, доступен ли этот пункт меню. Как только возникает необходимость вывести меню на экран, можно быстренько просмотреть таблицу и все сразу станет ясно. При любой операции, которая может повлечь за собой изменения в статусе какого-либо пункта меню, таблица обновляется. Все это в совокупности называется подходом непрерывного обновления (continuous-updating approach).
Другой подход состоит в том, чтобы, не имея такой таблицы, перед каждым выводом меню на экран анализировать все условия, которые влияют на возможную блокировку. Он называется подходом обновления по требованию (update-on-demand approach). Именно такой подход и реализован в Windows. До широкого внедрения идей объектно-ориентированного программирования в разработку Windows-приложений такой анализ выполнялся следующим образом: система посылала сообщение WM_INITMENUPOPUP, которое означало: "Я готовлюсь вывести на экран меню", огромный оператор switch в функции WinРrос() перехватывал это сообщение и быстренько разрешал или блокировал определенные пункты меню. Эта методика абсолютно противоречит главным идеям объектно-ориентированного программирования, которые требуют, чтобы разные части информации хранились в разных объектах и не морочили голову остальной программе — были от нее скрыты.
Когда наступает время выводить на экран меню, конкретные объекты "знают", нужно ли блокировать связанный с ними пункт меню. Например, объект класса документа знает, был ли он модифицирован после последнего сохранения, и решает, стоит ли блокировать пункт Save меню File. Объект класса представления знает, есть ли выделенный фрагмент текста, и может решить, как поступить с пунктами Cut и Сору меню Edit. Все это означает, что комплексная задача блокировки пунктов меню в соответствии с контекстом приложения распределяется между различными объектами приложения, а не возлагается на главную вызывающую подпрограмму WndProc().
Подход, реализованный в MFC, состоит в том, чтобы использовать небольшой объект класса CCmdUI (класс интерфейса с командами пользователя — command user interface) и предоставить ему возможность перехватывать любые сообщения CN_UPDATE_COMMAND_UI. Организовать такой перехват можно, добавив (или предоставив возможность ClassWizard добавить) макрос ON_UPDATE_COMMAND_UI в карту сообщений. За ширмой макроса происходит следующее: операционная система по-прежнему посылает сообщение WM_INITMENUPOPUP, а затем в дело вступают базовые классы MFC, такие как CFrameWnd. Они формируют объект класса CCmdUI, устанавливают значения его членов-переменных соответственно первому пункту меню и вызывают один из методов этого класса— DoUpdate(). Затем DoUpdate() посылает сообщение CN_UPDATE_COMMAND_UI, направляя его самому себе, так как обработчиком сообщений указан объект CCmdUI. Затем тот же самый объект CCmdUI перенастраивается соответственно второму пункту меню и т.д., пока все меню не будет подготовлено к выводу. Объект класса CCmdUI также используется для блокировки или разблокировки командных кнопок и других элементов управления по той же технологии.
Класс CCmdUI имеет следующие функции-члены.
• Еnаble(). Принимает аргумент TRUE или FALSE. Блокирует элемент интерфейса пользователя, если передан аргумент FALSE, в противном случае делает элемент доступным.
• SetCheck(). Включает или выключает элемент управления.
• SetRadio(). Включает или выключает элемент управления как принадлежащий к группе зависимых переключателей, из которых только один может быть включен.
• SetText(). Устанавливает текст надписи пункта меню или кнопки, если элемент управления —
кнопка.
• DoUpdate(). Формирует сообщение.
Как правило, выбор, какая из перечисленных функций-членов нужна вам для определенных целей, очевиден. Ниже приведена упрощенная версия карты сообщений объекта класса CWhoisView, производного от CFormView, который выводит информацию на экран для пользователя. Соответствующая экранная форма имеет несколько текстовых полей, и пользователь может вставлять текст в одно из них. Карта сообщений содержит компонент перехвата обновления для команды ID_EDIT_PASTE, что в тексте программы выглядит следующим образом:
BEG I N_MESSAGE_MAP(CWhoisView, CFormVi ew) ON_UPDATE_COMMAND_ ID(ID_EDIT_ PASTE, OnUpdateEditPaste) END_MESSAGE_MAP()

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

void CWhoisView::OnUpdateEditPaste(CCmdUI* pCmdUI)

{ pCmdUI->Enable(:: IsCLipboardFormatAvai lable(CF_TEXT)),

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

9.8 Как ClassWizard помогает перехватывать команды и их обновления
В диалоговом окне ClassWizard, представленном на рис. 1.1, в списке Object IDs выделено имя класса. Ниже имеются идентификаторы всех ресурсов (меню, панелей инструментов, элементов управления и т.д.), которые могут формировать команду или сообщение при условии, что объект данного класса присутствует на экране. Если вы выделите один из них, то список связанных с ним сообщений Messages станет значительно короче, как это видно на рис. 1.4.
С каждым идентификатором ресурса связаны только две строки в списке сообщений — COMMAND и UPDATE_COMMAND_UI. Выбор первой позволяет добавить в класс функцию, которая будет обрабатывать либо ту команду меню, которую выбрал пользователь, либо щелчок на кнопке, т.е. в конечном счете обрабатывать команду. Выбор второй позволяет добавить в класс функцию, которая задает состояние пункта меню, кнопки или любого другого элемента управления перед тем, как операционная система соберется вывести его на экран, т.е. выполнить обновление команды. (Строка COMMAND выведена на рис. 1.4 полужирным шрифтом, поскольку в классе CShowStringApp перехват этой команды уже запрограммирован.)

Puc 1.4 ClassWizard позволяет программировать перехват или обновление команд
Если вы считаете нужным ввести новую функцию для перехвата команды или обновления, щелкните на кнопке Add Function. Это включит в процесс разработки еще один этап — ClassWizard предоставит вам возможность изменять имя функции, которое он сформировал по стандартной схеме (рис.1.5). Эта возможность оставлена для самых привередливых, поскольку стандартная схема формирования имени, как правило, не вызывает возражений даже у опытных программистов, давно имеющих дело с MFC. Имя функции обработки команды начинается с Оn. Оставшаяся часть формируется следующим образом — удаляется ID и символы подчеркивания из идентификатора ресурса, а каждое слово пишется строчными литерами, кроме первого символа. Имена обработчиков обновления команд начинаются с OnUpdate, а далее используется то же преобразование идентификатора ресурса Например, функция, которая перехватывает команду от ID_АРР_ЕХIТ, будет называться OnAppExit, а функция, которая обновляет ID_APP_EXIT, будет называться OnUpdateAppExit.

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

9.9. Сохранение – восстановление объектов и работа с файлами

9.9.1. Концепция сохранения-восстановления объектов
Ни для кого не секрет, что одна из основных задач программы — сохранять данные пользователя после их изменения по той или иной причине. Без этого все усилия, которые пользователь затратил на редактирование данных, пропадут, как только приложение завершит работу. С таким инструментом кашу не сваришь! В большинстве случаев, когда приложение создается с использованием AppWizard, Visual C++ без вашего участия включает в него программы, которые необходимы для сохранения и восстановления данных. Однако иногда, точнее — когда вы создаете собственные типы объектов, придется кое-что сделать самостоятельно, чтобы обеспечить надежное сохранение-восстановление пользовательских данных.
При создании приложения вам приходится иметь дело с достаточно большим разнообразием типов объектов. Одни типы объектов, хранящих данные, довольно просты, например тип int или char. Другие являются экземплярами классов — строками (экземплярами класса CString) или даже объектами классов, созданными специально для данного приложения. При использовании таких объектов в приложении, которое должно формировать, сохранять и восстанавливать документы, разработчику волей-неволей необходимо изобретать средства сохранения и восстановления этих объектов с тем, чтобы можно было их восстановить.
Свойство объекта сохраняться и восстанавливаться называется живучестью (persistence). Практически все классы MFC наделены этим свойством, поскольку они прямо или косвенно происходят от базового класса CObject. Последний уже обладает базовыми функциями сохранения-восстановления объекта. В последующих разделах этой главы вы узнаете, как MFC обеспечивает живучесть объекта класса документа.

9.9.2. Структура приложения File Demo
При создании программы с помощью AppWizard вы получите приложение, которое использует классы документа и представления для формирования, редактирования и отображения данных. Объект класса документа, производного от CDocument отвечает за хранение данных в течение всего сеанса работы приложения, а также за сохранение и загрузку данных, так что документ сохраняет свое состояние после завершения одного сеанса работы с ним и восстанавливает в начале следующего сеанса.
В процессе изучения этой главы вы создадите приложение File Demo, которое демонстрирует основные методы сохранения и восстановления данных из объектов классов, производных от CDocument. Документ этого приложения представляет собой единственную текстовую строку с кратким, но многозначительным сообщением, которая выводится на экран классом представления.
Основную роль в работе приложения File Demo играют три команды меню. При первом запуске текст сообщения автоматически устанавливается как Default Message (Сообщение по умолчанию). Его можно изменить, выполнив команду меню Edit Change Message. Сохранить документ можно с помощью команды File Save, а вновь загрузить — с помощью File Open.

9.9.3. Классы документа
Способность объектов сохраняться после изменения в одном сеансе и восстанавливать свое состояние в следующем, используя файл в качестве промежуточной среды хранения, есть ничто иное, как живучесть объектов с точки зрения пользователя. Сейчас мы вернемся к основным концепциям их структуры, фокусируя внимание на возможности реализации этих концепций в классах, создаваемых вами самостоятельно.
Работая с приложениями, созданными с помощью AppWizard, вы должны выполнить некоторую последовательность операций, чтобы обеспечить возможность сохранения и восстановления документа. Эти операции в том виде, в котором они применяются для SDI-приложения (однодокументного приложения), будут рассмотрены в настоящем разделе.
1. Создание членов-переменных класса документа, которые будут хранить специфические для данного вида документа данные.
2. Инициализация этих членов-переменных в методе OnNewDocument()класса документа.
3. Организация отображения текущего состояния документа в методе OnDraw()класса представления.
4. Включение в класс представления методов, обеспечивающих редактирование документа.
5. Модификация метода Serialize() класса документа— включение в него операторов, обеспечивающих сохранение и загрузку данных, которые и представляют собой содержание документа.
Что касается MDI-приложений, то, помимо перечисленных операций, придется сделать кое-что дополнительно, поскольку нужно обеспечить правильный выбор сохраняемого и корректную загрузку восстанавливаемого документов с учетом того, что приложение такого типа работает в течение одного сеанса с множеством документов одновременно. К счастью, большую часть этих функций MFC реализует без участия программиста.

9.9.4. Создание приложения File Demo
Для создания приложения File Demo запустите AppWizard и настройте его на создание SDI-приложения. При этом можно оставить все настройки в том виде, в котором AppWizard их предлагает по умолчанию. Поэтому можно на этапе 1 сразу после выбора типа приложения щелкнуть на кнопке Finish. Только обратите внимание, чтобы был установлен флажок поддержки архитектуры документ/представление.
Щелкните дважды на CFileDemoDoc в окне ClassView и отредактируйте файл заголовка этого класса документа. Добавьте в секцию атрибутов определение переменной m_message типа CString, чтобы этот фрагмент определения класса выглядел следующим образом:
// Атрибуты.
public:
CString m_message;
В данном случае документ содержит единственный объект класса CString — строку текста. В реальных приложениях данные будут значительно сложнее. Однако и этой единственной строки текста хватит, чтобы продемонстрировать особенности технологии обеспечения сохранности документа. Очень часто программисты используют в классе документа открытые члены-переменные вместо закрытых членов, для каждого из которых организуется открытая функция доступа. Это несколько облегчает разработку класса представления, методы которого должны обращаться к членам класса документа. Но в дальнейшем при сопровождении программы и, в частности, ее модификации такой подход несколько усложнит жизнь.
Класс документа также должен обеспечить инициализацию данных при открытии нового документа, что возлагается на метод OnNewDocument() этого класса. Вызовите при помощи окна ClassView текст этой функции в окно редактора кода и отредактируйте его. Добавьте оператор инициализации строковой переменной, как в листинге 2.1.
Листинг 2.1. Инициализация данных документа |
BOOL CFileDemoDoc::OnNewDocument()

if (! CDocument::OnNewDocument())

return FALSE;

m_message = "Default Message";

return TRUE;
После того как переменная m_message — член класса документа — инициализирована, приложение должно вывести содержимое документа в свое окно. Здесь за дело берется метод OnDraw() класса представления. Вывести текст этой функции в окно редактора кода можно уже известным вам способом при помощи окна ClassView. После редактирования функция должна иметь вид, представленный в листинге 2.2.
Листинг 2.2. Вывод на экран данных документа
void CfileDemoView::OnDraw(CDC* pDC)

CFileDemoDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc);

pDC->TextOut(20, 20, pDoc->m_message);

Теперь оттранслируйте приложение File Demo и запустите его на выполнение. Вы увидите, что на экране появится сообщение Default Message.
До тех пор, пока содержимое документа удовлетворяет пользователя, программе ничего не надо делать. Но, естественно, приложение, которое не позволяет пользователю редактировать документ, представляет ценность разве что для демонстрации. Для того чтобы обеспечить такую возможность, нужно включить в меню Edit приложения пункт Change Message. По этой команде должны запускаться средства, позволяющие пользователю изменить текст документа— выводимого сообщения. Приложение ShowString продемонстрирует, как можно сформировать диалоговое окно, именно такое, в котором нуждается наше приложение File Demo
Щелкните на вкладке Resource в левой части экрана и вызовите окно ResourceView, разверните компонент Menus и дважды щелкните на IDR_MAINFRAME. Теперь можно приступить к редактированию меню. Щелкните на пункте Edit и разверните его. Щелкните на пустом поле внизу списка пунктов этого меню и введите Change &Message. В результате в меню будет добавлен новый пункт.
Теперь вызовите мастер ClassWizard. Он понадобится вам для установления связи между новой командой и текстом программы. В левом окне ClassWizard должен быть подсвечен пункт ID_EDIT_CHANGEMESSAGE. Если это не так, щелкните на этом пункте. В раскрывающемся списке справа вверху выберите CFileDemoView. Щелкните на COMMAND в окне справа внизу, а затем — на кнопке Add Function. Предлагаемое мастером имя функции OnEditChangemessage() нам вполне подходит, так что щелкните на кнопке ОК в появившемся диалоговом окне. Теперь щелкните на кнопке Edit Code — заготовка новой функции будет выведена в окне редактора кода. Ее нужно отредактировать соответственно листингу 2.3.
Листинг 2.3. Редактирование содержимого документа
void CFi leDemoView::OnEditChangemessage()


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: