- •История Windows
- •Windows 1.0
- •Windows 1.3
- •Windows 2.0
- •Windows 3.0
- •Windows 3.1
- •Windows for Workgroups версии 3.11
- •Windows NT
- •Windows 95
- •Windows NT Workstation 4.0 и Windows NT Server 4.0
- •Windows NT 4.0 Server Enterprise Edition
- •Windows 98
- •Windows 98 Second Edition (SE)
- •Windows 2000
- •Windows 98 Millenium Edition (ME)
- •Windows XP
- •Общая архитектура WINDOWS приложения.
- •Каркас приложения
- •Регистрация класса окна
- •Создание окна.
- •Отображение окна.
- •Цикл обработки очереди сообщений.
- •WndProc
- •Обработка сообщений типового приложения.
- •Контрольные вопросы
- •Сообщения
- •Типы сообщений
- •Обработка клавиатурных сообщений
- •Обработка сообщений от мыши
- •Сообщения таймера
- •Контрольные вопросы
- •Организация ввода
- •Разупорядоченный ввод
- •Разделение потоками виртуальных очередей ввода
- •Локальное состояние ввода
- •Ввод с клавиатуры и фокус
- •Управление курсором мыши
- •Контрольные вопросы
- •Окна
- •Окна Windows
- •Иерархия окон
- •Оконная процедура, стандартные оконные процедуры
- •Стиль класса окна
- •Стили окон, окна основных стилей
- •Перекрывающиеся окна
- •Временные окна
- •Дочерние окна
- •Сообщения управления окнами
- •Окна с полосами прокрутки
- •Системные метрики
- •Определение размера окна
- •Определение расположения окна
- •Контрольные вопросы
- •Графический интерфейс устройств(GDI).
- •Создание (получение) контекста устройств.
- •Сохранение контекста устройства.
- •Прямые (отрезки) и кривые
- •Закрашенные области
- •Битовые шаблоны (растровые шаблоны, растровые образы)
- •Текст и шрифты
- •Режимы масштабирования и преобразования
- •Метафайл
- •Регионы
- •Путь
- •Палитры
- •Контрольные вопросы
- •Объекты ядра
- •Что такое объект ядра
- •Учет пользователей объектов ядра
- •Защита
- •Таблица описателей объектов ядра
- •Создание объекта ядра
- •Закрытие объекта ядра
- •Синхронизация объектов
- •Именованные объекты
- •Дублирование описателей объектов
- •Изменение флагов описателя
- •Синхронизация потоков
- •Критическая секция
- •Мьютексы
- •Семафоры
- •События
- •Ожидаемые таймеры
- •Контрольные вопросы
- •Ресурсы Windows приложения
- •Файлы ресурсов приложения
- •Значки (пиктограммы)
- •Курсоры
- •Битовые образы
- •Символьные строки
- •Ресурсы, определяемые пользователем
- •Таблица акселераторов
- •Меню
- •Диалоговые окна
- •Контрольные вопросы
- •Элементы управления
- •Дочерние окна управления
- •Создание дочерних окон
- •Сообщения родительского окна дочерним окнам
- •Дочерние окна и фокус ввода
- •Дочерние окна управления и цвет
- •Сообщения дочерних окон родительскому окну
- •Кнопки различных стилей (класс BUTTON)
- •Нажимаемые кнопки
- •Флажки-переключатели
- •Переключатели
- •Окна групп
- •Кнопки, определяемые пользователем
- •Статические поля (класс static)
- •Текстовые редакторы (класс edit)
- •Списки разных стилей (класс listbox)
- •Комбинированные списки (класс combobox)
- •Полосы прокрутки (класс scrollbar)
- •Контрольные вопросы
- •Расширенные элементы управления
- •Основы общих элементов управления
- •Инициализация библиотеки элементов общего пользования
- •Создание элементов управления общего пользования
- •Посылка сообщений общим элементам управления
- •Уведомляющие сообщения от общих элементов управления
- •Контрольные вопросы
- •Стандартные диалоговые окна.
- •Окна сообщений
- •Диалоговые окна общего пользования
- •Контрольные вопросы
- •Динамически подключаемые библиотеки
- •Создание DLL
- •Проецирование DLL на адресное пространство процесса
- •Функция входа/выхода
- •Функция DllMain и стандартная библиотека С
- •Функция LibEntry
- •Функция LibMain
- •Функция WEP
- •Экспорт функций и переменных из DLL
- •Импорт функций и переменных из DLL
- •Заголовочный файл DLL
- •Разделы в ЕХЕ- и DLL-файлах
- •Контрольные вопросы
- •Файлы, проецируемые в память
- •Контрольные вопросы
- •Классы, определяющие архитектуру приложения
- •Классы приложения и поддержки потоков
- •Классы приложения и потоков
- •Классы фреймов окон
- •Получение информации о приложении
- •Соглашения об именах MFC
- •Включаемые файлы
- •Функция WinMain
- •Класс CWinApp
- •Класс CWnd
- •Класс CFrameWnd
- •Создание главного окна SDI-приложения
- •Примечание
- •Создание главного окна SDI-приложения
- •Создание дочерних окон
- •Ограничение размеров окна
- •Ограничение доступа к окну
- •Создание многодокументных приложений
- •Класс CMDIChildWnd
- •MDI — пример приложения
- •Категории сообщений
- •Карта сообщений
- •Компоненты карты сообщений
- •Класс CCmdTarget
- •Стандартный маршрут команды
- •Команды обновления и класс CCmdlll
- •Функции для работы с сообщениями
- •Основные положения
- •Класс CDocTemplate
- •Класс CSingleDocTemplate
- •Роль фреймов в архитектуре "документ/представление"
- •Документ и его представления
- •Документы
- •Класс CDocument
- •Класс CArchive
- •Представления
- •Класс CView
- •Панели элементов управления
- •Класс CStatusBar
- •Класс CStatusBarCtrl
- •Класс CDialogBar
- •ControlBars — пример приложения
- •НЕКОТОРЫЕ КЛАССЫ MFC
- •Класс CObject - основной класс MFC
- •Конструкторы класса
- •Оператор присваивания
- •Диагностика
- •Проверка целостности объектов класса
- •Получение дампа объекта класса
- •Сохранение и восстановление состояния объекта
- •Метод IsSerializable
- •Виртуальный метод Serialize
- •Информация о классе
- •Виртуальный метод GetRuntimeClass
- •Метод IsKindOf
- •Класс CPoint - точка на плоскости
- •Класс CSize - относительные координаты
- •Класс CString - текстовые строки
- •Конструктор класса
- •Коллекции
- •Массивы - шаблон CArray
- •Списки - шаблон CList
- •Словари - шаблон CMap
- •Класс CTime - дата и время
- •Файловая система - класс CFile
- •Открытие и создание файлов
- •Идентификатор открытого файла
- •Закрытие файлов
- •Чтение и запись файлов
- •Метод Flush
- •Операции с файлами
- •Блокировка
- •Позиционирование
- •Характеристики открытого файла
- •Файловая система - классы CMemFile и CStdioFile
- •Модификация класса CMemFile
- •Файловая система - класс CStdioFile
- •Запись и восстановление объектов
- •Запись в архивный файл
- •Чтение из архивного файла
- •Исключения - класс CException
- •Класс CException
- •Класс CMemoryException
- •Класс CFileException
- •Приложение Except
- •Класс CArchiveException
- •Класс CNotSupportedException
- •Класс CResourceException
- •Класс CUserException
Рис. 32. Несколько документов двух типов, используемых одним приложением
Таким образом, если внимательно посмотреть на перечисленные функции и члены класса CWinApp, при работе в рамках архитектуры "документ/представление", роль объекта-приложения заключается в создании, хранении и организации доступа к списку доступных для использования шаблонов документов. Фактически его роль сводится лишь к передаче управления "диспетчеру документов", представленному классом CDocManager, который, собственно, и выполняет всю необходимую для этого работу. Схематично процесс создания шаблона документа изображен на рис. 34.
Роль фреймов в архитектуре "документ/представление"
Фрейм документа, который мы будем здесь рассматривать, имеет две основные составляющие — собственно фрейм и его содержимое, представляющее на экране данные документа. Эти два компонента представлены и управляются различными группами классов библиотеки MFC: классы фреймов (CFrameWndw. CMDIChildWnd) и классы представлений (CView, CScrollView и другие). Процесс создания главного и дочерних фреймов подробно обсуждался в первом томе (см. главы 11, 12) и нет смысла повторяться. Вместо этого рассмотрим несколько фрагментов кода из приложения NoteDraw:
// описание класса (файл Childfrm.h) class CNoteFrame : public CMDIChildWnd {
I/ Для возможности динамического создания объекта // класса CNoteFrame вызывается макрос DECLARE_DYNCREATE(CNoteFrame)
protected:
CNoteFrame();
//реализация класса (файл Childfrm.cpp)
//Для возможности динамического создания объекта // класса CNoteFrame
вызывается макрос IMPLEMENT DYNCREATE(CNoteFrame, CMDIChildWnd)
Интерес здесь представляют два макроса, подробно описанные в главе 8 первого тома - DECLARE_DYNCREATE и IMPLEMENT_DYNCREATE -и защищенный (protected) конструктор по умолчанию. Дело в том, что все вышеперечисленные составляющие архитектуры "документ/представление (документ, фрейм и представление) создаются шаблоном документов динамически, во время выполнения программы. Кроме того, эти макросы охватывают также все возможности двух других групп макросов —
DECLARE_DYNAMIC, IMPLEMENT^ DYNAMIC, DECLARE_SERIAL и IMPLEMENT_ SERIAL, что гарантирует также поддержку получения информации времени выполнения и сериализации. Забыв включить эти макросы соответственно в объявление и реализацию некоторого класса, вы тем самым исключаете для него возможность корректной работы механизмов RUNTIME_CLASS и сериализации.
Рассмотрим функции класса CFrameWnd, которые связаны с архитектурой "документ/представление".
void BOOL CFrameWnd::OnCreateClient(
LPCREATESTRUCT Ipcs, CCreateContext *pContext) -
вызывается только библиотекой классов MFC из обработчика OnCreate и не должнавызыватьсянепосредственно. В качестве параметров в функцию передаются: Ipcs — указатель на структуру CREATESTRUCT и pContext— указатель на структуру CCreateContext:
struct CCreateContext{
CRuntimeClass* m_pNewViewdass; CDocument* m_pCurrentDoc;
CDocTemplate* m_pNewDocTemplate;
CView* m_pLastView;
CFrameWnd* m_pCurrentFrame;
CCreateContext ();
Структура CCreateContext создается шаблоном документа (при создании документа и ассоциированных с ним компонентов). Перечислим поля этой структуры (все поля могут содержать NULL):
m_pNewViewClass |
указатель на структуру CRuntimeClass вновь создаваемого |
представления |
|
m_pCurrentDoc |
указатель на уже существующий документ, с которым ассо- |
циируетсяновоепредставление |
|
m_pNewDocTemplate указатель на шаблон документа, с которым ассоциирован |
|
создаваемыйфрейм |
|
m_pLastView |
указатель на начальное представление, к которому добав- |
ляется создаваемое, например, при работе с разделенным окном или при создании дополнительного представления документа
m_pCurrentFrame указатель на текущий фрейм, к которому добавляется создаваемый, например, при создании дополнительного фрейма документа
Библиотекой MFC эта структура используется в следующих функциях: CWnd::Create, CFrame Wnd::Create View, CFrame Wnd:: Load Frame, CFrameWnd:;OnCreateClient, CFrameWndr.Create, CSplitterWndr.Create и CSplitterWnd::Create View.
virtual void CFrameWnd::ActivateFrame(int nCmdShow = -1) —
активизирует фрейм, т. е. делает его видимым и доступным для пользователя. Параметр nCmdShow принимает такие же значения, как и посылаемые в функцию CWnd::ShowWindow. По умолчанию функция делает фрейм видимым и переводит его на самый верх Z-порядка, и при необходимости то же самое выполняет для главного окна приложения. При переопределении, после проведения необходимых действий, например, разворачивания дочернего окна, необходимо вызвать соответствующую функцию базового класса с явным указанием параметра nCmdShow, как, например, сделано в приложении NoteDraw.
void CNoteFrame::ActivateFrame(int nCmdShow)
{
// Разворачиваем фрейм документа
CMDIChildWnd::ActivateFrame(SW MAXIMIZE);
void CFrameWnd::lnitialUpdateFrame( CDocument *pDoc,
BOOL bMakeVisible) -
вызывается после создания нового фрейма и инициирует вызов обработчика OnlnitialUpdate для всех своих представлений. При этом активизируется представление, у которого идентификатор дочернего окна установлен в AFX_IDW_PANE_FIRST. Если значение параметра bMakeVisible равно TRUE, то фрейм делается видимым; в противном случае — нет. Параметр pDoc определяетдокумент, ассоциированныйсданнымфреймом.
virtual CFrameWnd* CFrameWnd::GetActiveFrame() -
возвращает указатель на активное дочернее окно MDI-приложения. При работе с SDI-приложениями функция возвращает указатель на текущий объект — this.
void CFrameWnd::SetActiveView( CView *pViewNew, BOOL bNotify = TRUE) -
переводит представление pView в активное состояние. Эта функция автоматически вызывается библиотекой MFC, когда пользователь сменил фокус представления внутри фрейма. Ее можно вызвать специально для программной сменыфокусапредставления.
// Установить фокус на область (1, 0) SetActiveView((CView*)m_spltWnd.GetPane(1, 0) )
;
Параметр bNotify определяет, будет ли само представление извещено об активизации. Если его значение равно TRUE, то для активизируемого представления вызывается функция OnActivateView.
CView* CFrameWnd::GetActiveView() -
возвращаетуказательнаобъекттекущегоактивногопредставления. Еслитакого нет, то возвращается NULL.
CWnd* CFrameWnd::CreateView(
CCreateContext *pContext,
UINT nID = AFX_IDW_PANE_FIRST) -
создает представление внутри фрейма, которое не является производным от CView, и возвращает указатель на него. После выполнения функции необходимо самостоятельно установить активность и видимость вновь созданного представления. Параметр pContext определяет тип представления и документа, а пЮ — идентификатор представления.
virtual CDocument* CFrameWnd::GetActiveDocument() —
возвращает указатель на документ, ассоциированный с текущим активным представлением. Если такого нет, что, в принципе, возможно, то функция возвращает значение NULL.
В качестве примера (фрагмент кода из приложения NoteDraw) рассмотрим, как можно переопределить функцию OnCreateClient для создания статического разделенного окна с двумя горизонтальными областями, в каждой из которых создается свое представление1 (рис. 35).
BOOL CNoteFrame::OnCreateClient(LPCREATESTRUCT Ipcs,
CCreateContext* pContext)
//создаем разделенное окно Windows // с двумя строками и одним столбцом
if(!m_spltWnd.CreateStatic(this, 2, 1))
//создаем представление в первой строке (горизонтальная область) if(!m_spltWnd.CreateView(0, 0, pContext->m_pNewViewClass, CSize(lpcs->cx, lpcs->cy*2/3), pContext))
Характер рассмотренных функций достаточно наглядно показывает роль фрейма в архитектуре "документ/представление". Прежде всего, фрейм хранит путь к текущему активному представлению. В случае, когда он содержит более одного представления, например, при работе с разделенным окном, то в качестве активного принимается самое последнее используемое представление.1 Последняя из описанных выше функций показывает, что фрейм имеет также доступ к документу, ассоциированному с текущим активным представлением. Кроме того, фрейм занимается координацией взаимодействия между различными представлениями, ассоциированными с определенным документом, направляя им команды и получая от них извещения. Маршруты, по которым осуществляется обмен сообщениями, подробно описаны нами в главе 10. И последнее. Мы уже говорили, что с каждым документом ассоциируются определенные ресурсы меню и акселераторов. Так вот, задачу разделения этих ресурсов среди документов, созданных на основе одного шаблона, и замены ресурсов при активизации документа другого типа также с успехом решают главный фрейм и фрейм документа.
В заключение коротко перечислим те шаги, которые необходимо проделать для организации работы в рамках архитектуры "документ/представление":
О создать объект-приложение;
Q создать объекты-документы (см. главу 27);
Q создать необходимое число представлений каждого документа (см. главу 27);
Q в функции Initlnstance объекта-приложения создать объекты-шаблоны документов и добавить их к его списку;
Q создать необходимые ресурсы для каждого из них;
Q переопределить функцию CFrameWnd::OnCreateClient, в которой присоединить к фрейму документа необходимые представления;
Q создать и вывести на экран главное окно приложения с присоединенными к нему фреймами документа.Теперь, когда мы разобрались в общей структуре рассматриваемой архитектуры, перейдем к вопросам создания и работы с ее основными составляющими — документами и ассоциированными с ними представлениями.
Документ и его представления
Как мы уже неоднократно отмечали, одним из основных достоинств архитектуры "документ/представление" является то, что в ней данные отделены от их изображения.1 Любые изменения данных осуществляются
посредством специального класса документа, который обеспечивает необходимое пространство для их хранения в памяти, отвечает за запись и чтение документа с диска и предоставляет интерфейс для доступа и обновления данных. За изображение данных на экране, принтере или любом друго^г устройстве отвечает представление, которое использует для этого специальный класс CView, или производный от него. Можно сказать, что объект этого класса представляет собой окно, посредством которого, с одной стороны, осуществляется взаимодействие с пользователем, а с другой — организуется доступ к интерфейсной части документа для возможности обновления данных. В достаточно упрощенном виде сказанное можно проиллюстрировать с помощью рис. 36. Следует также повторить, что один и тот же документ одновременно может иметь несколько различных представлений.
