Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Visual C++ 6. Руководство Разработчика [rus]

.pdf
Скачиваний:
303
Добавлен:
16.08.2013
Размер:
4.96 Mб
Скачать

public: CMainWnd() (

Create(NULL, "Hello MFC World", WSJDVERLAPPEDWINDOW, rectDefault, NULL, NULL), ) };

BOOL CTheApp: : Initlnstance 0

{

m_pMainWnd = new CMainWnd (); m_pMainWnd->ShowWindow (m_nCmdShow) ; m_pMainWnd->UpdateWindow() ;

return TRUE; } CTheApp TheApp;

В следующих параграфах мы детально рассмотрим назначение каждого блока программы.

Файл AFXWIN.H

Файл AFXWIN.Hвыполняет роль шлюза в библиотеку MFC . Через него подключаются все остальные файлы заголовков, включая WINDOWS. H. Использование файла AFXWIN.H упрощает создание предварительно скомпилированных файлов заголовков. Предварительная компиляция частей программы позволяет сократить время, затрачиваемое на повторное построение приложения.

Создание класса, производного от CWinApp

Приложение начинается с определения класса CTheApp, являющегося производным от

CWinApp:

class CTheApp : public CWinApp

{

public:

virtual BOOL Initlnstance () ; };

Виртуальный метод Initlnstance() наследуется от CWinApp. Переопределяя этот метод, программист получает возможность управлять инициализацией приложения. В классе CWinAppимеются также открытые виртуальные функции Exitlnstance(),Run()и другие, но в большинстве приложений нет необходимости переопределять их.

Ниже приведено описание класса CWinApp, взятое из файла AFXWIN.H.

///////////////

//CWinAppбазовый класс для всех приложений Windows class CWinApp : public CWinThread {

DECLARE_DYNAMIC (CWinApp) public:

//Конструктор

CWinApp(LPCTSTR IpszAppName =• NULL);// имя приложения

//задается по умолчанию

//Атрибуты

//параметры запуска (не изменять) HINSTANCE m_hlnstance;

HINSTANCE m_hPrev!nstance; LPTSTR m_lpCmdLine;

int m_nCmdShow;

//параметры выполнения (могут меняться в Initlnstance)

LPCTSTR m_pszAppName;

//

читаемое имя

приложения

LPCTSTR m_pszRegistryKey; //

используется

для регистрации

CDocManager* m_pDocManager;

 

 

public:

// устанавливаются

в конструкторе

LPCTSTRm_pszExeName;

// имя исполняемого файла (без пробелов)

LPCTSTRm_pszHelpFilePath; //

определяется

на основании пути к модулю

321

LPCTSTRm_pszProfileName; // определяется на основании имени приложения

// Операции инициализации - должны выполняться в

Initlnstanceprotected:

void LoadStdProfileSettings(UINT nMaxMRU = _AFX_MRU_COUNT); void EnableShellOpen ();

void SetDialogBkColor(COLORREF clrCtlBk = RGB(192,192,192),

COLORREFclrCtlText= RGB(0, 0, 0)); // установка фонового цвета диалогового окна и окна сообщений

void SetRegistryKey(LPCTSTR IpszRegistryKey); void SetRegistryKey(UINT nIDRegistryKey);

//позволяет хранить данные о приложении в реестре, а не в INI-файле

//(в качестве ключа обычно используется название компании) BOOLEnable3dControls(); //для 3-мерных элементов управления

//используется файл CTL3D32.DLLtifndef _AFXDLL

BOOLEnableSdControlsStatic(); // для тех же целей статически компонуется

// файлCTL3D.LIB fendif

void RegisterShellFileTypes(BOOL bCompat=FALSE);

// вызывается после того, как будут зарегистрированы все шаблоны // документа .

void RegisterShellFileTypesCompat();

//требуется для совместимости с предыдущими версиями void UnregisterShellFileTypes();

//Вспомогательные операции - обычно выполняются в Initlnstance public:

//Указатели мыши

HCURSOR LoadCursor(LPCTSTR IpszResourceName) const; HCURSOR LoadCursor(UINT nIDResource) const;

