Студия web-дизайна Хостмэйк
Наши работыКонтактыО компанииОтзывыГлоссарийСтатьи

Глава 4. Классы окон библиотеки MFC

Статьи Программирование на С/С++

Классы окон библиотеки MFC



Вспомним, что Windows — это
операционная система, которая прежде всего работает с окнами. Со своей стороны,
подавляющую часть библиотеки MFC
составляют классы окон. Пришло время подробно познакомиться и с теми и с
другими, а также с их взаимодействием.


Объекты оконных классов библиотеки size=2>MFC, естественно, отличаются от окон size=2>Windows, но тем не менее тесно с ними связаны. Полное и правильное
понимание взаимосвязей между ними является залогом успеха при создании
приложений.


Как и любой другой объект C++, объект "окно" создается и уничтожается
конструктором и деструктором класса, соответственно. Это с одной стороны. А с
другой, окно Windows — это внутренняя
структура данных операционной системы, которая формируется функцией интерфейса
.прикладного программирования Win32 API
Create,
а разрушается функцией Destroy
Window
. В системе Windows каждое
окно идентифицируется своим дескриптором, значение которого хранится в
переменной m_hWnd объекта face="Courier New" size=2>CWnd (рис. 4.1).



............................................................1

Рис. 4.1. Объект класса CWnd
связан с окном Windows через дескриптор
m_hWnd


Несколько возможных способов создания и работы с окнами мы рассмотрели в
предыдущей главе, поэтому здесь акцентируем наше внимание на тех типах окон,
которые имеются в Windows.


Окна, определенные в системе Windows


