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

Глава 3. Основные составляющие приложения на базе библиотеки классов MFC

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

Основные составляющие приложения на базе библиотеки классов MFC


Цель этой главы — проанализировать общую структуру программы для face="Courier New" size=2>Windows, написанной с использованием тех
возможностей, которые предоставляет библиотека MFC, и показать тесную
взаимосвязь между классами библиотеки и интерфейсом прикладного программирования
Win32 API.


Начнем с рассмотрения минимального приложения size=2>First, создающего простое окно с заголовком, бордюром и системным
меню.


size=2>/////////////////////////////////////////////////////////



// Файл First.h


// Copyright (c) 2000
Тихомиров Ю.


#ifndef _AFXWIN_H_


#error сначала включаем
'stdafx.h' для поддержки РСН 


#endif


class CFirstApp : public
CWinApp


{


public:


CFirstApp(};


// Переопределяемые
функции 


// {{ AFX_VIRTUAL
(CFirstApp)


public-virtual BOOL
Initlnstancei);


//}}AFX_VIRTUAL


};


size=2>///////////////////////////////////////////////////////



// Файл First.срр


// Copyright (с) 2000
Тихомиров Ю.


#include "stdafx.h"


#include "First.h"


#include "MainFrm.h"


// Может быть создан один и
только один объект CFirstApp


CFirstApp theApp;


CFirstApp::CFirstApp()


{


}


// Инициализация объекта
CFirstApp


 BOOL
CFirstApp::Iriitlnstance()


{


const char *szWndClass =
AfxRegisterWndClass( 


CS_HREDRAW |
CS_HREDRAW, 


size=2>LoadStandardCursor(IDC_ARROW), 


(HBRUSH)COLOR_BACKGROUND +
1,


 
LoadIcon(IDR_MAINFRAKE)); 


CMainFrame *pFrame = new
CMainFrame;


 m_pMainWnd =
pFrame;               
//


pFrame->Create(
szWndClass,          //


"Первая
программа",                 
//


size=2>WS_OVERLAPPEDWINDOW,                
//


CRect(0, 0, 560,
400),              
//


size=2>NULL,                               
//


size=2>NULL,                               
//


size=2>0,                                  
//


size=2>NULL                                
//


);


size=2>m_pMainWnd->CenterWindow();


size=2> m_pMainWnd->ShowVJindow (SW_SHOW) ; 


size=2>m_pMainWnd->UpdateWindow();


return TRUE; 


}


size=2>/////////////////////////////////////////////////////////



// Файл MainFrm.h


// Copyright (c) 2000
Тихомиров Ю.


class CMainFrame : public
CWnd f public:


CMainFrame();


public:


virtual ~ CMainFrar-ie ( )
;


size=2>////////////////////////////////////////////////////////



// Файл MainFrm.cpp


.// Copyright (ci 2000
Тихомиров 1C.


#include "stdafx.h"


#include "First.h"


#include "MainFrm.h"


// Конструктор/деструктор
.класса CMainFrame 


size=2>CMainFrame::CMainFrame()


{


}


CMainFrame : : ~CMai nFrame
()