HCDRSOR LoadStandardCursor(LPCTSTR IpszCursorName) const; HCURSOR LoadOEMCursor(UINT nIDCursor) const;

// Значки

HICON Loadlcon(LPCTSTR IpszResourceName) const; HICON Loadlcon(UINT nIDResource) const;

HICON LoadStandardlcon(LPCTSTR IpszIconName) const; HICON LoadOEMIcon(UINT nIDIcon) const;

// могут переопределяться virtual BOOL Initlnstance();

virtualintExitlnstanceO; // возвращает код завершения приложения virtual int Run();

virtual BOOL OnIdle(LONG ICount);

virtual LRESULT ProcessWndProcException(CException* e,const MSG* pMsg);

public:

virtual CWinApp(); protected:

// { {AFX_MSG (CWinApp) afx_msg void OnAppExitO;

afx_msg void OnUpdateRecentFileMenu (CCmdUI* pCmdUI) ; af x_msg BOOL OnOpenRecentFile (UINT nID) ; //}}afx_msg declare_message_map ( ) };

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

322

Класс CFrameWnd

Окно приложения, выводимое на экран и управляемое классом CMainWnd, создается на базе класса CFrameWnd:

class CMainWnd : public CFrameWnd

{

public: CMainWnd () (

Create (NULL, "Hello MFC World", WS_OVERLAPPEDWINDOW, rectDefault, NULL, NULL);

}

};

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

Ниже представлено описание класса CFrameWnd, взятое из файла AFXWIN.H.

////////////

//CFrameWndбазовый класс для масштабируемых окон class CFrameWnd : public CWnd

{

DECLARE_DYNCREATE(CFrameWnd)

//Конструкторы

public:

static AFX_DATA const CRect rectDefault; CFrameWnd();

BOOL LoadAccelTable(LPCTSTR IpszResourceName); BOOL Create(LPCTSTR IpszClassName,

LPCTSTR IpszWindowName,

DWORD dwStyle = WS_OVERLAPPEDWINDOW, const RECT& rect = rectDefault,

CWnd* pParentWnd = NULL, // != NULL для всплывающих окон LPCTSTR IpszMenuName = NULL,

DWORD dwExStyle =0, CCreateContext* pContext = NULL);

//динамическое создание - загружает рамку и связанные с окном ресурсы virtualBOOLLoadFrame(HINTnIDResource,

DWORD dwDefaultStyle = WS_OVERLAPPEDWINDOW I FWS_ADDTOTITLE,

CWnd* pParentWnd = NULL, CCreateContext* pContext = NULL);

//специальная функция для создания области просмотра

CWnd*. CreateView(CCreateContext* pContext, UINT nID = AFX IDW PANE FIRST);

// прикрепление панелей инструментов void EnableDocking(DWORD dwDockStyle);

void DockControlBar(CControlBar* pBar, UINT nDockBarlD = 0, LPCRECT IpRect = NULL);

void FloatcontrolBar(CControlBar* pBar, CPoint point, DWORD dwStyle = CBRS_ALIGN_TOP); CControlBar* GetControlBar(UINT nID);

// Реализация

public:

 

 

virtual

-CFrameWnd

();

intm_nWindow;

// номер окна — отображается как ":n"

323

HMENUm_hMenuDefault;

//

ресурс меню

HACCELm_hAccelTable;

//

таблица горячих клавиш

DWORD m_dwPromptContext;

BOOLm_bHelpMode;// если TRUE, активен режим вызова справки

// по[Shift+Fl]

CFrameWnd* m_pNextFrameWnd; // следующее окно в списке приложения

CRect m_rectBorder; COleFrameHook* m_pNotifyHook;

CPtrList m_listControlBars; // массив панелей инструментов,

//связанных с данным окном intm_nShowDelay;

//обработчики оконных сообщений

afx_msg int OnCreate(LPCREATESTRUCT IpCreateStruct); afx_msg void.OnDestroy();

afx_msg void OnClose();

afx_msg void OnlnitMenu(CMenu*);