Существует всего три основных типа окон: 




  •  Перекрывающиеся ( size=2>overlapped
  •  Всплывающие или вспомогательные ( size=2>popup)
  •  Дочерние (child)

из которых программист может создавать множество самых разнообразных
объектов, комбинируя предопределенные биты стиля, имеющие имена с префиксом
WS_ (от size=2>window style — стиль окна). Рассмотрим более подробно эти биты, их
влияние на внешний вид и некоторые свойства окон. Начнем с простого
перечисления:


WS_BORDER 



Задает окно, имеющее рамку без
заголовка


WS_CAPTION 



Задает окно, имеющее заголовок и рамку. Как
правило, этот стиль используется для перекрывающихся окон и не может
применяться совместно со стилем WS_DLGFRAME


WS_CHILD 



Устанавливает дочернее окно; не может
использоваться совместно со стилем WS_POPUP


WS_CLIPCHILDREN



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


WS_CLIPSIBLINGS 



Исключает все другие дочерние окна из своей
области рисования; другими словами, если дочерние окна перекрываются, а этот
стиль не указан, то при изменении рабочей области одного из окон могут быть
испорчены рабочие области других дочерних окон; этот стиль используется только
вместе со стилем WS_CHILD


WS_DISABI_ED 



Задает неактивное окно, т. е. сразу после
его создания окно недоступно для ввода с клавиатуры или с помощью мыши


WS_DLGFRAME



 Задает окно, имеющее двойную рамку и
не имеющее заголовка


WS_GROUP 



Определяет первый элемент управления группы
окон, к которым пользователь может переходить при помощи клавиш со стрелками;
все элементы управления, определенные с этим стилем, заканчивают текущую и
начинают новую группу (одна группа заканчивается там, где начинается
другая)


WS_HSCROLL 



Задает окно, имеющее горизонтальную полосу
прокрутки


WS_VSCROLL 



Задает окно, имеющее вертикальную полосу
прокрутки


WS_MAXIMIZE 



Задает отображение окна в развернутом
виде


WS_MAXIMIZEBOX



Задает окно, имеющее кнопку "Развернуть";
если окно является дочерним окном элемента управления, то этот флаг стиля
используется под другим именем — WS_TABSTOP


WS_MINIMIZE 



Задает отображение окна в виде пиктограммы;
используется только со стилем WS_OVERLAPPED


WS_MINIMIZEBOX 



Задает окно, имеющее кнопку "Свернуть";
если окно является дочерним окном элемента управления, то этот флаг стиля
используется под другим именем — WS_GROUP


WS_OVERLAPPED 



Устанавливает, что окно является
перекрывающимся; обычно имеет заголовок и рамк
у


WS_POPUP



 Задает всплывающее окно; не может
использоваться совместно со стилем WS_CHILD


WS_SYSMENU 



Задает окно, имеющее пиктограмму системного
меню в полосе , заголовка


WS_TABSTOP 



Назначается одному или нескольким элементам
управления для того, чтобы между ними можно было перемещаться с помощью
клавиши табуляции <ТаЬ>


WS_THICKFRAME



Задает окно, имеющее утолщенную рамку, при
помощи которой можно изменять размер окна


WS_VISIBLE 



Устанавливает режим, когда окно становится
видимым сразу после создания; этот стиль в основном используется для окон
диалога


Помимо перечисленных стилей окон size=2>Windows, в файле <winuser.h>
определены стили, являющиеся комбинацией наиболее часто используемых
стилей.


size=2>WS_OVERLAPPEDWINDOW 



Комбинация стилей WSjDVERLAPPED,
WS_CAPTION,
WS_SYSMENU, WSJTHICKFRAME,
WSJ/IINIMIZEBOX и WS_MAXIMIZEBOX


WS_POPUPWINDOW 



Комбинация стилей WS_POPUP, WS_BORDER и
WS_SYSMENU


При работе с окнами часто также используются дополнительные или расширенные
биты стиля:


WS_EX_ABSPOSITION 



Определяет, что позиция окна задается в
абсолютных единицах относительно левого верхнего угла экрана


color=#800000>WS_EX_ACCEPTFILES 



Определяет, что окно допускает
перетаскивание файлов (drag-and-drop)


WS_EX_CUENTEDGE 



Придает "трехмерный эффект" границе окна,
клиентская область при этом как бы вдавлена в окно


WS_EX_CONTEXTHELP 



Включает знак вопроса в заголовок окна;
когда пользователь нажимает на этот знак, то курсор изменяется на указатель в
виде знака вопроса; если теперь выбрать какое-либо дочернее окно — оно получит
сообщение WM_HELP


size=2>WS_EX_CONTROLPARENT 



Позволяет пользователю перемещаться по
дочерним окнам родительского окна, используя для этого клавишу табуляции
<ТаЬ>


size=2>WS_EX_DLGMODALFRAME 



Задает окно, имеющее удвоенную границу, что
при использовании совместно со стилем WS_CAPTION позволяет создавать окно с
полосой заголовка


WS_EX_LEFT 



Устанавливает для окна свойство левого
выравнивания (по умолчанию)


size=2>WS_EX_LEFTSCROLLBAR 



Задает расположение полосы прокрутки (если
она имеется) с левой стороны рабочей (клиентской) области окна


WS_EX_LTRREADING



 Используется по умолчанию и
определяет естественный порядок (слева направо) для большинства языков ввода и
чтения текста


size=2>WS_EX_MDICHILD 



Задает дочернее окно MDI


size=2>WS_EX_NOPARENTNOTIFY 



Определяет, что дочернее окно, созданное с
этим стилем, не посылает сообщения WM_PARENTNOTIFY своему родительскому окну
при создании или уничтожении


WS_EX_RIGHT 



Устанавливает в зависимости от класса окна
групповое свойство правого выравнивания


size=2>WS_EX_RIGHTSCROLLBAR 



Задает расположение полосы прокрутки (если
она имеется) с правой стороны рабочей (клиентской) области окна; используется
по умолчанию


WS_EX_RTLREADING 



Определяет порядок ввода и чтения текста
справа налево


WS_EX_SMCAPTION 



Задает окно, имеющее уменьшенную высоту
полосы заголовка; используется при создании "плавающих" панелей
инструментов


WS_EX_STATICEDGE 



Определяет окно, имеющее трехмерный стиль
границы, заданный для использования в элементах, к которым пользователь не
получает доступа (статические элементы управления)


WS_EX_TOOLWINDOW 



Задает окно, которое используется для
создания "плавающей" панели инструментов; такое окно имеет укороченную полосу
заголовка и не отображается на панели задач


WS_EX_TOPMOST 



Задает окно, которое будет располагаться
поверх всех окон (созданных без этого стиля); для установки или сброса этого
бита можно использовать функцию SetWindowPos


WS_EX_TRANSPARENT 



Задает прозрачное окно, т. е. не
закрывающее другие окна, расположенные "под ним"; сообщение WM_PAINT такое
окно получает до того, как это сообщение получают все окна того же уровня, но
расположенные "под ним"


WS_EX_WINDOWEDGE 



Задает окно, имеющее приподнятую границу
для создания "трехмерного эффекта" 


Так же, как в случае основных стилей, для расширенных определены два
комбинированных дополнительных стиля size=2>(WINUSER.H);


size=2>WS_EX_OVERLAPPEDWINDOW 



Комбинация стилей WS_EX_CLIENTEDGE и
WS_EX_WINDOWEDGE


size=2> WS_EX_PALETTEWINDOW 



Комбинация стилей WS_EX_WINDOWEDGE,
WS_EX_SMCAPTION и WS_EX_TOPMOST


После того как мы перечислили все возможные стили окон, осталось сказать
несколько слов об упомянутых выше основных типах окон Windows. Напомним, что их
всего три.



  •  Перекрывающиеся окна. Это основной, наиболее универсальный
    тип окон Windows. Главное окно приложения, как правило, имеет именно этот тип.
    Для их создания чаще всего используется стиль size=2>WS_OVERLAPPEDWINDOW.
  •  Вспомогательные или всплывающие окна. Чаще всего этот тип
    окон создается с использованием стиля size=2>WS_POPUP. Обычно они отображают какую-либо информацию короткого
    промежутка времени. Наиболее часто окна этого типа используются для
    отображения диалоговых окон или окон сообщения. Основное их отличие от других
    окон заключается в том, что, даже если они имеют родительское окно, то все
    равно всегда отображаются поверх всех окон на экране, выскакивая, как
    поплавки, наверх даже тогда, когда пользователь делает активным другое окно.
    Для окон этого типа, как правило, организуется своя оконная процедура. Они
    могут иметь, а могут и не иметь родителя. Если такое окно не имеет
    родительского, то оно является совершенно независимым от создавшего его окна и
    по своим свойствам практически неотличимо от перекрывающихся окон. Поведение
    всплывающего окна, имеющего родителя, зависит от того, что происходит с
    последним. Когда главное окно минимизируется, всплывающее окно "без родителя"
    скрывается, а "с родителем" — остается на экране сверху. Подчеркнем еще один
    важный момент: когда мы говорим, что вспомогательное окно имеет родителя, это
    совсем не означает, что оно является дочерним.

Примечание 


Наиболее полным семантическим эквивалентом английского
термина "popup window" является термин "окно-поплавок". Мы будем называть такие
окна всплывающими.



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

Какие же возможности предоставляет нам библиотека size=2>MFC в плане создания и работы с окнами? Если обратимся к иерархии
классов MFC, то вспомним, что все классы,
имеющие какое-либо отношение к окнам, являются производными (прямо или косвенно)
от единственного класса CWnd (рис. 4.2).



......................................................................2

Рис. 4.2. Иерархия оконных классов


Этот класс, а также специальные производные от него классы, включая face="Courier New" size=2>CFrameWnd, CMDIFrameWnd, CMDIChildWnd, CView и
CDialog,
имеющиеся в библиотеке, спроектированы таким образом, чтобы
сделать за нас большую часть обязательной, но рутинной работы с различными
типами окон Windows.


Класс CWnd — это базовый класс для
всех окон, созданных на базе библиотеки size=2>MFC (рис. 4.3). Помимо предоставления всем своим производным
классам большого числа функций для работы с окнами, он также служит для создания
разнообразных дочерних окон.



...........................................................................3

Рис. 4.3. CWnd— базовый класс
всех окон библиотеки MFC


Из имеющихся компонентов класса CWnd
для нас на данном этапе интерес представляет один:


HWND CWnd::m_hWhd



m_hWnd является дескриптором окна Windows,
присоединенного к объекту класса CWnd. Это достаточно важный параметр,
особенно для главного окна приложения, т. к. он позволяет библиотеке взять на
себя всю работу для корректного завершения приложения, когда пользователь
закрывает его главное окно.


Класс CWnd содержит практически все
функции, необходимые для работы с окнами. Таких функций более двухсот и их можно
разбить на несколько категорий, каждая из которых включает функции, направленные
на решение определенного круга задач. Приведем список категорий с кратком
характеристикой входящих в них функций:



  •  Конструктор. Создает объект класса без создания окна face="Courier New" size=2>Windows.
  •  Инициализация. В эту категорию входят: функции face="Courier New" size=2>Create и size=2>СгсагеЕх. отвечающие за создание окна size=2>Windows (соответствующей ему внутренней структуры) и
    присоединение его к объекту класса; виртуальная функция face="Courier New" size=2>PreCreaieWindow, позволяющая зарегистрировать
    используемым по умолчанию класс окна " size=2>AfxWnd"; функции GetStyle
    и GetExStyle, позволяющие узнать
    текущий обычный или расширенный стиль окна; функции size=2>Anach и Detach,
    позволяющие присоединить или отсоединить окно Windows от объекта класса face="Courier New" size=2>CWnd; функции size=2>GetSafeWnd для получения дескриптора окна face="Courier New" size=2>Windows и size=2>FromHandle и size=2>FromHandlePermanent для получения указателя на объект по
    дескриптору; функции PreSithclassWindow
    и SubclassWinclow для работы с
    подклассами окна, а также некоторые другие функции.
  •  Состояние окна. Сюда входят функции, позволяющие: определить ( face="Courier New" size=2>IsWindowEnable} или изменить ( face="Courier New" size=2>EnableWindow) доступ к окну; узнать пли
    назначить активное окно (обычное — size=2>GetActlveWnd и size=2>SesAciiveWnd, окно переднего плана — size=2>GetForegroundWindow и size=2>SetForcgmtiiniWinciow): получить или установить фокус ввода с
    клавиатуры (GetFocus и face="Courier New" size=2>SetFocus) или от мыши ( face="Courier New" size=2>GetCapture и size=2>SetCapture), а также дескриптор пиктограммы, ассоциированной с
    окном (Getlcon и face="Courier New" size=2>Setlcon); модифицировать расширенный или
    обычный стили окна (ModifyStyle и face="Courier New" size=2>ModifyStyleExy, получить указатель на объект
    "рабочего стола" Windows.
  •  Изменение размеров и позиции окна. Включает две группы функций —
    функции, служащие для определения или установки состояния окна:
    видимое/невидимое (GetWindowPlacement и
    SetWindow Placement}, свернуто ( face="Courier New" size=2>Islconic) или развернуто ( face="Courier New" size=2>IsZoomed) и функции, позволяющие узнать или
    изменить размеры и/или позицию окна: size=2>MoveWindow — перемещение окна с изменением размеров; face="Courier New" size=2>SetWindowPos — перемещение окна с изменением
    размеров и расположения относительно других окон; size=2>Arrange Iconic Windows — упорядочить все свернутые дочерние
    окна; BringWindowToTop — делает окно
    старшим в Z-порядке; GetWindow Rect
    определяет размеры всего окна; size=2>GetClientRect — определяет размеры рабочей области окна.
  •  Доступ к окну. Из функций этой категории мы пока хотели бы отметить
    следующие: FindWindow — позволяет
    определить, существует ли в системе окно, заданное именем класса и именем окна
    (оба параметра являются необязательными), т. е. запущено ли приложение,
    имеющее искомое окно; CenterWindow
    центрирует положение окна относительно его родителя. Кроме представленных,
    категория содержит еще большую группу функций, которые используются
    значительно реже и поэтому будут рассмотрены не все.
  •  Обновление-перерисовка. Из функций этой категории перечислю только
    наиболее часто используемые: Update
    Window — обновляет рабочую область,
    посылая сообщение WM_PAINT; face="Courier New" size=2>Invalidate — задает область модификации для
    последующей перерисовки при обработке ближайшего сообщения face="Courier New" size=2>WM_PAINT; size=2>ShowWindow — отображает окно на экране, режим отображения
    задается передаваемым параметром. Кроме вышеперечисленных, сюда же можно
    отнести группу функций для работы с контекстами устройств: face="Courier New" size=2>BeginPaint, size=2>EndPaint, Print, PrintClient, GetDC, size=2>ReleaseDC и GetWindowDC. которые подробно будут описаны при
    обсуждении вывода в окна графической информации.
  •  Преобразование координат. Служит для взаимного преобразования
    рабочих и экранных координат текущего окна.
  •  Работа с текстом. В эту категорию входят функции, которые позволяют
    установить или получить текст, ассоциированный с окном ( face="Courier New" size=2>SetWindowText и size=2>GetWindowText). и его длину ( size=2>GetWindowTextLength), а также используемый шрифт ( face="Courier New" size=2>SetFont и size=2>GetFont).
  •  Работа с сообщениями. Функции этой категории будут рассмотрены более
    подробно, т. к. они важны для понимания принципов работы всей системы face="Courier New" size=2>Windows и ваших приложений в частности.

Оставшиеся категории функций имеют достаточно специфическую направленность и
будут обсуждаться в соответствующих разделах книги. К ним относятся следующие
категории: функции для работы с полосами прокрутки, каретками, элементами блока
диалога, меню, таймерами, всплывающими подсказками, а также функции для работы с
буфером обмена и обработчики сообщений.


Класс CWnd служит для выполнения двух
основных целей: предоставление интерфейса всем другим оконным классам библиотеки
MFC и создание дочерних окон Windows. В
связи с этим мы ограничились здесь простым перечислением основных реализованных
в классе функций. Многие из них мы рассмотрим при обсуждении конкретных примеров
программ.



..............................................................4

Рис. 4.4. Основной класс для создания фреймов


В отличие от своего базового класса size=2>CWnd класс CFrameWnd (рис.
4.4) служит для создания перекрывающихся или всплывающих окон и поддерживает
однодокументный интерфейс Windows (SDI).
С этим классом (и производными от него) тесно связано понятие фрейма ( face="Courier New" size=2>frame window). Под ним понимается окно, которое
координирует взаимодействие пользователя с приложением. Оно отражается на экране
в виде рамки с необязательной строкой состояния и стандартными элементами
управления. Это окно отвечает за управление размещением своих дочерних окон и
других элементов рабочей области. Кроме того, фрейм переадресует команды своим
представлениям (специальным дочерним окнам) и может отвечать на сообщения от
элементов управления.


 Примечание 


Понятие "представление" ( size=2>view) очень тесно связано с архитектурой "документ/представление",
которую мы рассмотрим в одной из следующих глав.


Класс CFrameWnd спроектирован таким
образом, чтобы взять на себя выполнение всех основных функций приложения face="Courier New" size=2>Windows на базе интерфейса face="Courier New" size=2>SDI:



  •  Передача команды и многих общих извещений в активное текущее
    представление.
  •  Управление размещением панелей элементов управления, представлений и
    других дочерних окон внутри своей рабочей области, обновление панели
    инструментов и кнопок панелей элементов управления во время цикла ожидания,
    обработка команд по умолчанию для показа или скрытия панели инструментов и
    строки состояния.
  •  Управление полосой основного меню. Когда изображается раскрывающееся
    меню, фрейм использует механизм size=2>UPDATE_COMMAND_UI для установки элементов меню в состояние
    "доступен", "заблокирован" или "помечен", а также для добавления и удаления
    элементов. Когда пользователь выбирает элемент меню, фрейм обновляет строку
    состояния, выводя туда соответствующее заданное сообщение.
  •  Возможность использовать специальную таблицу назначений клавиш
    (accelerator table), которая
    автоматически транслирует комбинации клавиш в команды.
  •  Наличие необязательного идентификатора справки, который используется
    для контекстно-зависимой справочной системы. Управление самим механизмом
    контекстно-зависимой справочной системы (вызов комбинацией клавиш < face="Courier New" size=2>Shift>+< size=2>Fl>) и режимом предварительного просмотра перед печатью.
  •  Поддержка выполнения операций size=2>drag-and-drop для работы файлами. На перенос зарегистрированных
    и ассоциированных с приложением типов файлов класс реагирует генерацией
    требования открыть канал динамического обмена данными ( face="Courier New" size=2>DDE).
  •  Предложение сохранить модифицированные документы, выдаваемые в
    случае, если пользователь закрывает приложение, в котором фрейм является
    главным окном (определяется значением size=2>CWinThread::m_MamWnd).

Из определенных в классе CFrameWnd
компонентов мы остановимся на одном:



Startic AFX_DATA const CRect
CFramewnd: : rectDefault


Компонент определяет константный объект
класса CRect, который предписывает Windows самостоятельно установить размеры и
положение создаваемого окна и задается следующим образом:


const AFX_DATADEF CRect
CFrameWnd::rectDefault(


CW_USEDEFAULT, 


CW_USEDEFAULT,


0, 


0


0;


Функции этого класса можно сгруппировать по следующим категориям:



  • Конструктор. Как обычно, конструктор создает объект класса, но не
    создает окно.
  •  Инициализация. Сюда входят: две функции, отвечающие за
    создание окна Windows и присоединение
    его к текущему объекту класса — Create
    и LoadFrame; функция, загружающая
    таблицу командных клавиш — size=2>LoadAccelTable: группа функций для управления инициализацией
    панелей элементов управления ( size=2>LoadBarSiate — загружает сохраненные в INI-файле или реестре
    установки панели. SciveBarSJate
    сохраняет текущие установки панели в INI-файле или в реестре, face="Courier New" size=2>SetDockState — сохраняет размещение текущего
    окна относительно главного, size=2>GetDockStare — восстанавливает размещение текущего окна
    относительно главного (для плавающих панелей) и size=2>ShowControlBar — управляет режимом отображения панели элементов
    управления).
  •  Операции. В эту категорию входит большое число функций для
    работы с документами и их представлениями, с панелями элементов управления,
    строкой состояния и для управления модальностью фрейма окна.

Помимо своего основного назначения — поддержки SDI-приложений — класс
CFrameWnd служит базовым для классов CMDIFrameWnd и CMDlChildWnd, которые
созданы специально для организации приложений на базе MDI. Но о них несколько
позже.


Еще раз подчеркнем важный момент — на базе этого класса легко и удобно
создавать фреймы окон. А мы пока переходим к "развитию" нашего первого
приложения. А именно — к созданию и работе с различными типами окон Windows.



Окна Windows и библиотека MFC


Пора более подробно рассмотреть процесс создания и работы с окнами. В этом
разделе мы познакомимся с тем, как



  •  создать главное окно приложения:
  •  создать 10 дополнительных окон с различными комбинациями оконных
  • стилей в каждом;
  •  обрабатывать нажатие левой кнопки мыши.

В результате мы должны получить нечто похожее на представленное на


рис. 4.5.



.......................................................5

Рис. 4.5. Различные типы окон приложения size=2>Styles



Создание главного окна SDI-приложения


В рассмотренной в предыдущей главе программе size=2>First мы образовали класс нашего окна из базового face="Courier New" size=2>CWnd. Это допустимый, но очень неэффективный
путь. Пришло время познакомить вас с другим возможным подходом для создания
главного окна SDI-приложения.


Примечание


Такой подход стал поддерживаться только в шестой версии
Visual C++. До этого все необходимые действия приходилось выполнять вручную. Но
даже если вы пользуетесь Visual C++ 6, рекомендую не пропускать эту главу,
поскольку здесь вы найдете подробнейшее описание не только того кода, который
генерирует AppWizard, но и много другой полезной информации.


Прежде всего обратим внимание на базовый класс нашего главного окна:



class CMainFraime : public
CFrameWnd 


{


...


};


Надеюсь, здесь уже нет необходимости объяснять, почему в качестве базового
был выбран класс CFrameWncr.
Действительно, этот класс спроектирован таким образом, чтобы предоставить
максимум удобств для работы с перекрывающимися и всплывающими окнами. А, как вы
помните, в качестве главного окна приложения наиболее приемлемым является именно
перекрывающееся окно. Теперь нам надо подробно рассмотреть функцию face="Courier New" size=2>CStylesApp::lnitInsnance. где, как вы помните,
и начинается создание главного окна:



BOOL
CStylesApp::Triitlnstance()


{


// Создаем объект класса
CMain.Frame


CMainFrame ""pMainWnd = new
CMainFrame;


r_pMainWnd =-
pMainWnd;


// Создаем собственно окно
Windows 


pMainWnd->LoadFrame
(IDR^MAINFRAME);


// Определяем размеры
экрана


int cx = : :
GetSystemMetrics  (SM CXSCREEN) /8 ;


int cy = : :GetSystemMetrics
(SM CXSCREEN) /4 ;


// В зависимости от них
устанавливаем размеры окна 


// и выводим его на
экран


pMainWnd->SetWindowPos
(NULL,


cx,


cy,


6*cx,


2*cy,


SWP_NOZORDER |
SWP_SHOWWINDOW);


return TRUE;


}


Как видите, процесс создания окна состоит из трех шагов. Прежде всего
необходимо создать объект "главное окно":



CMainFrame *pMainWnd = new
CMainFrame;


Следующий шаг состоит в вызове специальной функции, которая создает окно
Windows и присоединяет его к нашему
объекту:



size=2>pMainWnd->LoadFrame(IDR_MAINFRAME);


И наконец, следует отобразить окно на экране, чтобы пользователь мог с ним
взаимодействовать:



pMainWnd->SetWindowPos
(NULL,


cx,


 су, 


6*сх, 


2*су, 


SWP_NOZORDER |
SWP_SHOWWINDOW);


Создание объекта класса не должно вызвать никаких вопросов, и поэтому
рассмотрим процесс создания окна Windows
или, используя терминологию MFC, фрейма
окна.


Из двух функций, реализованных в классе size=2>CFrameWnd, в данном случае мы остановили свой выбор на виртуальной
функции CFrameWnd:: face="Courier New" size=2>LoadFrame. которая берет на себя задачу
регистрации оконного класса, используя для этого предопределенный шаблон, и
извлекает из файла ресурсов, задаваемого идентификатором, остальные необходимые
для создания окна Windows параметры:



virtual BOOL
CFrameWnd::LoadFrame (


UINT nIDResource,


DWORD dwDefaultStyle =
WS_OVERLAPPEDWINDOW | FWS ADDTOT1TLE,


CWnd *pParentWnd =
NULL,


CCreateContext *pContext =
NULL)


Функция возвращает значение TRUE, если
создание фрейма прошло успешно, и FALSE — в противном случае. Она имеет
следующие параметры: nIDResource — идентификатор ассоциированных с фреймом
разделяемых ресурсов, который определяет меню, таблицу командных клавиш
(accelerator keys), пиктограмму и строку, помещаемую в заголовок окна;
pParentWnd— указатель на родительское окно данного фрейма (необязательный
параметр и для главного окна должен быть равен NULL— ведь главное окно не
может иметь "родителя"); pContext— указатель на структуру CCreateContex,
которая определяет объекты, связанные с данным фреймом; dwDefaultStyle— стиль
фрейма (необязательный параметр). Дополнительно к стандартным стилям окна
могут быть использованы еще и следующие:


FWS_ADDTOTITLE 



В конец заголовка окна будет добавлена
дополнительная текстовая строка


FWS_PREFIXTITLE 



Перед заголовком окна будет помещено имя
документа


FWS_SNAPTOBAR 



Размеры окна будут подогнаны под размеры
панели элементов управления 


Основное назначение функции LoadFrame
— максимальное упрощение процесса создания фрейма окна. Используя идентификатор
ресурсов, функция извлекает из них необходимые параметры и... вызывает функцию
СFrameWnd::Create, рассмотренную в
предыдущей главе. Функция загружает ресурс меню и выполняет функцию face="Courier New" size=2>CWnd::CreateEx, которая регистрирует имя
оконного класса, заполняя структуру size=2>WNDCLASS. и вызывает виртуальную функцию size=2>PreCreoteWindow.


Здесь мы немного приостановимся, поскольку сначала надо разобраться с
ресурсами. Вы обратили внимание, что единственным обязательным параметром
функции LoadFrame является идентификатор
ресурсов? Говоря точнее, обязательным является только один ресурс, а именно —
меню. И если его не определить, после запуска приложения получим сообщение об
ошибке (рис. 4.6).



..........................................................6

Рис. 4.6. Неопределение меню — единственного обязательного ресурса для
работы с функцией LoadFrame — приводит к
ошибке во время выполнения приложения


Поэтому следующим нашим шагом будет создание простейшего меню.



Создание простейшего меню


Используя мощные возможности Visual C++, создать меню чрезвычайно
просто  выполните приведенную ниже последовательность действий, и у вас
сразу все заработает.


1. Раскройте вкладку Resource View в
окне Workspace, щелкните правой кнопкой
мыши на Styles Resource и в появившемся
контекстном меню выберите пункт Insert. В
результате вы увидите окно Insert
Resource
(рис. 4.7), в котором необходимо выделить надпись face="Courier New" size=2>Menu и нажать кнопку size=2>New. Результат ваших действий представлен на рис. 4.8.


2. Щелкните правой кнопкой мыши на "пунктирном прямоугольнике" и в
появившемся контекстном меню выберите пункт size=2>Properties. Введите название пункта меню (я использовал
стандартное — Файл) в поле Caption (рис.
4.9) и обратите внимание, что под исходной полосой меню появился новый
"прямоугольник". Выделите его и введите название в поле size=2>Caption, а также идентификатор в поле size=2> ID (можно выбрать один из стандартных, как мы делаем в данном
конкретном случае — ID_APP_EXIT).



................................................7

Рис. 4.7. Диалог для выбора типа создаваемого ресурса



.................................................8

Рис. 4.8. Исходная точка для создания нашего меню



......................................................9

Рис. 4.9. В этом окне можно определить параметры элементов меню (да и
других ресурсов тоже)


Примечание 


Для того чтобы каждый раз не приходилось пользоваться
правой кнопкой мыши, нажмите кнопку Keep Visible, расположенную в левом верхнем
углу окна ... Properties. В результате окно всегда будет доступно.


3. Осталось присвоить соответствующий идентификатор самому созданному
ресурсу. Для этого в окне Workspace
выделите строку IDR_MENU1 и в поле face="Courier New" size=2>ID окна Menu
Properties
введите IDR_MAINFRAME
именно такой идентификатор мы использовали в функции size=2>LoadFrame.


4. Вновь скомпилируйте и запустите приложение.


Результат, как видите, совершенно другой — все работает, ничего не "падает",
и окно ведет себя аналогично тому, как это было в нашем первом примере. Более
того, выбрав пункт меню "Выход", вы увидите, что приложение действительно
закрылось. И это несмотря на то, что мы не добавили ни строчки кода. Благодаря
выбранному нами идентификатору библиотека сама разобралась в том, чего мы хотим,
и все сделала.


Итак, на данный момент мы подошли к тому же результату, что и в первом
приложении, только "с другой стороны". Однако вернемся к нашему главному окну.



Создание главного окна приложения
(продолжение)


Мы остановились на том, что в процессе выполнения функции face="Courier New" size=2>PreCreateWindow система Windows посылает в окно
следующие сообщения: WM_GETMINMAXINFO,
WM_NCCREATE, WM_NCCALKSIZE
и WM_
CREATE
. Если при создании окна был определен стиль face="Courier New" size=2>WS_VISIBLE, то в окно дополнительно посылаются
все сообщения, необходимые для активизации и отображения окна на экране. Таким
образом, переопределяя функцию size=2>PreCreateWindow и/или обработчик любого из представленных
сообщений Windows, можно изменять
параметры оконного класса и собственно окна как до, так и после создания окна
Windows.


Рассмотрим, как этот механизм реализован в нашей программе. Начнем с
переопределения функции size=2>CFrameWnd::PreCreateWindow. Для этого:


1. Откройте окно ClassWizard, выбрав
пункт меню View ClassWizard или нажав
аналогичную кнопку на панели инструментов (это для тех, кто как и я предпочитает
работать с кнопками панели инструментов, а не через меню).


2. В раскрывающемся списке Class name
выберите класс CMainFrame, a в
списке Messages size=2>PreCreateWindow (рис. 4.10). Нажмите кнопку face="Courier New" size=2>Add size=2>Function (или дважды щелкните левой кнопкой мыши по имени
PreCreateWindow) и затем кнопку Edit Code, чтобы непосредственно перейти на то
место проекта, где мы будем выполнять дальнейшие действия.



.......................................................10

Рис. 4.10. ClassWizard
существенно облегчает процесс создания новых функций


3. Внесите в переопределенную функцию необходимые изменения. В нашем случае
она примет вид:



BOOL CMainFrame::
PreCreateWindow (GREATEST/ROOT& cs)


 {


cs.lpszName = "Главное окно
приложения "Стили"";


 return
CFrameWnd::PreCreateWindow(cs); 


}


Единственный параметр, передаваемый в эту функцию, — ссылка на структуру
CREATESTRUCT, которая определяет
параметры инициализации, посылаемые в оконную процедуру, и содержит следующие
поля:



typedef struct
tagCREATESTRUCT{


LPVOID
IpCreateParams; 


HANDLE
hlnctance; 


HMENU hMenu;


HWND hwndParent;


int cy; 


int cx; 


int y;


int x; 


LONG style; 


LPCSTR IpszName;


LPCSTR
IpszClass; 


DWORD dwExStyie; 


}CREATESTRUCT;


Назначение полей этой структуры:
IpCreateParams — указатель на данные, используемые при создании окна;
hlnstance — дескриптор модуля, который владеет окном; hMenu— идентификатор
меню, используемого окном; hwndParent — дескриптор окна-родителя, если этот
параметр равен NULL, то новое окно является окном верхнего уровня; су, сх, у,
х— целые числа, задающие соответственно ширину и высоту окна, а также его
положение относительно своего владельца; IpszName— символьная строка, задающая
имя окна; IpszClass— символьная строка, содержащая имя класса, которому
принадлежит окно; dwExStyie — определяет атрибуты расширенного стиля
окна.


Мы использовали функцию size=2>PreCreateWindow, чтобы не заниматься процедурой регистрации класса
окна, возложив эту задачу на библиотеку, поскольку принятые по умолчанию
установки нас вполне устраивают. Единственное, что нам следует заменить, это
заголовок окна:



cs . IpszName = "Главное окно
приложения "Стили "";


Это один из возможных способов присвоения имени окну. После того как окно
Windows создано и присоединено к объекту
фрейма окна библиотеки MFC, ему посылается сообщение size=2>WM_CREATE. Для этого сообщения в библиотеке (точнее, в классе
CWnd) создан специальный обработчик —
OnCreate, который можно переопределить
под свои потребности:



int CMainFrame: :OnCreate
(LPCREATESTRUCT IpCreateStruct)


{


if
(CFrameWnd::OnCreateiIpCreateStruct: = -1)


renurn -1;


return 0;


}


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


Для правильного завершения процесса создания окна не забывайте вызывать перед
какими-либо своими действиями обработчик базового класса face="Courier New" size=2>CFrameWndr.OnCreate. Вы, конечно же, понимаете,
что последняя фраза относится к случаю самостоятельного создания прототипа этой
функции — если воспользоваться услугами size=2>ClassWizard, то каркас функции будет вам уже предоставлен.


После того как фрейм создан, его необходимо вывести на экран. Библиотека
предоставляет несколько функций для реализации этого процесса. Для отображения
нашего главного окна мы остановились на одной из них — функции face="Courier New" size=2>СWnd::SetWindowPos.



BOOL CWnd::SetWindowPos
(


const CWnd
*pWndlnsertAfter,


 int x,


 int y, 


int cx,


int cy,


 UINT nFlags)


Вызов этой функции позволяет изменить как
размеры, так и расположение дочерних и всплывающих окон относительно экрана и
других окон. Она имеет следующие параметры: pWndlnsertAfter — указывает на
объект CWnd, после которого будет расположено окно. Вместо этого указателя
можно использовать одно из следующих предопределенных значений, задающих
расположение окна относительно других окон:


wndBottom 



Разместить окно под другими окнами (внизу
стека Z-no-рядка); если окно имело статус wndTopMost то этот статус теряется —
удаляется флаг расширенного стиля WS_EX_TOPMOST


wndTop 



Разместить окно над другими окнами (на
вершине стека Z-порядка)


wndTopMost 


Разместить окно над всеми другими окнами,
имеющими статус wndTopMost; эта позиция сохраняется (флаг расширенного стиля
WS_EX_TOPMOST остается установленным), даже когда окно находится в неактивном
состоянии


wndNoTopMost



Переместить окно выше всех окон, имеющих
статус wndTop, но ниже окон, имеющих статус wndTopMost


х, у, сх, су— задают новые значения,
соответственно, горизонтального и вертикального расположения окна, его ширины и
высоты. nFlags — определяет параметры размера и позиции окна и может принимать
одно из следующих значений:


SWP_DRAWFRAME 



Задает рамку вокруг окна, определенную в
классе окна


SWP_HIDEWINDOW



 Делает окно невидимым 


SWP_NOACTIVATE 



Блокирует активизацию окна


SWP_NOMOVE



 Предписывает окну сохранение текущей
позиции; параметры х и  у игнорируются


SWP_NOREDRAW



 Предписывает не перерисовывать окно;
после перемещения приложение должно перерисовать окно самостоятельно


SWP_NOSIZE 



Задает сохранение текущих размеров;
параметры сх и су игнорируются


SWP_NOZORDER



Задает сохранение текущего расположения
окна относительно других окон, при этом параметр pWndlnsertAfter
игнорируется


SWP_SHOWWINDOW 



Отображает окно


Примечание


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


Мы использовали функцию SetWindowPos
для указания размеров и расположения окна, а также для того, чтобы сделать его
видимым.


 Примечание 


Как я уже говорил, существуют и другие способы решения
этой задачи, многие из них также будут рассмотрены.


Следующий вопрос, на котором мы остановимся— как создаются дочерние окна.


 Примечание 


Поскольку любое порожденное окно программисты зачастую
называют "дочерним", то часто возникает некоторая путаница. Вы должны совершенно
четко отличать стиль
size=2>WS_CHILD от более широкого разговорного
понятия "дочерний"
.



Создание дочерних окон


Теперь, после создания основного окна приложения, можно переходить к созданию
некоторого дополнительного пространства для отображения информации и/или для
получения команд от пользователя. Каждому "ребенку", как и основному окну, можно
приписать конкретный стиль таким образом, чтобы приспособить его внешний вид и
назначение к стоящим перед ним задачам. В приложении size=2>Styles мы разбили создаваемые окна на два набора. Окна первого
располагаются на экране независимо от положения основного окна и имеют стиль
WS_POPUP, а для окон из второго набора
установлен стиль WS_CHILD и,
следовательно, они не могут покинуть пределы рабочей области основного окна.


Для создания дочерних окон необходимо проделать следующие действия: 



  •  Создать два новых класса, каждый из которых будет отвечать за "свои"
    окна.
  •  Привязать объекты этих классов к главному окну приложения. 
  •  Аналогично главному окну приложения создать по пять экземпляров
    новых классов. 
  •  Отобразить их на экране.

Есть и другие действия, но к ним мы перейдем постепенно.


Первое из перечисленных в списке действий совершим, воспользовавшись мастером
ClassWizard.


1. Откроем окно ClassWizard и в нем
нажмем кнопку-меню Add Class, где выберем
элемент New (рис. 4.11).



..................................................11

Рис. 4.11. Создаем новый класс


2. В результате на экране появится диалоговое окно size=2> New Class, в поле Name
которого вводим имя вновь создаваемого класса — у меня это face="Courier New" size=2>CChildWnd, а в раскрывающемся списке face="Courier New" size=2>Base class — имя базового класса, в данном
случае CWnd (рис. 4.12).


3. Нажимаем кнопку ОК и новый класс
создан.


4. Повторяем действия, описанные в п. 1. Только теперь не будем создавать
новых файлов, а воспользуемся уже существующими. Для этого нажмем кнопку face="Courier New" size=2>Change и в диалоговом окне face="Courier New" size=2> Change files выберем файлы < face="Courier New" size=2>childwnd.h> и < size=2>childwnd.cpp> (рис. 4.13).


5. В качестве базового класса в данном случае используем класс face="Courier New" size=2>CFrameWnd, поскольку size=2>CWnd не стоит использовать для создания всплывающих окон (рис.
4.14).


Примечание 


Такое разбиение не продиктовано необходимостью и
произведено лишь для наглядности. Дело в том, что, как мы упоминали, на базе
класса CWnd можно создавать только дочерние окна (имеющие стиль WS^CHILD). Его
мы и решили использовать для этих целей. На базе же класса CFrameWnd могут быть
созданы окна любого из трех имеющихся типов. Поэтому для создания всплывающих
окон именно он и был использован в качестве базового.



....................................................12

Рис. 4.12. Присваиваем имя и выбираем базовый класс для вновь
создаваемого



........................................................13

Рис. 4.13. Не будем создавать новых файлов



...............................................................14

Рис. 4.14. Для всплывающих окон в качестве базового используем класс
CFrameWnd


Как видите, создать новый класс чрезвычайно просто. К сожалению, это
высказывание справедливо не всегда — не из всех классов библиотеки face="Courier New" size=2>MFC можно создавать свои с помощью мастера
ClassWizard.


Следующим шагом является создание объектов новых классов и их привязка к
главному окну приложения. Последовательность действий при этом следующая:


1. В определении класса CMainFrame
вводим объекты новых классов



class CMainFrame : public
CFrameWnd 


{


...


CChildWnd
*apChildWnd[5]; 


CPopupWnd
*apPopupWnd[5];


...


};


2. В конструкторе класса CMainFrame
устанавливаем указатели на эти объекты в size=2>NULL, чтобы иметь гарантии корректности создания окон



size=2>CMainFrame::CMainFrame() 


{


for(int i = 0; i < 5;
i++) 


{


apChildWnd[i] = NULL;


  apPopupWnd[i] =
NULL; 


}


}


3. Теперь осталось вернуться к обработчику сообщения size=2>WM_CREATE:



extern char
szNameWnd[128];


int
CMainFrame::OnCreate(LPCREATESTRUCT IpCreateStructi 


{


if
(CFrameWnd::OnCreate(IpCreateStruct) == -1)


 return -1;


// Создаем пять дочерних окон
for (int i = 0; i < 5; i++)


{


apChildWnd[i] = new
CChildWnd; 


size=2>apChildWnd[i]->Create(NULL, NULL, WS_VISIBLE,


CRectfO, 0, 0, 0), this,
(UINT)i); 


}


// Установка нового курсора
для класса дочерних окон


size=2>::SetClassLong(apChildWnd[0]->GetSafeHwnd() , GCL_HCURSOR,


size=2>(LONG)AfxGetApp()->LoadStandardCursor(IDC_IBEAM));


// Создаем четыре всплывающих
окна 


for(i =0; i < 4;
i++)


{


apPopupWnd[i] = new
CPopupWnd;


size=2>apPopupWnd[i]->Create(NULL, NULL, 0,


rectDefault, this);


// Указываем номер окна в
поле данных, ассоциированных с окном


size=2>::SetWindowLong(apPopupWnd[ij->Get.SafeHwnd() ,


 GWL_USERDATA,
i);


// Формируем новый заголовок
окна


sprintf(szNameWnd, "Окно %d",
i ) ;


size=2>apPopupWnd[i]->SetWindowTex~(szNameWndi);


// Создаем перекрывающееся
окно


apPopupWnd[4] = new
CPopupWnd;


size=2>apPopupWnd[4]->Create(NULL, NULL, 0, rectDefaulr) ;
::SetWindowLong(apPopupWnd[i]->GetSafeKwnd(),


GWLJJSERDATA, 4);


sprintf(szNameWnd, "Окно %d",
i);


size=2> apPopupWnd[4]->SetWindowText(szNameWnd) ;


// Устанавливаем новый курсор
для класса всплывающих окон ::SetClassLong(apPopupWnd[0]->GetSafeHwnd. (),
GCL_HCURSOR,


size=2>(LONG}AfxGerApp(i->LoadStandardCursor(IDC_UPARROW)); 


// Создаем и устанавливаем
новый цвет фона для всплывающих окон


 HBRUSH hNewBrush =
::CreareSolidBrush;(RG3(255, 255, 220));
::SetClassLong(apPopupWnd[3]->GetSafeHwnd(),


GCL_HBRBACKGROUND, (LONG )
hNewBrush) ; .


// Отображение всплывающих
окон


 ford = 0; i < 5;
i++)


 {


size=2>apPopupWnd[i]->ShowWindow(SW_3HOWNORMAL);


apPopupWnd
Гi]->UpdateWindcw () ;


}


}


Как видите, при ближайшем рассмотрении это не более, чем создание десяти
окон, принадлежащих двум новым классам.


В основном процесс создания окон обоих типов стандартен: создаются объекты
классов, после чего вызывается некоторая функция для создания окна face="Courier New" size=2>Windows. Чтобы продемонстрировать как можно
больше предоставляемых библиотекой возможностей, в текст программы включены
дополнительные строки. Но обо всем по порядку. Начнем с дочерних окон, имеющих
установленный бит стиля WS_CHILD (процесс
создания объекта класса ничем не отличается от уже рассмотренных, и мы больше не
будем останавливаться на этом вопросе). Итак, вызов функции face="Courier New" size=2>CWnd::Create;



size=2>apChildWnd[i]->Create(NULL, NULL, WS_VISIBLE,


CRect(0, 0, 0, 0}, this,
(UINT)i);


Подчеркнем некоторые моменты. Во-первых, не определен класс Windows, к
которому относится окно, — эту задачу мы переложили на плечи библиотеки.
Во-вторых, установив бит стиля size=2>WS_VISIBLE, мы задали режим, когда окно сразу же после создания
выводится на экран. В-третьих, окно мы превратили в точку и поместили его в
левый верхний угол экрана. В-четвертых, окно имеет "родителя" — пятый параметр
определен как this. И. наконец, в
качестве последнего параметра мы передаем номер создаваемого окна. Как и при
создании главного окна, мы переопределяем функцию


BOOL
CChildWnd::PreCreateWindow(CREATESTRUCT& cs)


{


cs.style i=
adwStyles[nCount];


 sprintf (szNameWnd, "Окно
*d", nCount!; cs.ipszName = szNameWnd;


return
CWnd::PreCreateWindow(cs);


}


и функцию-обработчик сообщения size=2>WM_CREATE



int
CChildWnd::OnCreate(LPCREATESTRUCT IpCreateStruct)


 {


if
(CWnd::OnCreate(IpCreateStruct) == -1)


 return -1;


MoveWindow(nCount++ * 118,
24, 116, 96);


 return 0; 


}


Первая заполняет поля style и face="Courier New" size=2>IpszName структуры size=2>CREATESTRUCT соответственно значениями стиля и имени конкретного
окна, а вторая — устанавливает размер и положение вновь созданного окна
(напомним, что мы задали окну нулевые размеры). Со структурой face="Courier New" size=2>CREATESTRUCT мы уже познакомились, поэтому
рассмотрим изящную функцию
CWnd::MoveWindow
, которая реализована в двух вариантах:



void CWnd::MoveWindow
(


int x, 


int. y, 


int nWidth, 


int nHeight, 


BOOL bRepaint =
TRUE) 


и



void
CWnd::MoveWindow(


 LPCRECT
IpRect, 


BOOL bRepaint = TRUE)


С помощью любой из этих реализаций можно
одновременно изменить размер и положение окна, задаваемые в параметрах х, у,
nWidth, nHeight или IpRect. Последний параметр функции определяет, будет ли
окно перерисовываться после перемещения. Если этот параметр равен TRUE (по
умолчанию), то объект "окно" получает сообщение Windows WM_PAINT. Кроме того,
функция посылает еще и сообщение WM_GETMINMAXINFO, которое вы также можете
обработать.


Примечание 


Здесь необходимо отметить, что позиция дочернего окна
определяется относительно координат его владельца, в то время как для
всплывающего окна положение задается относительно экрана.


Как мы уже отметили, задача регистрации оконного класса была поручена
библиотеке. Нам лишь остается "подправить" некоторые поля в соответствии с
собственными нуждами. Один из возможных путей состоит в применении функций face="Courier New" size=2>API size=2>SetClassLong. GetClassLong,
SetWindowLong и size=2>GetWindowLong. Возможно, вы захотите использовать их в своих
программах, поэтому рассмотрим эти функции подробнее.



DWORD SetClassLong


HWND hWnd,


 int
nlndex, 


LONG dwNewLong)


Эта функция устанавливает в структуре size=2>WNDCLASS, описывающей оконный класс для size=2>hWnd, новое значение size=2>dwNewLong в поле, определяемом параметром nlndex, который может
принимать одно из следующих значений:


GCL_CBCLSEXTRA



Устанавливает размер (в байтах)
дополнительной памяти, предназначенной для использования всеми окнами,
создаваемыми на базе этого класса; размер памяти, уже ассоциированной с
классом, при этом не изменяется


GCL_CBWNDEXTRA 



Устанавливает размер (в байтах)
дополнительной памяти, предназначенной для использования отдельно каждым
окном, создаваемым на базе этого класса; размер памяти, уже ассоциированной с
окном, при этом не изменяется


GCL_HBRBACKGROUND 



Устанавливает дескриптор кисти для фона,
ассоциированного с этим классом


GCL_HCURSOR 



Устанавливает дескриптор курсора,
ассоциированного с этим классом


GCL_HICON



 Устанавливает дескриптор пиктограммы,
ассоциированной с этим классом


GCL_HMODULE 



Устанавливает дескриптор модуля, который
зарегистрировал этот класс


GCL_MENUNAME 



Устанавливает адрес строки меню, которая
идентифицирует ресурс меню, ассоциированного с этим классом


GCL_STYLE 



Устанавливает биты стиля оконного класса
GCL_WNDPROC Устанавливает адрес оконной процедуры, ассоциированной с
классом


При успешном выполнении функция возвращает
значение указанного слова из структуры класса окна или нулевое значение — в
случае ошибки. Дополнительную информацию об ошибке можно получить, вызвав
функцию API GetLastError.


Мы воспользовались функцией size=2>SetClassLong для того, чтобы установить новые значения для курсора
и цвета фона.


Обратную задачу — получение информации из структуры класса окна — выполняет
функция GetClassLong.



DWORD GetClassLong
(


 HWND hWna,


 int nIndex).


Для работы с дополнительной памятью в структуре окна интерфейс face="Courier New" size=2>API предоставляет также две функции:



DWORD SetWindowLong
(


HWND hWnd,


int nlndex,


LONG dwNewLong) 


и



DWORD GetWindowLong
(


HWND hWnd,


int nlndex)


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


GWL_EXSTYLE 



Устанавливает новый расширенный стиль
окна 


GWL_STYLE 



Устанавливает новый стиль окна


GWL_WNDPROC 



Устанавливает новый адрес оконной
процедуры


 GWL_HINSTANCE



 Устанавливает новый дескриптор
приложения 


GWL_ID 



Устанавливает новый идентификатор
окна 


GWL_USERDATA 



Устанавливает 32-разрядное значение,
ассоциированное с конкретным окном и предназначенное для использования
приложением, которым это окно создано


Если дескриптор hWnd определяет блок диалога,
то доступными являются следующие значения:


DWL_DLGPROC 



Устанавливает новый адрес процедуры блока
диалога 


DWL_MSGRESULT 



Устанавливает значение, возвращаемое при
обработке сообщения в процедуре блока диалога


DWL_USER 



Устанавливает новую дополнительную
информацию для приложения, напр., идентификатор или указатель


Для функции GetWindowLong, кроме перечисленных, определено еще одно доступное
значение:


GWL_HWNDPARENT 



Возвращает дескриптор родительского окна
или NULL, если его нет


Мы использовали функцию SetWindowLong
для записи в дополнительную память номера созданного окна. Другими словами, у
первого окна в этом поле будет 0, у второго — 1, у третьего — 2 и т. д. Позже,
во время изображения окон на экране, программа воспользуется этими значениями
для идентификации окон.


Перед тем как закончить обсуждение вопроса об изменении характеристик оконных
классов и собственно окон, осталось отметить способ получения дескриптора окна
Windows. Для этой цели в классе CWnd
предусмотрена специальная функция



HWND CWnd::GetSafeWnd
()


Эта функция позволяет получить дескриптор
окна Windows, хранящийся в компоненте класса CWnd::m_hWnd, или NULL, если к
объекту не присоединено никакое окно.


Но вернемся к нашей программе. Нам осталось разобраться в создании
всплывающих окон. Обратите внимание на два несколько отличающихся вызова
функции CFrameWnd::Create:



size=2>apPopupwnd[i]->Create(NULL, NULL, 0, rectDefault, this);


и



size=2>apPopupWnd[4]->Create(NULL, NULL, 0, rectDefault);


и связанное с этим отличие в поведении всплывающих окон 3 и 4. Для четвертого
окна мы не указали родителя, и поэтому оно ведет себя достаточно независимо от
нашего главного окна.


Второй момент, на который хотелось бы обратить ваше внимание, связан с еще
одним способом изменения стилей созданных окон. Обратимся к тексту:



int
CPopupWnd::OnCreate(LPCREATESTRUCT IpCreateStruct)


{


ModifyStyle((DWORD)-1,
adwStyles[nCount] );


...


return 0;


}


Как видите, для установки стиля окна мы воспользовались функцией класса face="Courier New" size=2>CWnd — ModifyStyle:



BOOL CWnd::MbdifyStyle
(


DWORD dwRemove, 


DWORD dwAdd, 


UINT nFlags = 0)


Эта функция позволяет удалить ( size=2>dwRemove) или установить ( size=2>dwAdd) определенные атрибуты стиля окна. Если установлен параметр
nFlags, то вызывается функция face="Courier New" size=2>API :: size=2>SetWindowPos с этим параметром, являющимся комбинацией одного или
нескольких значений: SWP_NOMOVE, face="Courier New" size=2>SWP_NOACTIVATE, size=2>SWP_NOSIZE и SWP_NOZORDER.


Для изменения флагов расширенного стиля можно использовать функцию face="Courier New" size=2>Modify Style
Ex.



BOOL CWnd::MbdifyStyleEx


DWORD dwRemove, 


DWORD dwAdd, 


UINT nFlags = 0)


Попутно упомянем две функции, которые позволяют узнать текущие обычный и
расширенный стили окна:



DWORD CWnd::GetStyle
()


и



DWORD CWnd::GetExStyle
()


При рассмотрении вопроса о создании главного окна приложения мы обошли
молчанием конструктор и деструктор объекта этого окна. Вернемся теперь к их
содержимому:



CMainFrame: : CMainFrame
()


{


forfint 1=0; i < 5;
i++)


{


apChildWndfi] = NULL;


apPopupWnd[i] =
NULL; 


}


}


size=2>CMainFrame::~CMainFrame()


{


for(int i=0; i < 5;
i++)


if(apChildWnd[i] !=
NULL)


 delete
apChildWnd[i];


}


}


