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

Паппас К., Мюррей У. - Visual C++ 6. Руководство разработчика - 2000

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

CDialog::DoDataExchange(pDX); //{(AFX_DATA_MAP(CAboutDlg) / / } } AFX_DATA_MAP (

BEGIN_MESSAGE_MAP (CAboutDlg, CDialog)

//( {AFX_MSG_MAP (CAboutDlg)

//Обработчики сообщений отсутствуют

//}}AFX_MSG_MAPEND_MESSAGE_MAP( )

//Функция, управляющая выводом окна About void CEditorApp : : OnAppAbout ( )

{

CAboutDlg aboutDlg; aboutDlg . DoModal ( ) ;

}

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

//Другие функции класса CEditorApp

Первая схема сообщений принадлежит классу CEditorApp. В ней сообщения с идентификаторами id_app_about, id_file_new, id_file_openи id_file_ PRINT_SETUPсвязываются соответственно с обработчиками OnAppAbout( ) , CWin-Арр: :OnFileNew() , CWinApp: :OnFileOpen() И CWinApp: :OnFilePrintSetup() . В этом файле реализуются конструктор класса CEditorApp, а также его методы Initlnstance() И OnAppAbout().

Единственное изменение, внесенное нами в сгенерированный текст программы, — это переустановка цвета фона и цвета текста всех диалоговых окон, создаваемых программой.

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

//Регистрация шаблонов документов

CMultiDocTemplate* pDocTemplate; pDocTemplate = new CMultiDocTemplate ( IDR_EDITORTYPE,

RUNTIME_CLASS (CEditorDoc) ,

RUNTIME_CLASS (CChildFrame) , // пользовательское

//дочернее MDI-окно

RUNTIME_CLASS (CEditorView) ) ; AddDocTemplate (pDocTemplate} ;

Диалоговое окно About принадлежит классу CAboutDlg, являющемуся, как и в предыдущем примере, потомком класса CDialog. У него имеется схема сообщений, конструктор И метод

DoDataExchange( ) .

Файл MAINFRM.CPP

Файл MAINFRM.CPPсодержит реализацию класса CMainFrame, который порождается от класса CFrameWndи управляет всеми дочерними MDI-окнами.

//MainFrm.cpp: реализация класса CMainFrame

#include "stdafx.h" #include "Editor, h" #include "MainFrra.h"

lifdef _DEBOG #define new DEBDG_NEW #undef THIS_FILE

static char THIS_FILE[] = _ FILE _ ; #endif

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

//CMainFrame

IMPLEMENT_DYNAMIC (CMainFrame, CMDIFrameWnd) BEGIN_MESSAGE_MAP (CMainFrame, CMDIFrameWnd) // { (AFX_MSG_MAP (CMainFrame)

381

ON_WM_CREATE ( )

//}}AFX_MSG_MAP END_MESSAGE_MAP ( ) static UINT indicators!] =

{

ID_SEPARATOR, // поля строки состояния

ID_IKDICATOR_CAPS , ID_INDICATOR_NUM , ID_INDICATOR_SCRL , };

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

// Конструктор и деструктор класса CMainFrame CMainFrame::CMainFrame()

{

}

CMainFrame :: --CMainFrame ()

{

1

int CMainFrame: :OnCreate (LPCREATESTRUCT IpCreateStruct) { if (CMDIFrameWnd: :OnCreate (IpCreateStruct) == -1) return -1; if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD |

WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRSJFLYBY | CBRS_SIZE_DYNAMIC) | | ! m_wndToolBar . LoadToolBar { IDR_MAINFRAME) )

<

TRACED ("Failed to create toolbarXn") ;

 

return-1;

//не удалось создать панель инструментов

 

}

 

 

if (!m_wndStatusBar.Create(this) ||

 

!m_wndStatusBar.Setlndicators(indicators,

 

sizeof(indicators)/sizeof(UINT))) {

 

TRACED("Failed to create status bar\n"); return -1;

//не удалось

создать строку состояния

 

m_wndToolBar . EnableDocking (CBRS_ALIGN_ANY) ; EnableDocking(CBRS_ALIGN_ANY) ; DockControlBar (Sm wndToolBar) ;

return 0; }

BOOL CMainFrame: : PreCreateWindow (CREATESTRUCT Ses) ( if(! CMDIFrameWnd: : PreCreateWindow (cs)) return FALSE; return TRUE;

}

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

//Диагностика класса CMainFrame #ifdef __DEBUG

void CMainFrame::AssertValid() const

{

CMDIFrameWnd::AssertValid();

}

void CMainFrame::Dump(CDumpContext &dc) const CMDIFrameWnd::Dump(dc); }

#endif //_DEBUG

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

//Обработчики сообщений класса CMainFrame

Заметьте, что в схему сообщений добавлен обработчик сообщений wm_create. Обратите также внимание на этот небольшой фрагмент:

static UINT indicators[] =

ID_SEPARATOR,

// поля строки состояния

ID_INDICATOR_CAPS,

ID__INDICATOR_NUM,

382

ID_INDICATOR_SCRL,