afx_msg void OnlnitMenuPopup(CMenu*, UINT, BOOL); afx_msg void OnMenuSelect(OINT nltemlD, UINT nFlags, HMENU hSysMenu);

afx_msg LRESULT OnPopMessageString(WPARAM wParam, LPARAM IParam) ; afx_msg LRESULT OnSetMessageString(WPARAM wParam, LPARAM IParam), protected:

afx_msg LRESULT OnDDEInitiate(WPARAM wParam, LPARAM IParam); afx_msg LRESULT OnDDEExecute(WPARAM wParam, LPARAM IParam); afx_msg LRESULT OnDDETerminate(WPARAM wParam, LPARAM IParam);

afx_msg LRESULT OnRegisteredMouseWheel(WPARAM wParam, LPARAM IParam); DECLARE_MESSAGE_MAP ()

friend class CWinApp; );

Первый параметр метода Create() позволяет задать имя класса окна в соответствии с синтаксисом стандартной API-функции RegisterClass(). Обычно этот параметр не используется и равен null.

Реализация метода InitInstance( )

В классе CTheAppпереопределяется метод initlnstance() базового класса

CWinApp:

BOOL CTheApp::Initlnstance()

{

m_pMainWnd=new CMainWndO; m_j>MainWnd->ShowWindow (m_nCmdShow) ; m_pMainWnd->UpdateWindow(); returnTRUE; }

Оператор new вызывает конструктор CMainWnd (), рассмотренный в предыдущем параграфе. Переменная-член m_pMainWnd(префикс га_ указывает на переменную-члена класса) определяет положение окна на экране. Функция ShowWindow() выводит окно на экран. Параметр m_nCmdShow инициализируется конструктором класса CWinApp и определяет параметры отображения окна. Функция Updatewindow() перерисовывает содержимое окна.

Конструктор

В последнем блоке программы вызывается конструктор класса CWinApp:

CTheAppTheApp;

Запуск программы

Рассмотренная нами программа очень проста. Приложение просто отображает свое окно, ничего не выводя в нем (рис. 18.1).

324

Рис. 18.1. Окно простейшей MFC -программы

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

325

Глава 19. Создание MFC -приложений

Шаблон MFC -приложения o Файл MFC SWP.H

o Файл MFC SWP.CPP o Запуск программы

Рисование графических примитивов в рабочей области окна o Файл GDI.CPP

o Запуск программы

Построение ряда Фурье

o Файл FOURIER.H

o Файлы ресурсов

o Файл FOURIER.CPP

oЗапуск программы

Построение гистограмм

oФайл BARCHART.H

o Файлы ресурсов

o Файл BARCHART.CPP

o Запуск программы

Ранее, в главах 16 и 17, нами были рассмотрены ресурсы Windows, такие как меню, диалоговые окна, горячие клавиши. В предыдущей главе речь шла об основных принципах применения библиотеки MFC при создании приложений Windows. В настоящей главе мы попытаемся, воспользовавшись полученными знаниями о ресурсах и MFC , создать несколько полноценных 32-разрядных приложений.

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

Шаблон MFC -приложения

В предыдущей главе вы познакомились с простейшей MFC -программой, которая отображала на экране свое окно. Ее код можно рассматривать как основу для любого другого приложения Windows, выводящего в окно текст или графику.

Первое из рассматриваемых в этой главе приложений, которое называется MFC SWP (MFC SimpleWindowsProgram), просто выводит строку текста в рабочую область окна. Прежде чем приступать к его изучению, обратимся к листингу программы. Собственно говоря, ниже показано два листинга: файл заголовков и программный файл.

Вспомните, что в предыдущей главе содержимое файла заголовков было включено в программный файл. Здесь в файле заголовков приводится информация о том, как классы приложения порождаются от базовых классов библиотеки MFC . Такой стиль рекомендован разработчиками Microsoft. Вот текст файла MFC SWP.H:

326

class CMainWnd : public CFrameWnd

{

public:

CMainWndO;

afx_rasg void OnPaintО; DECLARE MESSAGE MAP() ; };

class CmfcswpApp : public CWinApp

{

public:

BOOL Initlnstance(); } ;