Как видите, мы явно освобождаем только ту память, которую занимали объекты,
образованные из класса, производного от size=2>CWnd. При использовании


в качестве базового других классов (в нашем случае size=2>CFrameWnd) явно освобождать память не надо, т. к. объекты
выполняют это сами.



Ограничение размеров окна


Мы создали главное окно приложения size=2>Styles таким образом, что пользователь не может изменить его
размеры. Более того, окно не изменит своих размеров даже тогда, когда вы
попытаетесь максимизировать его. Такое поведение окна достигается введением
соответствующей обработки сообщения size=2>Windows WM_GETMINMAX1NFO, которая выполняется обработчиком:



void
CMainFrame::OnGetMinMaxInfо(MINMAXINFO FAR* IpMMI)


}


int :x = : :GetSystemMetrics
(SM CXSCREEN) / 8;


int ey = :: GetSystemMetrics
(SM_CYSCREEN)/4;


lpMMI->ptMinTrackSize.x =
6*cx;


lpMMI->ptMinTrackSize.y =
2*cy;


lpMMI->ptMaxTrackSize.x =
6*cx;


lpMMI->ptMaxTrackSize.y =
2*cy;


lpKMI->ptMaxPosition.x =
Cx;


lpMMI->ptMaxPosition.y =
cy;