Как вы помните, в одном из окон мастера AppWizard была задана возможность добавления в окно приложения строки состояния. В массиве indicators перечислены идентификаторы различных полей строки состояния, которые служат индикаторами нажатия клавиш [CapsLock], [NumLock] и [ScrollLock].

Файл EDITORDOC.CPP

Файл EDITORDOC.CPPсодержит реализацию класса CEditorDoc, который управляет работой с конкретным документом, а также обеспечивает загрузку и сохранение данных документа.

// EditorDoc.cpp: реализация класса CEditorDoc #include "stdafx.h"

#include "Editor.h" #include "EditorDoc.h"

#ifdef _DEBUG Idefine new DEBDG_NEW #undef THIS_FILE

static char THIS_FILE[]= _ FILE _ ; #endif

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

//CEditorDoc

IMPLEMENT_DYNCREATE (CEditorDoc, CDocument) BEGIN_MESSAGE_MAP (CEditorDoc, CDocument)

//{ (AFX_MSG_MAP (CEditorDoc) //)}AFX_MSG_MAP END_MESSAGE_MAP ( )

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

//Конструктор и деструктор класса CEditorDoc CEditorDoc: : CEditorDoc ()

{

}

CEditorDoc::-CEditorDoc()

{

}

BOOL CEditorDoc: : OnNewDocument () {

if ( ! CDocument : : OnNewDocument ( ) ) return FALSE; return TRUE;

}

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

//Сериализация класса CEditorDoc

void CEditorDoc::Serialize(CArchive &ar) ( ((CEditView*)m_viewList.GetHead())->SerializeRaw(ar);

}

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

//Диагностика класса CEditorDoc #ifdef DEBUG

void CEditorDoc: :AssertValid()const { CDocument : :AssertValid() ; )

void CEditorDoc: : Dump (CDumpContext &dc) const { CDocument : : Dump (dc); } #endif //_DEBOG

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

//Другие функции класса CEditorDoc

Строка функции Serialize(), выделенная полужирным шрифтом, поддерживает работу командменю FUe, обеспечивающих создание, открытие и сохранение файлов.

Файл EDITORV1EW.CPP

383

Файл EDITORVIEW.CPPсодержит реализацию класса CEditorView, который порождается от класса CEditViewи управляет отображением документа.

//EditorView.cpp: реализация класса CEditorView//

# include "stdafx.h" #include . "Editor .h"

#include "EditorDoc.h" #include "EditorView.h" #ifdef _DEBUG

#define new DEBOG_NEW #undef THIS_FILE

static char THIS_FILE[] = _ FILE _ ; #endif

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

//CEditorView

IMPLEMENT_DYNCREATE (CEditorView, CView)

BEGIN_MESSAGE_MAP (CEditorView, CView) //{{AFX_MSG_MAP (CEditorView) //}}AFX_MSG_MAP // Стандартныекомандыпечати

ON_COMMAND(ID_FILE_PRINT, CView: : OnFilePrint) ON_COMMAND(ID_FILE_PRINT_DIRECT, CView: :OnFilePrint) ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView: :OnFilePrintPreview)

END_MESSAGE_MAP ( )

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

//Конструктор и деструкторкласса CEditorView CEditorView::CEditorView()

{ } CEditorView::-CEditorView()

{

}

BOOL CEditorView: :PreCreateWindow(CREATESTRUCT Ses) { BOOL bPreCreated = CEditView: :PreCreateWindow (cs);

cs.style &= ~ (ES_AUTOHSCROLL I WS_HSCROLL) ; // разрешен перенос слов return bPreCreated;

)

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

//Отображение документа

void CEditorView::OnDraw(CDC* pDC)

{

CEditorDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc) ; }

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

// Печать документа

BOOL CEditorView: :OnPreparePrinting (CPrintlnf o* plnfo) {

//стандартные действия по подготовке к печати return CEditView: :OnPreparePrinting (plnfo);

}

void CEditorView: :OnBeginPrinting (CDC* pDC, CPrintlnfo* plnfo) { CEditView: :OnBeginPrinting (pDC, plnfo); }

void CEditorView: :OnEndPrinting (CDC* pDC, CPrintlnfo* plnfo) { CEditView: :OnEndPrinting (pDC, plnfo);

}

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

//Диагностика класса CEditorView

#ifdef _DEBUG

void CEditorView: :A-ssertValid() const

{

384

CView::AssertValid() ; }

void CEditorView: : Dump (CDumpContext &dc) const

{

CView::Dump(dc); }

CEditorDoc* CEditorView::GetDocument() // отладочнаяверсия{ ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CEditorDoc))); return (CEditorDoc*)m_pDocument; }

#endif //_DEBUG

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

//Обработчики сообщений класса CEditorView

void CEditorView::OnRButtonDown(DINT nFlags, CPoint point)

{

char szTimeStr[20];

CTime tm = CTime::GetCurrentTime();

sprintf{szTimeStr, "It'snow %02d:%02d:%02d", tn>. GetHour () , tm. GetMinute () , tm.GetSecondO ) ;

MessageBox(szTimeStr, "Isit time to quit yet?", MB_OK); CEditView::OnRButtonDown(nFlags, point); }