Ниже показан текст файла MFC SWP.CPP:

//

//mfcswp.cpp

//Эту программу можно использовать как шаблон

//для разработки других MFC -приложений.

//

#include <afxwin.h> #include "mfcswp.h" CmfcswpApp theApp; CMainWnd::CMainWnd() {

Create(NULL, "A MFC Windows Application", WS_OVERLAPPEDWINDOW, rectDefault, NULL, NULL); } void CMainWnd: :OnPaint () {

CPaintDC dc(this);

dc.TextOut(200, 200, "Using the MFC Library", 21); } BEGIN_MESSAGE_MAP(CMainWnd, CFrameWnd) ON_WM_PAINT() END_MESSAGE_MAP ()

BOOL CmfcswpApp::Initlnstance() { m_pMainWnd = new CMainWndO; m_pMainWnd->ShowWindow(m_nCmdShow); m_pMainWnd->UpdateWindow() ; return TRUE;

Файл MFC SWP.H

В MFC -приложениях обычно используются файлы заголовков двух типов. Файлы первого типа, наподобие рассматриваемых в этом параграфе, описывают порождение классов приложений от базовых классов MFC . Их имена совпадают с именами приложений и имеют расширение Н. Файлы второго типа содержат идентификаторы элементов меню и диалоговых окон, а также описания различных констант. Для распознавания файлов этого типа мы будем в их именах добавлять букву R, что означает "resource" (ресурс). Такие файлы встретятся нам в этой главе в двух последних примерах программ.

Итак, в нашем файле заголовков содержится описание двух классов: CMainWnd, порождаемого от CWinApp, и CmfcswpApp, потомка CFrameWnd.

class CMainWnd : public CFrameWnd public:

CMainWnd () ;

afx_msg void OnPaint(); DECLARE_MESSAGE_MAP () ; );

class CmfcswpApp : public CWinApp public:

BOOL Initlnstance();

}

327

Класс CMainWndсодержит метод OnPaint() и макрос, связанный с обработкой сообщений. В случае обработчиков сообщений, например OnPaint(), вместо ключевого слова virtual используется afx_msg. Наличие метода OnPaint() позволяет изменять содержимое рабочей области окна приложения. Эта функция автоматически вызывается каждый раз, когда объекту CMainWndпередается сообщение WM_PAINT.

Макрос declare_message_mapприменяется практически во всех MFC -приложениях и сигнализирует о том, что в классе организуется собственная схема обработки сообщений. Разработчики Microsoftрекомендуют использовать схемы сообщений, а не просто вызовы виртуальных функций, так как благодаря этому удается значительно сократить размер программного кода.

Файл MFC SWP.CPP

В основу нашего приложения положен код рассматривавшейся в главе 17 программы SIMPLE.CPP, однако между этими кодами имеется несколько существенных отличий. Они касаются, в частности, метода OnPaint(). Проанализируем показанный ниже фрагмент программы.

void CMainWnd::OnPaint()

{

CPaintDC do(this);

dc.TextOut(200,200, "Using the MFC Library", 21);

}

Сначала создается контекст устройства, в рамках которого может вызываться любая GDIфункция. Когда метод OnPaint() завершает свою работу, автоматически вызывается деструктор класса CPaintDC.

В данном приложении используется предельно короткая схема сообщений:

BEGIN_MESSAGE_MAP(CMainWnd,CFrameWnd)

ON_WM_PAINT;()

END_MESSAGE_MAP() . . ...

В параметрах макроса begin_message_map указаны два класса: CMainWndиCFrameWnd.

Первому адресуются сообщения, а второй содержит стандартные обработчики, которые вызываются по умолчанию. Макрос on_wm_paint() управляет обработкой всех сообщений wm_paint и переадресовывает их только что рассмотренной функции OnPaint{). Макрос end_message_map завершает схему сообщений.

Существенное преимущество любой схемы сообщений состоит в том, что с ее помощью удается избежать использования тяжеловесных и чреватых ошибками конструкций с характерными для процедурных приложений операторами switch/case.

Запуск программы

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

328

Рис. 19.1. Вывод текста в рабочую область окна