size=2>CFrameWnd::OnGetMinMaxInfо(IpMMI);


}


Обработчику в качестве параметра передается указатель на структуру типа face="Courier New" size=2>MINMAXINFO, которая содержит информацию о
максимально возможных размерах и позиции окна, а также о минимальных и
максимальных изменяемых размерах:



typedef struct tagMINMAXINFO
(


POINT ptReserved;


POINT ptMaxSize;


POINT ptMaxPosition;


POINT ptMinTrackSize;


POINT ptMaxTrackSize;


 } MINMAXINFO;


Поля этой структуры имеют следующие
назначения: ptReserved— зарезервировано для внутреннего использования;
ptMaxSize— устанавливает размеры окна, которые оно может иметь в развернутом
виде; ptMaxPosition — устанавливает значение, которое должен иметь левый
верхний угол развернутого окна; ptMinTrackSize— устанавливает минимальные
размеры, до которых пользователь может сжать границы окна; ptMaxTrackSize—
устанавливает максимальные размеры, до которых пользователь может растянуть
границы окна.


Как видите, все очень просто. Последнее, что нам осталось рассмотреть — каким
образом можно получить информацию о системных параметрах.



Функция GetSystemMetrics


Эта функция позволяет получить размеры (высоту и ширину) изображаемы*
элементов Windows, а также другую информацию. Все размеры даются в пикселах.