{


{


size=2>//////////////////////////////////////////////////////



// Файл Stdafx.h


// Copyright (c) 2000
Тихомиров Ю.


// stdafx.h : заголовочный
файл, подключающий стандартные,


 // наиболее часто
используемые заголовочные файлы


#define VC_EXTRALEAN  //
Исключает редко используемые части 


size=2>                     
// заголовочных файлов Windows


#include
<afxwin.h>   // Ядро MFC и стандартные компоненты


size=2>/////////////////////////////////////////////////////////////////



// Файл Stdafx.cpp


// Copyright (с) 2000
Тихомиров Ю.


// Stdafx.cpp : исходный
файл, который подключает только


size=2>               
стандартные включаемые файлы


// First.pch :  файл
прекомпилированных заголовков


// stdaix.obj : файл,
содержащий перекомпилированные типы информации


# include "stdafx.h"


size=2>//////////////////////////////////////////////////////////



// Файл First.re


// Copyright (с? 2000
Тихомиров Ю.


....


size=2>////////////////////////////////////////////////// face="Courier New" color=#800000 size=2>//////



// Пиктограмма


size=2>IDP_MAINFRAME       
ICON     DISCARDABLE   "res\First.ico"



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

Рис. 3.1. Главное окно программы size=2>First


Программа First строит обычное,
традиционное окно, хорошо знакомое всем пользователям системы face="Courier New" size=2>Windows (рис. 3.1). Окно можно перемещать по
экрану, закрывать, свертывать (уменьшать до размера пиктограммы) или раскрывать
(увеличивать до размеров экрана), а также изменять его размер. Основное, можно
даже сказать единственное, назначение этого примера состоит в том, что он
позволяет нам познакомиться с принципами построения программ на базе библиотеки
классов MFC.


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


Первое, на что следует обратить внимание — это наличие объекта face="Courier New" size=2>CFirstApp, являющегося объектом-приложением
Windows. Основной задачей класса, из
которого он образован — CWinApp, является
создание процесса в системе. Если вспомнить, что процесс — каждый выполняемый
экземпляр приложения (в более ранних версиях size=2>Windows применялся термин "задача"), то становится понятным, что в
приложении может быть определен только один объект класса face="Courier New" size=2>CWinApp. Основными задачами, возложенными на
этот класс, являются создание и инициализация главного окна (напоминаю, что
Windows — "оконная" система) и опрос
системных сообщений. Итак, еще раз: каждое приложение, которое использует
библиотеку MFC, может содержать только
один объект "приложение", который конструируется вместе с другими глобальными
объектами C++ (определение — size=2>CFirstApp theApp) и уже
доступен, когда Windows вызывает функцию
WinMain. На данном этапе знакомства это
самый существенный момент для успешного программирования под face="Courier New" size=2>Windows на базе MFC, и если вы его усвоили, то
можно переходить непосредственно к функции size=2>WinMain. которая является "точкой входа" в любую написанную под
Windows программу (точно так же, как
функция main является "точкой входа" в программу, написанную на языке С).



Функция WinMain


Так где же эта обязательная функция? Пусть вас не удивляет, что в
представленном листинге вы не найдете даже упоминания о ней. Дело в том, что
создатели библиотеки MFC проделали
большую работу и избавили вас от написания многих строк вспомогательного кода,
предоставив возможность заниматься только решением конкретной задачи. Однако это
имеет и оборотную сторону — библиотека скрывает от программиста и часть того,
что заставляет Windows работать. По этой
причине мы будем углубляться в Windows
немного больше, чем может показаться необходимым. Мы уверены, что приобретенное
понимание позволит вам с большей легкостью использовать возможности библиотек
MFC и size=2>SDK. Сказанное в полной мере относится к функции face="Courier New" size=2>WinMain. Что же предлагают нам разработчики
MFC в плане ее реализации?


 Примечание 


На самом деле функция size=2>WinMain операционной системой не вызывается. Вместо этого
происходит обращение к стартовой функции из стандартной (runtime) библиотеки
C/C++. Компоновщик Visual C++ знает, что
она имеет имя _WinMainCRTStartup и отвечает за выполнение таких операций,
как:



  •  поиск указателя на полную командную строку
    нового процесса;

  •  поиск указателя на переменные окружения нового
    процесса;

  •  инициализация глобальных переменных из
    стандартной библиотеки (runtime library) языка С, доступ к которым
    обеспечивается включением файла <stdlib.h>;

  •  инициализация блока памяти (heap), используемого
    функциями выделения

  • памяти и процедурами низкоуровневого ввода/вывода
    языка С; 

  •  вызов функции WinMain библиотеки MFC.

Давайте вместе подробно рассмотрим фрагмент исходного текста из библиотеки.



int AFXAPI WinMain(


HINSTANCE hlnstance,


HINSTANCE
hPrevInstance,


LPTSTR IpCmdLine,


int nCindShow) {


int nReturnCode = -1;


CWinApp* pApp =
AfxGetApp();



// Внутренняя
инициализация


if (!AfxWinInit(hlnstance,
nFrevInstance,


IpCmdLine, nCmdShow)) goto
InitFailure;



// Глобальная инициализация
приложения


 if
(!pApp-XInitApplication())


 goto
InitFailure;


// Специфическая
инициализация экземпляра приложения


 if
(!pApp->Init!nstance()) 


{


// В случае неудачи
необходимо корректно завершить приложение ...


 if
(pApp->m_pMainW:id != NULL) 


{


// удалив главное окно, если
оно все же было создано


 TRACED ("Warning:
Destroying non-NULL m_MainWndn") ;
pApp->m_pMainWnd->DestroyWindow();


}


nReturnCode =
pApp->Exit!nstancei};


 goto
InitFailure;


 }


// Если все в порядке -
запускаем цикл обработки сообщений


 nReturnCode =
pApp->Run(); 


InitFailure: 


AfxWinTerm() ;


 return
nReturnCode; 


}


Для лучшего понимания задач, решаемых WinMain, рассмотрим структуру этой
функции, упрошенное условное изображение которой представлено на рис. 3.2.



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

Рис. 3.2. Упрощенная структура функции size=2>WinMain


Все представленные здесь функции определены в классе size=2>CWlnApp — базовом для объекта "приложение", и должны быть
переопределены в нашем производном от него классе. Место класса face="Courier New" size=2>CWinApp в иерархии объектов библиотеки face="Courier New" size=2>MFC показано на рис. 3.3.


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



CWinApp::CWinApp
(LPCTSTR IpszAppKame = NULL)


Параметр IpszAppName— указатель на
текстовую строку, которая содержит имя приложения, используемое системой face="Courier New" size=2>Windows. Если этот аргумент отсутствует или
равен NULL (по умолчанию), то для
формирования имени приложения конструктор использует строку из файла ресурсов с
идентификатором AFX_IDS_ face="Courier New" size=2>APP_TITLE (в ней вы можете указать имя главного
окна вашего приложения), а при ее отсутствии — имя исполняемого файла. Этот
параметр конструктор запоминает в компоненте класса size=2>m_pszAppName.



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

Рис. 3.3. Место класса CWinApp
в иерархии


Следующую важную группу составляют переопределяемые (виртуальные) функции. В
документации на MFC обращается внимание на следующие функции этой группы: face="Courier New" size=2>Initlnstance, size=2>Run, Exit Instance и Onldle.



virtual BOOL
CWinApp::Initlnstance()


Отвечает за инициализацию каждого нового
экземпляра приложения.


Если посмотреть поставляемые исходные тексты, то можно увидеть, что в своем
первозданном виде эта функция не делает ничего:



BOOL CWi лАрр:
:Initlnstance()


{


 return TRUE;


}


и наполнение ее содержанием целиком является задачей программиста. Обычно это
то место, где конструируется объект "главное окно" приложения, загружаются
стандартные настройки из INI-файла или из реестра Windows, обрабатывается
командная строка текущего экземпляра приложения, создается новый или открывается
существующий документ, регистрируются шаблоны документов, создаются сами
документы, их представления (view) и
ассоциированные с ними окна (этот процесс будет подробно рассмотрен в одной из
следующих глав). После создания главного окна переменная face="Courier New" size=2>CVinThread::m_pMainWnd устанавливается равной
значению указателя на это окно. Это единственная функция face="Courier New" size=2>CWinApp, которую вы должны обязательно
переопределить для того, чтобы ваше приложение что-нибудь делало. Если вы
вернетесь к тексту нашего приложения, то увидите, что именно это мы и сделали.


Следующие две функции не требуют обязательного переопределения, но
представление о них необходимо иметь.



virtual BOOL
CWinApp::ExitInstance ()


Вызывается только из функции Run для
завершения работы текущего экземпляра приложения. Реализованная версия этой
функции записывает сохраняемые настройки в INI-файл приложения. Если есть
необходимость в проведении специальной обработки при завершении приложения —
такой, как возврат памяти, распределенной во время работы, очистка контекста
устройства или других ресурсов, то следует переопределить эту функцию.
Освобождение стандартных элементов, например, документов и их представлений
(view), производится стандартными средствами библиотеки классов MFC и не
должно беспокоить разработчиков программного обеспечения.


virtual int
CWinApp::Run ()


Запускает цикл обработки сообщений, в
котором получаются и распределяются . сообщения Windows до тех пор, пока не
поступит сообщение WM_QUIT, инициирующее завершение работы приложения. Все
поступающие сообщения направляются в функцию PreTranslateMessage и затем в
стандартную функцию Windows Translate/Message для поддержки работы с
клавиатурой. В заключение вызывается функция Windows DispatchMessage. Если
очередь сообщений пуста, то Run вызывает виртуальную функцию Onldle для
выполнения фоновой обработки. Эта функция не требует переопределения, хотя и
допускает его.


Теперь, после некоторого знакомства с классом CWinApp, можно вернуться к
нашей первой программе.



Минимальная программа для Windows


Напомним еще раз основные этапы создания и работы нашей первой программы.


1. Создается единственный глобальный объект класса приложения face="Courier New" size=2>CFirstApp size=2>theApp. Программа First
использует класс CWinApp как базовый для
собственного класса CFirstApp, который
имеет две функции — конструктор и функцию, необходимую для создания главного
окна приложения и переопределяющую аналогичную функцию родительского класса:



class CFirstApp : public
CWinApp


{


public:


CFirstApp () ;


 //
Переопределяемые


 // ClassWizard
описывает здесь виртуальные функции


size=2>//{{AFX_VIRTUAL(CFirstApp)


public:


virtual BOOL
Initlnstance();


//}}AFX_VIRTUAL


 } ;


2. После создания объекта theApp
операционная система вызывает функцию size=2>WinMain — точку входа в программу, написанную под face="Courier New" size=2>Windows. Реализация этой функции в библиотеке
MFC выполняет следующие действия:


• определяет указатель на объект "приложение", вызывая для этого глобальную
функцию AfxGetApp



CWinApp* pApp =
AfxGetApp();


• вызывает функцию, отвечающую за инициализацию первого экземпляра приложения



size=2>pApp->InitApplication();


• вызывает функцию, отвечающую за мниииатизацию текущего экземпляра
приложения



pApp->Init!nstance
();


• запускает цикл обработки сообщений



 pApp->Run();


• завершает функцию Win Main, а
значит, и работу приложения.


При всей своей лаконичности функция Win Main имеет все составляющие,
необходимые для выполнения программы под Windows. Из этих составляющих
наибольший интерес представляют инициализация текущего экземпляра и цикл
обработки сообщений, поэтому рассмотрим их подробнее. Любая программа,
написанная на базе библиотеки классов MFC, переопределяет функцию Initlnstance.
В примере First это выглядит так:



BOOL
CFirstApp::Initlnstance() 


{


const char *szWndClass --
AfxRegisterWndClass(


CS_HREDRAW I
CS_HREDRAW,


size=2>LoadStandardCursor(IDC_ARROW), 


(HBRUSH)COLOR_BACKGROUND +
1,


size=2>Loadlcon(IDR_MAINFRAME);;


 CMainWnd *pWnd = new
CMainWnd; 


pWnd->CreateEx(


size=2>0,                             
// дополнительные стили


size=2>szWndClass,                    
// класс окна


"Первая
программа",            
// заголовок


size=2>WS_OVERLAPPEDWINDOW,           
// стиль


CW_USEDEFAULT,
CW_USEDEFAULT,   // левый верхний угол (х, у)


CW_USEDEFAULT,
CW_USEDEFAULT,   // размерь; {сх, су)


size=2>NULL,                          
// родительское окно


NULL)
;                        
// идентификатор меню


size=2>pWnd->ShowWindow(m_nCmdShow);


 m_pMainWnd =
pWnd;


 return TRUE;


 }


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



const char *szWndClass =
AfxRegisterWndClass(


C3_HREDRAW i CS_
HREDRAW,


 LoadStandardCursor(
IDC_ARROW),


 (HBRUSH)COLOR
BACKGROUND +1 ,


 LoadIcon (IDR_
MAINFPAME)) ;


а затем создать экземпляр одного из оконных классов size=2>MFC:



CMainWnd *pWnd = new
CMatnWnd;


 и создать собственно окно:



size=2>pWnd->НекотораяФункцкяСозданияОкна(...);


После того как объект окна MFC и само
окно созданы, указатель на этот объект присваивается переменной face="Courier New" size=2>CWinThread::m pMainWnd (такое присвоение
необходимо для того, чтобы иметь возможность корректно завершить приложение,
когда будет закрыто его главное окно):



m_pMainWnd = pWnd;


Можно создавать окно Windows и
выводить его на экран



size=2>m_pMainWnd->ShowWindow(m_nCmdShow);


По завершении инициализации основная работа объекта "приложение" состоит в
том, чтобы обеспечить передачу сообщений между пользователем и оконным объектом.


К этим вопросам мы еще вернемся, а пока нам надо рассмотреть процесс создания
собственно окна.



Создание окна


Каждая программа на базе MFC, которую
вы создаете, будет содержать по крайней мере один класс, определяющий оконный
объект. Приложение First определяет свой
класс CMainFrame, базирующийся на одном ш
предопределенных классов, а именно на size=2>CFrameWnd, и полностью использует тот прочный фундамент, который
заложила библиотека MFC. не добавляя
ничего своего:



class CMainFrame : publiс
CFrameWnd


{


public:


CMainFrame 0 ;


virtual
~CMainFrame(); 


};


В действительности все еще проще: этот класс можно было вообще не определять,
поскольку обе его функции пустые. Я включил его только для наглядности. Всю
работу выполняет базовый класс нашего окна CFnimeWnd. Еще раз повторим — окно
создается в два-три шага: сначала определяется оконный класс (этот шаг в
большинстве случаев необязателен), затем создается объект "окно", и, наконец,
окно делается видимым.


Теперь о создании собственно окна size=2>Windows. Мы использовали для этой цели функцию



CWnd::CreateEx(


0,


size=2>szWndClass,                    
// класс окна


"Первая
программа",            
// Заголовок


size=2>WS_OVERLAPPEDWINDOW,           
// стиль


CW_USEDEFAULT,
CW_USEDEFAULT,   // левый верхний угол (x,у)


CW_USEDEFAULT,
CW_USEDEFAULT,   // paзмеры (сх, су)


size=2>NULL,                          
// родительское окно.


size=2>NULL);                         
// идентификатор меню


В дополнение к CreateEx класс face="Courier New" size=2>CWnd имеет вторую функцию для создания окон —
Create. Эти функции практически идентичны
и имеют два отличия: во-первых, функция size=2>Create позволяет создавать лишь дочерние окна, в то время как
CreateEx— также перекрывающиеся и
вспомогательные, и, во-вторых, CreateEx содержит один дополнительный параметр
(Ex. означает size=2>Extended, т. е. расширенный). Поскольку нам надо было создать
главное окно программы, которое не может быть дочерним, мы воспользовались
функцией CreateEx.


После возврата из CreateEx система
Windows создает у себя всю внутреннюю
информацию, необходимую для сопровождения окна. т. е. вносит запись в базу,
содержащую информацию об окнах Но в большинстве случаев окно на экране еще не
появляется — требуется вызвать функцию Show
Window
, которая также принадлежит классу CWnd:



m_pMainWnd->ShowWindow
(m_nCnidShow)


В зависимости от значения mjiCmdShow программа может при вызове иметь
свернутое, обычное или. развернутое окно. Вызовом Show-Window завершается
инициализация оконного объекта.


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


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

16.02.2006

Телефон

+7 8636 237-836

Поиск

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

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