Если вы хотите поэкспериментировать с различными графическими примитивами, удалите из программы функцию TextOut() и вставьте вместо нее функцию Rectangle (), Ellipse () или, скажем, LineTo(). В следующем примере о применении этих функций мы поговорим более подробно.

Рисование графических примитивов в рабочей области окна

Вторая программа рисует в рабочей области окна различные графические фигуры. О том, как это происходит, речь шла в главе 17. Данное приложение также будет представлено двумя файлами: файлом заголовков GDI.H и программным файлом GDI.CPP. Файл заголовков, по сути, не отличается от используемого в предыдущем примере.

class CMainWnd : public CFrameWnd

{

public: CMainWnd ();

afx_msg void OnPaintO; DECLARE_MESSAGE_MAP() ; );

class CgdiAApp : public CWinApp { public: BOOLInitlnstance();

}

Теперь приведем текст программного файла:

//

//gdi.cpp

//Расширенный вариант приложения mfcswp.cpp,

//ориентированный на создание графических примитивов.

#include <afxwin.h> #include "gdi.h" CgdiAApp theApp; CMainWnd::CMainWnd() {

Create(NULL, "Experimenting With GDI Primitives", WSJDVERLAPPEDWINDOW, rectDefault, NULL, NULL); >> void CMainWnd::OnPaint() {

static DWORD

dwColor[9]

= {RGB(0, 0, 0),

// черный

RGB(255,0, 0),

// красный

 

RGB (0,255.,

0),

//

зеленый

 

329

RGB(0,0, 255),

// синий

RGB(255,255, 0),

// желтый

RGB(255,0, 255),

// пурпурный

RGB(0,255,255),

// голубой

RGB(127,127, 127),

// серый

RGB(255,255, 255)};// белый

short

xcoord;

 

POINT

polylpts[4],polygpts[5] ;

CBrush

newbrush;

 

CBrush*

oldbrush;

 

CPen newpen;

CPen*oldpen;

CPaintDC dc(this);

//рисование толстой черной диагональной линии newpen.CreatePen(PS_SOLID, 6, dwColor[0]); oldpen = dc.Selectobject(Snewpen); dc.MoveTo(0, 0) ;

dc.LineTo(640,430); dc.TextOut(70,20,"<-diagonal line",15);

//удаление пера

dc.Selectobject(oldpen); newpen.DeleteObj ect() ;

//рисование синей дуги newpen.CreatePen(PS_DASH, 1, dwColor[3]); oldpen = dc.Selectobject(Snewpen) ; dc.ArcdOO,100, 200, 200, 15X), 175, 175,150), dc.TextOut (80,180, "small -arc->", 11);

//удаление пера

dc.SelectObjecb(oldpen);

newpen.DeleteObject();

// рисование зеленого сегмента с толстым контуром newpen.CreatePen(PS_SOLID, 8, dwColor[2]);

oldpen = dc.Selectobject(Snewpen); dc.Chord(550, 20,630,80, 555, 25,625,70); dc.TextOut(485,30,"chord->", 7) ;

//удаление пера dc.Selectobject(oldpen); newpen.DeleteObject() ;

//рисование эллипса и заливка его краснымцветом newpen.CreatePen(PS_SOLID, 1, dwColor[1]); oldpen = dc.Selectobject(Snewpen); newbrush.CreateSolidBrush(dwColor[1]);

oldbrush = dc.Selectobject(Snewbrush) ; dc.Ellipse(180, 180, 285, 260);

dc.TextOut(210,215, "ellipse",7); // удаление кисти dc.SelectObject(oldbrush) ; newbrush.DeleteObject(); // удаление пера dc.SelectObject(oldpen) ; newpen.DeleteObj ect{);

//рисование круга и заливка его синим цветом

newpen.CreatePen(PS_SOLID, I, dwColor[3]); oldpen = dc.SelectObject(Snewpen); newbrush.CreatesolidBrush(dwColor[3]) ; oldbrush = dc.SelectObject(Snewbrush); dc.Ellipse(380,180, 570, 370); dc.TextOut(450,265,"circle",6);

330