int GetSystemMetrics
(int nlndex)


Значение nIndex определяет параметр,
который вы хотите получить (возвращаемые функцией значения могут изменяться в
зависимости от типа используемого дисплея и установок пользователя). Приведем
небольшой список наиболее часто используемых параметров:


SM_CMOUSEBUTTONS 



Число кнопок мыши; если мышь не
установлена, то возвращается 0


SM_CXDORDE color=#800000>R face="Courier New" color=#800000 size=2>SM_CYDORDER color=#800000>                 



 Ширина и высота рамки
окна 


SM_CXFULLSCREEN,
SM_CYFULLSCREEN



 Ширина и высота рабочей области
максимизированного окна


SM_CXICON, SM_CYICON



Ширина и высота большой пиктограммы,
заданные по умолчанию; обычно они равны 32, но могут изменяться в зависимости
от установок пользователя


SM_CXMIN, SM_CYMIN 



Минимальные допустимые ширина и высота
окна


 SM_CXMINTRACK,
SM_CYMINTRACK



 Минимальные величины, до которых
пользователь может уменьшить ширину и высоту окна; для их изменения необходимо
обработать сообщение Windows WM_GETMINMAXINFO


SM_CXSCREEN, SM_CYSCREEN



Ширина и высота экрана 


SM_CYCAPTION



 Высота области заголовка