Анализируя схему сообщений, вы заметите, что в ней содержится макрос on_wm__rbuttondown, который был добавлен мастером ClassWizard, и обработчики

Сообщений ID_FILE_PRINT, ID_FILE_PRINT_DIRECT, ID_FILE_PREVIEW, используемые совместно с классом CEditorView. Конструктор и деструктор класса остались пустыми. Печать документов реализуется с помощью функций onPreparePrinting(), OnBeginPrinting() и OnEndPrinting().

В конце листинга помещен текст функции OnRButtonDown(}, осуществляющей обработку сообщений wm_rbuttondown. Процесс добавления этой функции с помощью мастера ClassWizard проиллюстрирован на рис. 20.25.

Выполните двойной щелчок на элементе OnRButtonDown в списке Memberfunctions, чтобы перейти непосредственно к разделу файла EDITORVIEW.CPP, отвечающему за обработку сообщений. На рис. 20.26 показано место, куда был вставлен новый программный блок.

Теперь, после компиляции приложения, в результате щелчка правой кнопкой мыши в окне текстового редактора отобразится небольшое окошко, содержащее текущее время (рис. 20.27).

385

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

Рис. 20.26. Добавление функции OnRButtonDown

386

Рис. 20.27. Диалоговое окно, отображающееся при нажатии правой кнопки мыши.

387

Глава 21. Введение в OLE

Основные концепции

o Объекты

o Структурированные файлы

o Унифицированная передача данных

o Внедрение

oСвязывание

Создание OLE -контейнера

oРабота с мастером приложений

oАнализ программного кода

Проверка работы контейнера

Внастоящей главе вы познакомитесь с основными концепциями технологии OLE(ObjectLinkingandEmbedding— связывание и внедрение объектов), которую можно определить как объектно-ориентированный протокол совместного доступа к данным и программному коду из разных процессов и даже из разных компьютеров в пределах локальной сети. OLE позволяет программистам создавать приложения для работы с составными документами, представляющими собой динамические связанные структуры, отдельные части которых могут разрабатываться в различных программах. Составной документ обычно включает в себя главный документ и ряд внедренных или связанных объектов.

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

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

Основные концепции

Объекты

Процедурные приложения для Windows базируются главным образом на использовании стандартных API-функций. Из-за этого иногда бывает трудно определить язык реализации программы (С или C++), поскольку вся она может состоять только из вызовов стандартных функций!

Вглавах 18 и 19 мы постепенно перешли от процедурных подходов в программировании к объектно-ориентированной методике. Этот переход стал возможным благодаря использованию библиотеки MFC . Технология OLE открывает новые возможности для объектно-ориентированного программирования.

Воснове OLE лежит модель компонентных объектов — COM (ComponentObjectModel), представляющая собой двоичный стандарт, который предназначен для организации взаимодействия между двумя не связанными приложениями. Подобное взаимодействие организуется посредством интерфейсов, которые должны реализовываться объектами. Объекты, подчиняющиеся правилам СОМ, называются СОМ-объектами.

Каждый СОМ-объект имеет уникальный идентификатор класса (CLSID) и создается с помощью функций, содержащихся в специальной фабрике классов (classfactory), связанной с данным

388

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

Структурированные файлы

Данные составных документов записываются на диск в виде структурированных файлов, в которых используются специальные объекты — потоки (stream) и хранилища (storage). Потоки напоминают обычные файлы, а хранилища аналогичны папкам. Структурированные файлы выполняют роль оболочки, скрывающей реальное размещение данных на диске и облегчающей пользователям процесс манипулирования документами.

Унифицированная передача данных

Унифицированная передача данных реализуется посредством объектов данных, инкапсулирующих сами данные. Наличие указателя на объект облегчает подключение к источнику данных различных клиентов. Объект данных, в свою очередь, осуществляет полный контроль за обменом данными между приложениями. Поэтому, с точки зрения программистов, обмен данными, осуществляемый методом drag-and-drop, ничем не отличается от передачи через буфер обмена.

Внедрение

В составных документах часто хранится информация из разных источников, не связанных между собой. Например, текстовый документ MicrosoftWordможет содержать электронную таблицу Excelи точечный рисунок из программы Paint.

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

В описываемом случае Word является контейнером, a Excel и Paint— серверами. Иными словами, контейнер содержит объекты, созданные в других приложениях, а сервер — это приложение, являющееся источником самих объектов. В качестве примера мы рассмотрим внедрение в документ Word объекта Paint.

Запустите программу MicrosoftWord. Типичное окно Word с введенным текстом показано на рис. 21.1.

389

Рис. 21.1. Microsoft Word является приложением-контейнером

Далее в меню Insert выберите команду Object.... Перед вами откроется диалоговое окно вставки объекта (рис. 21.2).

Рис. 21.2. Окно вставки позволяет выбрать тип внедряемого объекта

В списке типов объектов выделите элемент PaintbrushPicture. После щелчка на кнопке ОК будет автоматически запущена программа Paint, область рисования которой разместится

390

Соседние файлы в предмете Программирование на C++