Теперь, когда у нас есть работающее приложение, мы можем его модифицировать с помощью мастера ClassWizard. Если приложение уже загружено, выберите пункт ClassWizard из меню View. На рис. 1.8 изображено диалоговое окно мастера ClassWizard.
Рис. 1.8. Диалоговое окно мастера ClassWizard
В диалоговом окне мастера ClassWizard есть пять вкладок. Выберите вкладку Message Map, как показано на рисунке. В диалоговом окне будут показаны установленные обработчики событий для класса, имя которого вы выбираете в поле со списком Class name. Список Object IDs содержит имя класса и список идентификаторов для меню. Вы добавляете обработчик событий, выбрав один из идентификаторов меню или имя класса и указав требуемое сообщение в списке Messages. Новый обработчик сообщений будет создан после щелчка по кнопке Add Function.
Давайте создадим обработчик событий, который будет сообщать о нажатии на клавиши. Это можно сделать установив обработчик для сообщения WM_KEYDOWN. Система Windows посылает сообщение WM_KEYDOWN при нажатии на любую клавишу.
Убедитесь, что в поле со списком Class name выбран класс CSampleView и этот же класс отмечен в списке Object IDs. В списке Message list отметьте строку WM_KEYDOWN (вам понадобится прокрутить список, чтобы найти строку WM_KEYDOWN). После того, как произведете выбор, щелкните по кнопке Add Function. Мастер AppWizard добавит строку WM_KEYDOWN в список Members functions (в нем отображаются существующие в программе обработчики) и добавит новый обработчик событий в текст программы. Теперь щелкните по кнопке Edit code. Мастер ClassWizard откроет окно с текстом программы. Созданный нами новый обработчик показан на рис. 1.9.
Рис. 1.9. Созданный нами обработчик события WM_KEYDOWN
ЗАМЕЧАНИЕ | Обратите внимание на код обработчика событий. Обратите внимание на код, который мастер ClassWizard помещает в новый обработчик событий. ClassWizard отмечает наилучшее место для добавления вашего кода, помещая туда комментарий. Иногда ваш код располагается перед вызовом функции базового класса, иногда — после. В некоторых случаях ClassWizard вообще не будет вызывать функции базового класса. |
Единственной вещью, которую делает созданный мастером ClassWizard обработчик, является вызов подобной функции базового класса. Мы должны добавить наш код в место, отмеченное ClassWizard с помощью комментариев. Для примера мы будем использовать отладочное макроопределение TRACE, которое будет показывать информацию о поступившем сообщении. Модифицируйте обработчик событий, как показано ниже:
void CSampleView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { TRACE("WM_KEYDOWN message received "); TRACE("keycode=%d repeat=%d flags=%d\n", nChar, nRepCnt, nFlags); CView::OnKeyDown(nChar, nRepCnt, nFlags); }Теперь скомпилируйте и запустите приложение. После появления окна приложения нажмите какую-нибудь клавишу. В окне Debug программы Developer Studio будет показано сообщение, напечатанное функцией TRACE.
ЗАМЕЧАНИЕ | Этот пример будет работать, только если компилируется в отладочном режиме (Debug mode) и запускается из программы Developer Studio потому что макроопределение TRACE в режиме Release mode не работает. |
Программы для Windows также имеют точку входа: функцию WinMain(). WinMain() — это написанная вами функция, которую Windows вызывает, когда запускает ваше приложение. В отличие от функции main() для DOS, функция WinMain() должна выполнять определенные задачи. Типичные действия WinMain — инициализация структур данных, создние окна и запуск цикла обработки сообщений, представляющего собой непрерывную проверку наличия новых доступных сообщений. При обнаружении нового сообщения цикл принимает его и передает для дальнейшей обработки. Типичный цикл обработки сообщений выглядит следующим образом:
while ( GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); }Функции GetMessage, TranslateMessage, и DispatchMessage являются частью Windows SDK. Сообщения могут быть отправлены другими приложениями или самой системой Windows. Эти сообщения могут быть уведомлениями об изменении системной палитры, о нажатии клавиши, о перемещении мыши и т.д. В конечном счете цикл получает и обрабатывает сообщение WM_QUIT, которое сигнализирует программе о необходимости прекратить работу.
После выхода Windows 3.0 многие программисты, работавшие на других платформах, перешли к написанию приложений для Windows. Многие из них начинали работу с DOS и обнаружили, что программирование для Windows сильно отличается. Дело обстояло еще хуже, поскольку не было библиотек функций, шаблонов классов или визуальных средств разработки, чтобы облегчить переход.
С тех пор многое изменилось. Visual C++ — замечательный инструмент, объединяющий мощную структуру классов с визуальными инструментами, берущими на себя тяжелую работу проектирования ресурсов, таких, как диалоговые окна и меню. Мастер ClassWizard позволяет вам добавлять функции к вашему приложению простым щелчком по кнопке. Мастер AppWizard создает готовые к компиляции проекты, обеспечивающие твердую основу для написания собственного приложения.
Несмотря на всю мощь Visual C++, чтобы использовать его возможности, вы должны быть программистом и понимать основные концепции программирования для Windows. В этой главе вы научитесь использовать Visual C++ для создания законченных приложений и узнаете,как их модифицировать. Также в этой главе вы научитесь создавать законченные приложения использующие Direct3D.
Здесь не содержится полный курс обучения Visual C++, но приведенных сведений достаточно, чтобы вы могли начать работать, если у вас уже есть некоторый опыт программирования.
Вспомните, что библиотека MFC разработана для изоляции программиста от некоторых запутанных деталей архитектуры приложений Windows. MFC изолирует вас от обработчика событий, предоставляя свой собственный, который вызывает создаваемые вами индивидуальные функции обработки отдельных событий. Это выполняется с помощью карт сообщений. Карта сообщений — это макрос, который сообщает MFC, что вы заинтересованны в обработке определенного события. Все что вам необходимо — это включить карту сообщений и обработчики для каждого события в вашу программу, а MFC позаботится об остальном. Карта сообщений выглядит следующим образом:
BEGIN_MESSAGE_MAP(OurClass, BaseClass) ON_WM_PAINT() ON_WM_SIZE() ON_WM_LBUTTONDOWN() END_MESSAGE_MAP()Эта карта сообщений указывает MFC, что у нас есть класс, с именем OurClass являющийся производным от класса BaseClass и обрабатывающий три сообщения: WM_PAINT, WM_SIZE и WM_LBUTTONDOWN (это стандартные сообщения Windows).
Теперь вам необходимо написать функцию-обработчик для каждого из этих сообщений. Например, обработчик сообщения WM_PAINT может выглядеть следующим образом:
void OurClass::OnPaint() { // Здесь располагается функция обработки // сообщения WM_PAINT. }Все функции обработки событий должны быть объявлены внутри класса. Для рассматриваемых в примере трех функций описание выглядит следующим образом:
class OurClass : public BaseClass { protected: afx_msg void OnPaint(); afx_msg void OnSize(UINT type, int cx, int cy); afx_msg void OnLButtonDown(UINT state, CPoint point); DECLARE_MESSAGE_MAP() };Макроопределение afx_msg определяет описываемую функцию как обработчик события, а макроопределение DECLARE_MESSAGE_MAP указывает MFC, что данный класс использует карту сообщений.
Карты сообщений представляют собой мощный инструмент, значительно облегчающий обработку событий, но Visual C++ делает эту задачу еще более легкой, предоставляя для использования мастер создания классов ClassWizard. ClassWizard — это инструмент, входящий в состав Visual C++ Developer Studio, который предоставляет возможность добавлять, удалять и редактировать функции обработки событий. На рис. 1.2 показан внешний вид диалогового окна мастера ClassWizard.
Рис. 1.2. Диалоговое окно мастера ClassWizard
В окне мастера ClassWizard вы выбираете сообщение, обработчик которого вам необходим, и щелкаете по кнопке Add Function. Мастер ClassWizard создает не выполняющий никаких действий обработчик для выбранного сообщения, который в дальнейшем вы можете модифицировать в соответствии с вашими требованиями. ClassWizard делает добавление обработчиков событий настолько простым, насколько это возможно, поскольку создаваемые им обработчики уже готовы для компиляции. Единственный отсутствующий в них компонент — это ваш код.
Код, который ClassWizard добавляет в ваш проект немного отличается от рассмотренного ранее кода для карты сообщений. Например, если вы создадите предыдущий фрагмент программы с помощью ClassWizard, он будет выглядеть следующим образом:
BEGIN_MESSAGE_MAP(OurClass, BaseClass) //{{AFX_MSG_MAP(OurClass) ON_WM_PAINT() ON_WM_SIZE() ON_WM_LBUTTONDOWN() //}}AFX_MSG_MAP END_MESSAGE_MAP()Отличие заключается в том, что ClassWizard вставляет в текст программы элементы, выполняющие роль закладок. С точки зрения компилятора эти закладки являются обыкновенными комментариями, однако мастеру ClassWizard они показывают местоположение карты сообщений в вашем исходном коде. Вы можете удалить эти закладки, и получившийся код будет правильно компилироваться, но вы больше не сможете редактировать карту сообщений с помощью мастера ClassWizard.
Вы также можете использовать ClassWizard для удаления обработчиков событий. Когда вы удаляете обработчик с помощью ClassWizard, будет удалена ссылка в карте сообщений и соответствующее объявление функций. Вам останется только удалить фактическое тело функции.
Далее в этой главе мы рассмотрим пример использования мастера ClassWizard.
В то время, как мастер ClassWizard делает легкой модификацию проектов, мастер AppWizard позволяет легко создавать новые проекты. Visual C++ содержит, например, мастер позволяющий создать новый проект с использованием библиотеки MFC. Если вы запустите этот мастер, вам будет предложен ряд диалоговых окон с вопросами о том, какое MFC приложение вы хотели бы создать. Visual C++ содержит несколько различных мастеров для создания приложений: один для создания приложения с использованием библиотеки MFC, другой для создания консольного приложения, третий для создания библиотек динамической компоновки (DLL) и т.д.
Главная польза от использования мастера AppWizard для нового приложения состоит в том, что создаваемый программой код обычно уже готов к компиляции. Вам не требуется что-нибудь добавлять, чтобы скомилировать и проверить его. Создавая готовый к компиляции проект, мастер AppWizard спасает вас от огорчительных поисков ошибок в большом куске незнакомого кода, который не компилируется.
Visual C++ позволяет вам писать свои собственные мастера для создания приложений. Пользовательский мастер AppWizard может быть написан для генерации базового кода практически любого типа приложений. CD-ROM, прилагающийся к этой книге содержит пользовательский мастер Direct3D AppWizard, позволяющий создать полностью функционирующее приложение, использующее Direct3D.
Пользовательский мастер представляет собой специальную динамическую библиотеку (DLL) с расширением AWX. Для установки мастера необходимо скопировать файл с расширением AWX в папку Visual C++ с шаблонами (обычно это c:\msdev\template). Для установки мастера Direct3D AppWizard вам необходимо либо скопировать файл Direct3DappWiz.AWX из папки Direct3DappWiz\Release, расположенной на CD-ROM, либо воспользоваться программой инсталяции на CD-ROM.
После установки мастера, запустите Visual C++ Developer Studio, выберите пункт New из меню File, отметьте пункт Project Workspace и щелкните по кнопке OK. В окне New Project Workspace, в списке Type отметьте строку Direct3D AppWizard, как показано на рис. 1.10. Также необходимо ввести имя проекта. Для нашего примера мы используем имя Sample3D. После ввода имени щелкните по кнопке Create. Теперь вам будет показано первое диалоговое окно мастера Direct3D AppWizard, изображенное на рис. 1.11.
Рис. 1.10. Выбор мастера Direct3D AppWizard
Рис. 1.11. Первое диалоговое окно мастера Direct3D AppWizard
Первое диалоговое окно показывает краткое описание используемого мастера. Щелкните по кнопке Next для перехода ко второму диалоговому окну, изображенному на рис. 1.12.
Рис. 1.12. Диалоговое окно Object selection для выбора объекта
Во втором диалоговом окне мастера вам необходимо выбрать трехмерный объект, который будет отображаться создаваемым вами Direct3D-приложением. По умолчанию выбран переключатель Swirl object (завиток), но вы можете выбрать любой другой объект, отметив переключатель Let me choose an object и указав имя файла с отображаемым объектом в поле Object. Вы можете также воспользоваться кнопкой Browse для поиска объектов (файлы с объектами Direct3D имеют расширение X). Для примера мы используем предлагаемый по умолчанию объект Swirl. Щелкнем по кнопке Next для перехода к следующему диалоговому окну, изображенному на рис. 1.13.
Рис. 1.13. Диалоговое окно Lighting selection для выбора источников света
Третье диалоговое окно мастера предназначено для выбора используемых в вашем приложении источников света. Подробнее об освещении сцен мы поговорим позднее. Сейчас мы используем предлагаемое по умолчанию направленное освещение.
Также с помощью этого диалогового окна можно настроить цвет источника света. По умолчанию для любого источника света используется белый цвет. Снова щелкните по кнопке Next чтобы перейти к четвертому диалоговому окну мастера, изображенному на рис. 1.14.
Рис. 1.14. Диалоговое окно с именами классов
В четвертом диалоговом окне можно просмотреть и изменить имена классов, которые будут созданы мастером. Примите предложенные значения и щелкните по кнопке Next.
Теперь мастер покажет нам заключительное диалоговое окно (рис. 1.15) где мы можем увидеть выбранные параметры.
Рис. 1.15. Заключительное диалоговое окно мастера Direct3D AppWizard
Новый проект будет создан после щелчка по кнопке OK. Скомпилируем проект, нажав клавишу F7, и выполним новое приложение, нажав клавишу F5. На рис. 1.16 показано окно созданного нами нового приложения.
Рис. 1.16. Новое приложение с использованием Direct3D
Обработчик событий — это функция, которую вы пишете сами и регистрируете в системе вместе с окном приложения. После регистрации вашего обработчика событий каждое сообщение переданное функцией DispatchMessage попадет к вашему обработчику. Типичный обработчик событий содержит инструкцию switch с инструкциями case для каждого события, которое необходимо обработать. События, которые не нуждаются в специальной обработке, обычно передаются внутреннему обработчику событий системы Windows. Простейший обработчик событий выглядит следующим образом:
long WINAPI WndProc(HWND hWnd, UINT msg, UINT wParam, LONG lParam) { switch (msg) { case WM_KEYDOWN: // Здесь располагается код для обработки нажатия клавиши break; case WM_MOUSEMOVE: // Здесь располагается код для обработки перемещения мыши break; default: // Если событие не нуждается в обработке, передадим // его системе Windows return DefWindowProc(hWnd, msg, wParam, lParam); } return 0; }Конструкция обработчика событий мощная и полезная, потому что позволяет вам перехватывать сообщения до того, как они будут обработаны системой Windows. Вы можете задать реакцию на любое событие, проходящее через ваш обработчик, добавив в текст программы соответствующую инструкцию case.
С другой стороны, очевидно, что обработка каждого возможного сообщения в одной функции, приводит к появлению уродливого кода. Типичные программы для Windows (включая примеры программ, входящие в комплект поставки DirectX) часто содержат массивные обработчики событий, занимающие сотни строк программы. Альтернативой является написание отдельной функции обработки для каждого события и последующий вызов этой функции из обработчика событий. Этот вариант предпочтительней, поскольку позволяет вам писать набор маленьких обработчиков для отдельных событий, вместо одной огромной сложной программы, обрабатывающей все события. MFC использует именно такую технику с одним существенным усовершенствованием, называемым карты сообщений.
Программы для Windows имеют необычный вид. Программирование, управляемое событиями это не единственная вещь к которой необходимо приспособиться. Одна из причин отличия внешнего вида программ для Windows — частое использование венгерской нотации. Венгерская нотация использует имена переменных с префиксами, определяющими тип каждой переменной и предназначена для языков в которых отсутствует строгая проверка совпадения типов.
В то же время строгая проверка соответствия типов является одной из ключевых особенностей C++. Это значит, что в C++ уже решена проблема, для которой разрабатывалась венгерская нотация. Проверку соответствия типов в С++ выполняет компилятор, а не программист. Это позволяет свободно сконцентрироваться на более важных вещах (например, на трехмерной графике). В программах, рассматриваемых в этой книге, венгерская нотация не используется.
Другим отличием от общепринятой традиции, является то, что в этой книге классы написаны таким образом, что открытые (public) функции-члены расположены в начале класса. Это объясняется тем, что открытый интерфейс обычно представляет наибольший интерес для пользователей класса. Закрытые (private) данные и функции-члены класса располагаются ближе к концу, поскольку они не могут использоваться порождаемыми или внешними классами.
У вас будет множество возможностей применить полученные в этой главе знания, поскольку вся остальная часть книги посвящена созданию различных приложений, использующих возможности Direct3D.
Наиболее фундаментальным различием между Windows и DOS является то, что Windows представляет собой операционную систему, управляемую событиями (event-driven). Это означает, что практически все, происходящее в Windows, является ответом на сообщение или событие (в этой книге мы будем использовать термины сообщение и событие как синонимы).
В DOS вы указываете точку входа — место, с которого DOS начинает выполнение вашей программы. Точкой входа для DOS является функция main(). DOS вызывает вашу функцию main() и программа делает то, для чего предназначена. Вы не должны выходить из функции main(), пока программа не завершит свою работу. Как только будет выполнен возврат из функции main(), DOS прекратит выполнение вашей программы.
Создание приложений с использованием мастера AppWizard настолько легко, что мы можем создать один проект для практики прямо сейчас. Запустите программу Visual C++ Developer Studio и выберите пункт New в меню File. Будет выведено диалоговое окно New, представленное на рис. 1.3. Выберите пункт Project Workspace и щелкните по кнопке OK.
Рис. 1.3. Окно New программы Visual C++ Developer Studio
После этого будет открыто диалоговое окно New Project Workspace (рис. 1.4). Это окно предлагает вам выбрать один из мастеров AppWizard, установленных на вашем компьютере. Мы будем использовать MFC AppWizard для создания многодокументного приложения, использующего библиотеку MFC. Выберем пункт MFC AppWizard(exe). Теперь введем имя проекта. На рис. 1.4 видно, что для проекта мы выбрали имя Sample.
Рис. 1.4. Окно New Project Workspace
Обратите внимание, что выбранное для проекта имя также используется как имя папки, в которой будут содержаться файлы создаваемого проекта. Вы можете изменить имя и расположение этой папки, модифицируя текстовое поле Location.
Щелкните по кнопке Create и вам будет показано первое диалоговое окно мастера MFC AppWizard. Это окно вы можете увидеть на рис. 1.5. Здесь вам предлагается выбрать тип вашего приложения — однодокументное приложение (SDI), многодокументное приложение (MDI) или диалоговое приложение. В нашем примере мы будем создавать многодокументное приложение (MDI), которое мастер предлагает по умолчанию.
Рис. 1.5. Первое диалоговое окно мастера MFC AppWizard
Щелкните по кнопке Next, и вы перейдете к следующему диалоговому окну. В диалоговых окнах со второго по пятое задается множество параметров вашего нового проекта. Сейчас мы ничего не будем менять в этих окнах и воспользуемся установленными по умолчанию значениями. На рис. 1.6. показано шестое и последнее диалоговое окно мастера MFC AppWizard.
Рис. 1.6. Последнее диалоговое окно мастера MFC AppWizard
Последнее диалоговое окно позволяет вам изменить имена классов, которые будут использоваться в новом проекте. Мастер AppWizard создает имена классов добавляя в конец имени проекта идентификаторы типа App, View или Doc. Для наших целей эти имена вполне подходят. Теперь можно щелкнуть по кнопке Finish.
Перед созданием приложения мастер AppWizard покажет окно New Project Information (рис. 1.7) в котором будут отображены выбранные параметры.
Рис. 1.7. Окно New Project Information
Это ваш последний шанс посмотреть, что вы выбрали. Щелчок по кнопке OK создаст приложение. Вы можете скомпилировать новый проект, нажав клавишу F7 и запустить приложение, нажав клавишу F5.
Visual C++ — это набор инструментальных средств для создания приложений, работающих в Windows. Все эти инструменты объединены в Студию Разработчика (Developer Studio). Вы можете использовать Студию Разработчика, чтобы создавать минимальные приложения, добавлять функциональные возможности к существующим программам и создавать или редактировать ресурсы, такие как меню, диалоговые окна и значки. В Студию Разработчика также входят компилятор, отладчик и редактор. На рис. 1.1 показано главное окно программы Visual C++ Developer Studio.
Рис. 1.1. Главное окно программы Visual C++ Developer Studio
Windows SDK (Software Development Kit — комплект разработчика программного обеспечения) представляет собой набор функций, структур и макроопределений, позволяющий программистам писать приложения для Windows. В той или иной форме SDK присутствует в Windows, начиная с Windows 1.0 (да, когда-то была Windows 1.0). Написанный на C, SDK известен тем, что с ним трудно работать. Поскольку SDK не является объектно-ориентированным, его сложно расширять и программист вынужден уделять внимание всем мелким деталям программирования в Windows. Windows SDK поставляется вместе с Visual C++, но вы много потеряете, если ограничитесь программированием с использованием SDK. Настоящее сердце Visual C++ — это MFC.
MFC (Microsoft Foundation Classes) — это написанная на C++ библиотека классов, которая изолирует программистов от деталей Windows SDK. MFC действительно основа; набор гибких низкоуровневых объектов, которые можно расширить для применения практически в любой области. Многие классы MFC — просто тонкие оболочки вокруг конструкций Windows SDK. Сами по себе классы MFC не являются особенно внушительными или полезными, но они обладают замечательной расширяемостью. MFC также поставляется вместе с Visual C++.