окон 


SM_CYMENU 



Высота полосы меню


SM_SWAPBUTTON 



He равен 0, если левая и правая кнопки мыши
обменялись своими функциями


SM_CXEDGE, SM_CYEDGE



Горизонтальный и вертикальный размеры
трехмерной рамки


SM_CXFIXEDFRAME,
SM_CYFIXEDFRAME



Толщина (по горизонтали и вертикали) рамки
окна, которое имеет заголовок, но не может изменить свои размеры


SM_CXMAXIMIZED,
SM_CYMAXIMIZED



Предельно допустимые размеры развернутого
окна 


SM_CXMAXTRACK,
SM_CYMAXTRACK 



Максимальные величины, до которых
пользователь может увеличить ширину и высоту окна; для их изменения необходимо
обработать сообщение Windows WM_GETMINMAXINFO


SM_CXMINIMIZED,
SM_CYMINIMIZED



Предельно допустимые размеры свернутого
окна 


SM_CXSIZEFRAME, 
SM_CYSIZEFRAME



Толщина (по горизонтали и вертикали) рамки
окна, которое может изменять свои размеры


SM_CXSMICON, SM_CYSMICON



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


SM_CYSMCAPTION 



Высота области уменьшенного
заголовка


SM_NETWORK 



В возвращаемом значении установлен самый
младший бит, если сеть присутствует; остальные биты зарезервированы для
будущего использования


SM_SECURE 



Функция возвращает ненулевое значение, если
установлена защита, и 0 — в противном случае



Ограничение доступа к окну


Большинство из стилей окна, использованных в приложении face="Courier New" size=2>Styles, достаточно ясны. Поэтому мы остановимся
только на одном из них — WS_DISABLED.
Окна, имеющие такой стиль, абсолютно неподвижны, и ими нельзя манипулировать ни
с помощью мыши, ни с помощью клавиатуры. Обратите также внимание, что у такого
окна и курсор не соответствует заданному в оконном классе. Для доступа к этому
свойству окон в классе CWnd реализована
специальная функция



BGOL
CWnd::EnableWindow (BOOL bEnable = TRUE)


Разрешает (bEnable = TRUE) или запрещает
(bEnable = FALSE) доступ к окну для мыши и клавиатуры. Если при вызове функции
изменилось состояние окна, то до возврата из нее Windows посылает окну
сообщение WM_ENABLE.


Для того чтобы узнать текущее состояние окна в смысле его доступности, можно
использовать функцию



BOOL CWnd::IsWindowEnable
()


Возвращает значение TRUE, если окно
доступно, и FALSE — в противном случае.


Основная цель этой главы и рассмотренного в ней приложения — знакомство с
основными классами библиотеки MFC,
отвечающими за создание и работу практически всех типов окон Windows. Исключение
составляют окна так называемых size=2>MDI-приложений — приложений многодокументного (или многооконного)
интерфейса, которые мы рассмотрим несколько позже.


Здесь я попытался максимально подробно рассмотреть основные аспекты
программирования для Windows с использованием библиотеки классов MFC


и показать, что слухи о сложности этого процесса "несколько преувеличены".
Разобравшись в основах, изложенных в данной главе, вы уже прошли большую часть
пути: программирование для Windows — это прежде всего работа с окнами.


Единственный механизм, которым мы достаточно активно пользовались, но о
котором мало что сказали — работа с сообщениями. Поэтому, на мой взгляд, будет
разумно отвлечься на этот чрезвычайно важный вопрос и рассмотреть его более
глубоко и "теоретизированно".


По материаллам сайта: www.realcoding.net

16.02.2006

Телефон

+7 8636 237-836

Поиск

VSESMI.ru — новости в СМИ.
Один из больших по объему информации проектов, работающих под управлением HostCMS.

Tur-Hotel.ru — отзывы об отелях
На сайте представлено описание отелей, рейтинг отелей с отзывами туристов.