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

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

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

Рис. 22.6. Местонахождение инструментов ActiveX

В окне контейнера выберите в меню Edit команду InsertNewControl, и перед вами откроется диалоговое окно InsertControl, в котором будет представлен список всех зарегистрированных элементов управления . Теперь щелкните на кнопке ОК, чтобы внедрить выбранный элемент управления в окно контейнера .

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

421

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

Код, сгенерированный мастером

Для большинства элементов управления ActiveX мастер ControlWizard создает четыре программных файла. В нашем проекте это файлы STDAFX.CPP, TDCTRL.CPP, TDCTRLCTL.CPP и TDCTRLPPG.CPP. Каждому из них соответствует отдельный файл заголовков.

Файл STDAFX.CPPпредназначен для включения в программу всех файлов заголовков, необходимых для работы элемента управления ActiveX. Файл TDCTRL.CPPотвечает за реализацию класса CTDCtrlApp и регистрацию DLL-модуля.

В следующих параграфах мы проанализируем назначение файлов TDCTRLCTL.CPP и TDCTRLPPG.CPP.

Файл TDCTRLCTL.CPP

Файл TDCTRLCTL.CPPсодержит реализацию собственно класса элемента управления ActiveX. В нашем примере это класс CTDCtrlctrl. Именно данный файл больше других требует изменений со стороны программиста.

//TDCtrlCtl.cpp: Реализация класса CTDCtrlСtrl элемента управления. #include "stdafx.h"

#include "TDCtrl.h" #include "TDCtrlCtl.h" #include "TDCtrlPpg.h" tifdef _DEBUG

#define new DEBUG_NEW tundef THIS_FILE

static char THIS_FILE[] = _FILE_; #endif

IMPLEMENT_DYNCREATE(CTDCtrlctrl, COleControl)

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

//Схема сообщений

BEGIN_MESSAGE_MAP(CTDCtrlctrl, COleControl) //{{AFX_MSG_MAP(CTDCtrlctrl)

//ПРИМЕЧАНИЕ: мастер классов будет добавлять и удалять здесь

//макросы схемы-сообщений.

//НЕ РЕДАКТИРУЙТЕ то, что здесь находится.

//)}AFX_MSG_MAP

ON_OLEVERB (AFX_IDS_VERB_EDIT, OnEdit) ON_OLEVERB(AFX_IDS_VERB_PROPERTIES, OnProperties) END MESSAGE MAP ()

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

// Схема диспетчеризации

BEGIN DISPATCH MAP(CTDCtrlctrl, COleControl)

//{ {AFX_DISPATCH_MAP (CTDCtrlctrl)

//ПРИМЕЧАНИЕ: мастер классов будет добавлять и удалять здесь

//макросы схемы диспетчеризации.

//НЕРЕДАКТИРУЙТЕ то, что здесь находится. //}}AFX_DISPATOt_MAP

DISP_FUNCTION_ID (CTDCtrlctrl, "AboutBox", DISPID_ABOUTBOX, AboutBox, VT_EMPTY, VTSJTONE) END_DISPATCH_MAP ( )

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

// Схемасобытий

BEGIN_EVENT_MAP (CTDCtrlctrl, COleControl) // { (AFX_EVENT_MAP (CTDCtrlctrl)

422

//ПРИМЕЧАНИЕ: мастер классов будет добавлять и удалять здесь

//макросы схемы событий.

//НЕ РЕДАКТИРУЙТЕ то, что здесь находится.

//} }AFX_EVENT_MAP END_EVENT_MAP ( )

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

//Страницы свойств

//TODO: Сюда можно добавлять новые страницы свойств.

//Не забудьте увеличить значение счетчика!

BEGIN_PROPPAGEIDS (CTDCtrlctrl, 1)

PROPPAGEID (CTDCtrlPropPage : : quid) END_PROPPAGEIDS (CTDCtrlctrl)

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

// Инициализация фабрики класса и формирование GUID IMPLEMENT_OLECREATE_EX (CTDCtrlCtrl, "TDCTRL . TDCtrlCtrl .1",

Oxc0377506, Oxb276, Oxlldl, Oxba, Oxe9, 0, OxaO, Oxc9, Ox8c, Oxc4,

Охбе)

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

// Идентификатор библиотеки типов и ее версия IMPLEMENt_OLETYPELIB (CTDCtrlCtrl, _tlid, _wVerMajor, _wVerMinor)

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

//Идентификаторы интерфейсов const IID BASED_CODE IID_DTDCtrl =

{ Oxc0377504, Oxb276, Oxlldl, { Oxba, Oxe9, 0, OxaO, Oxc9, Ox8c, Oxc4, Охбе } } ;

const IID BASED_CODE IID_DTDCtrlEvents =

{ Oxc0377505, Oxb276, Oxlldl, { Oxba, Oxe9, 0, OxaO, Oxc9, Ox8c, Oxc4, Ох6е } ) ;

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

//Информация о типе элемента управления

static const DWORD BASED_CODE _dwTDCtr!01e'Misc = OLEMISC_ACTIVATEWHENVISIBLE I OLEMISC_SETCLIENTSITEFIRST | OLEMISC_INSIDEOUT | OLEMISC_CANTLINKINSIDE I OLEMISC_RECOMPOSEONRESIZE;

IMPLEMENT_OLECTLTYPE (CTDCtrlCtrl, IDSJTDCTRL, _dwTDCtr!01eMisc)

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

CTDCtrlCtrl: :CTDCtrlCtrlFactory: :UpdateRegistry

//Добавляет и удаляет записи системного реестра

//для класса CTDCtrlCtrl

BOOL CTDCtrlCtrl: : CTDCtrlCtrlFactory : :UpdateRegistry (BOOL bReglster)

{

//TODO: Проверьте, соответствует ли элемент управления

//правилам изолированной потоковой модели.

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

//MFC TechNote64.

//Если элемент управления не поддерживает эту модель,

//замените шестой параметр константой afxReglnsertable. if (bRegister)

return AfxOleRegisterControlClass ( AfxGetlnstanceHandle () ,

m_clsid, m_lpszProgID, IDSJTDCTRL, IDBJTDCTRL,

afxReglnsertable I afxRegApartmentThreadlng, _dwTDCtr!01eMisc,

423

_tlid, _wVerMajor, _wVerMinor) ; else

return AfxOleUnregisterClass(m_clsid, m_lpszProgID); }

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

//CTDCtrlCtrl::CTDCtrlCtrl - Конструктор CTDCtrlCtrl::CTDCtrlCtrl() { InitializellDs(SIID_DTDCtrl, SIID_DTDCtrlEvents);

//TODO: В этом месте инициализируйте данные

//текущего экземпляра элемента управления.

}

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

//CTDCtrlCtrl::-CTDCtrlCtrl - Деструктор CTDCtrlCtrl: : -CTDCtrlCtrl( )

{

//TODO: В этом месте удалите данные

//текущего экземпляра элемента управления.

)

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

I/ CTDCtrlCtrl::OnDraw— Функция отображения

void CTDCtrlCtrl::OnDraw(CDC* pdc, const CRect SrcBounds, const CRect Srclnvalid) {

//TODO: Замените следующие операторы

//собственными операторами отображения.

pdc->FillRect(rcBounds, CBrush::FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH))) pdc->Ellipse(rcBounds); }

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

//CTDCtrlCtrl::DoPropExchange — Поддержка постоянства элемента void CTDCtrlCtrl::DoPropExchange(CPropExchange* pPX) f ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor)); COleControl::DoPropExchange(pPX) ;

//TODO: Поместите здесь вызовы РХ_-функций для каждого

//постоянного пользовательского свойства.

}

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

// CTDCtrlCtrl::OnResetState— Восстанавливает первоначальное

//состояние элемента управления void CTDCtrlCtrl::OnResetState() {

COleControl::OnResetState(); // Сброс значений, установленных

//в методе DoPropExchange()

//TODO: Восстановите здесь все остальные переменные состояния

//элемента управления. )

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

//CTDCtrlCtrl::AboutBoxОтображает окно About

void CTDCtrlCtrl::AboutBox() {

CDialog dlgAbout(IDD_ABOUTBOX_TDCTRL) ; dlgAbout.DoModal();

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

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

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

Механизм автоматизации заключается в вызове методов и свойств элементов управления из разных приложений. Эти запросы распределяются посредством схемы диспетчеризации. Схема событий помогает обрабатывать события элемента управления.

424

Функция OnDraw() скоро станет объектом нашего особого внимания, поскольку это именно тот блок программы, который отвечает за вывод графического образа элемента управления. По умолчанию в созданном мастером элементе управления ActiveX вызывается функция Ellipse() , выводящая на экран эллипс.

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

// CTDCtrlCtrl :: OnDraw— Функция отображения

void CTDCtrlCtrl: : OnDraw (CDC* pdc, const CRect SrcBounds, const CRect Srclnvalid) {

//TODO: Замените следующие операторы

//собственными операторами отображения. pdc->FillRect (rcBounds,

CBrush: :FromHandle( (HBRUSH) GetStockObject (WHITE_BROSH) ) ) ; pdc->Ellipse (rcBounds) ; }

Мастер ControlWizard также создает для разрабатываемого проекта диалоговое окно About. Содержимое окна можно изменить таким образом, чтобы в нем отражалась специфическая информация о проекте. Описание окна вы найдете в файле TDCTRL.RC, а выводится оно на экран посредством следующей функции:

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

// CTDCtrlCtrl: :AboutBox— Отображает окно About void CTDCtrlCtrl.: :AboutBox () {

CDialog dlgAbout (IDD_ABOUTBOX_TDCTRL) ; dlgAbout . DoModal ( } ;

Файл TDCTRLPPG.CPP

Этот файл содержит реализацию класса CTDCtrlPropPage, являющегося потомком класса

COlePropertyPage.

//TDCtrlPpg.cpp: реализация класса CTDCtrlPropPageстраницы свойств. #include "stdafx.h"

#include "TDCtrl.h" #include "TDCtrlPpg.h" #ifdef _DEBUG

#define new DEBUG NEW #undef THIS_FILE

static char THIS_FILE[] = _FILE_; #endif

IMPLEMENT_DYNCREATE(CTDCtrlPropPage, COlePropertyPage)

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

//Схема сообщений

BEGIN_MESSAGE_MAP(CTDCtrlPropPage, COlePropertyPage) //{{AFX_MSG_MAP(CTDCtrlPropPage)

//ПРИМЕЧАНИЕ: мастер классов будет добавлять и удалять здесь

//макросы схемы сообщений.

//НЕ РЕДАКТИРУЙТЕ то, что здесь находится.

//}}AFX_MSG_MAP END_MESSAGE_MAP ()

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

//Инициализация фабрики классов и формирование GUID IMPLEMENT_OLECREATE_EX(CTDCtrlPropPage, "TDCTRL.TDCtrlPropPage.1", Oxc0377507,

Oxb276, Oxlldl, Oxba, Oxe9, 0, OxaO, Oxc9, Ox8c, Oxc4, 'Ох6е)

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

//CTDCtrlPropPage::CTDCtrlPropPageFactory::UpdateRegistry —

//Добавляет и удаляет записи системного реестра

//для класса CTDCtrlPropPage

425

BOOL CTDCtrlPropPage::CTDCtrlPropPageFactory::UpdateRegistry (BOOL bRegister) {

if (bRegister)

return AfxOleRegisterPropertyPageClass(AfxGetlnstanceHandle(), m_clsid, IDS_TDCTRL_PPG) else

return AfxOleUnregisterClass(m_clsid, NULL); }

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

//CTDCtrlPropPage::CTDCtrlPropPage — Конструктор CTDCtrlPropPage::CTDCtrlPropPage() : COlePropertyPage(IDD, IDS_TDCTRL_PPG_CAPTION) ! //({AFX_DATA_INIT(CTDCtrlPropPage)

//ПРИМЕЧАНИЕ: мастер классов будет добавлять здесь

//операторы инициализации переменных-членов.

//НЕ РЕДАКТИРУЙТЕ то, что здесь находится. //}}AFXDATAINIT

}

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

//CTDCtrlPropPage::DoDataExchangeОсуществляет обмен данными

//между страницей и связанными с ней свойствами

void CTDCtrlPropPage::DoDataExchange(CDataExchange* pDX) { ' //{(AFX_DATA_MAP(CTDCtrlPropPage)

//ПРИМЕЧАНИЕ: мастер классов будет добавлять здесь

//вызовы DDP-, DDX- и DDV-функций.

//НЕ РЕДАКТИРУЙТЕ то,что здесь находится.

//}}AFX_DATA_MAP DDP_PostProcessing(pDX); }

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

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

Функция AfxOleRegisterPropertyPageClass() предназначена для регистрации класса страницы свойств в системном реестре. Благодаря этому страница свойств может использоваться другими контейнерами, которые поддерживают внедрение элементов управления ActiveX. Регистрационная запись с указанием имени страницы свойств и ее местоположения в системе обновляется всякий раз при вызове данной функции.

Обратите внимание, что в конструкторе базового класса CDlePropertyPage, от которого порожден класс CTDCtrlPropPage, можно указать идентификатор шаблона диалогового окна, положенного в основу страницы свойств, а также идентификатор строки заголовка.

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

Модификация шаблона

Элемент управления ActiveX, автоматически созданный мастером ControlWizard, можно изменить с помощью мастера ClassWizard. Мы внесем следующие изменения в имеющийся шаблон:

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

прямоугольный элемент управления будет закрашен желтым цветом;

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

Сделать все это можно путем внесения изменений в файлы TDCtrlCtl.CPPи TDCtrlCtl.H.

Изменение формы, размеров и цвета элемента управления TDCtrl

426

В окне компилятора VisualC++ в меню View выберите команду ClassWizard, чтобы запустить мастер ClassWizard, и выполните действия, перечисленные далее.

1.В диалоговом окне MFC ClassWizard перейдите на вкладку Automation.

2.В списке Classname выберите класс CTDCtrlctrl.

3.С помощью кнопки AddProperty откройте одноименное диалоговое окно (рис. 22.9).

Рис. 22.9. Добавление свойства TDShape в окне AddProperty

4.В поле Externalname введите имя свойства TDShape.

5.В группе опций Implementation (тип реализации) выберите переключатель Membervariable(значение свойства будет храниться в переменной-члене).

6.В списке Туре (тип свойства) выберите тип данных BOOL. Обратите внимание, что в ходе выполнения предыдущих установок в поле Notificationfunction(функция обработки изменений) автоматически появилась запись OnTDShapeChanged, а для переменной-члена (поле Variablename) было подобрано имя m_tDShape, также автоматически.

7.Щелкните на кнопке ОК, чтобы принять заданные установки и вернуться к окну MFC

ClassWizard.

8.Еще раз щелкните на кнопке AddProperty, и перед вами повторно откроется диалоговое окно AddProperty.

9.В этот раз в списке Externalnameвыберите свойство BackColor.

10.В группе опций Implementationвыберите переключатель Stock(базовое свойство).

11.Щелкните на кнопке ОК, с тем чтобы вернуться к диалоговому окну MFC ClassWizard(рис. 22.10).

427

Рис. 22.10. Мастер ClassWizard добавляет в класс TDCtrlCtrl новые свойства - BackColor и TDShape

12. Щелкните на кнопке ОК, и мастер ClassWizardвнесет изменения в код элемента управления.

Мастер классов добавит в файл TDCTRLCTL.Hобъявление функции OnTDShapeChanged ( ) и переменной m_tDShape, а в файл TDCTRLCTL.CPPдобавит стандартную реализацию указанной функции и поместит в схему диспетчеризации соответствующие макросы.

Все перечисленные изменения автоматически вносились мастером классов. Теперь наступает наш черед производить изменения.

Возвращаемся к файлу TDCTRLCTL.CPP

В следующем листинге показаны изменения, вносимые в файл TDCTRLCTL.CPP(выделены полужирным шрифтом).

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

// CTDCtrlCtrl::OnDrawФункция отображения

void CTDCtrlCtrl::OnDraw(CDC* pdc, const CRect SrcBounds, const CRect srclnvalid) {

CBrush* pOldBrush;

CBrush NewBrush;

CPen* pOldPen; CPen NewPen;

pdc->Fil!Rect(rcBounds, CBrush::FromHandle((HBRUSH) GetStockObject(WHITE_BRUSH))); NewPen.CreatePen(PS_SOLID, 3, RGB(0, 0,0));

pOldPen = {CPen*)pdo->SelectObject(SNewPen), // Создание желтой кисти

NewBrush.CreateSolidBrush(RGB(255, 255, 0)); pOldBrush = (CBrush*)pdc- >SelectObject(SNewBrush);

// Рисование прямоугольника с заливкой pdc->Rectangle(rcBounds);

428

pdc->SelectObject(pOldPen); pdc->SelectObject(pOldBrush);

}

Действие функции Rectangle() приводит к тому, что элемент управления принимает вид прямоугольника, закрашенного в желтый цвет.

Реакция на события мыши

В данном параграфе будет показано, как заставить элемент управления TDCtrlреагировать на действия, осуществляемые с помощью мыши. Мы сделаем так, что элемент управления после щелчка на нем указателем мыши изменит свой цвет на светло-серый и в нем отобразятся системное время и дата.

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

1.В диалоговом окне MFC lassWizard перейдите на вкладку Automation.

2.В списке Classname выберите класс CTDCtrlctrl.

3.С помощью кнопки AddProperty откройте диалоговое окно AddProperty.

4.В поле External names введитеHitTDCtrl.

5.В группе опций Implementation выберите переключатель Member variable.

6.В списке Туре выделите тип данных ole^color и очистите поле Notification function.

7.Щелкните на кнопке ОК, чтобы принять сделанные установки и вернуться к диалоговому окну MFC ClassWizard(рис. 22.11).

8.Перейдите на вкладку MessageMaps.

9.В списке Classname выберите класс CTDCtrlctrl.

10.В списке Messages выберите сообщение wm_lbuttondown.

11.Щелкните на кнопке AddFunction.

12.Повторите действия, указанные в пунктах 10 и 11, по отношению к сообщению

wm_lbuttonup. Теперь ваше диалоговое окно должно выглядеть так, как показано на рис. 22.12.

Рис. 22.11. Свойство HitTDCtrl позволит элементу управления реагировать на события мыши

429

Рис. 22.12. Добавление обработчиков событий мыши

13. Щелкните на кнопке ОК, и мастер ClassWizard внесет изменения в код элемента управления.

Мастер классов автоматически добавит в файл TDCTRLCTL.Hобъявление переменной m_hitTDCtrl, а в файл TDCTRLCTL.CPP— стандартные реализации обработчиков

OnLButtonDown() и OnLButtonUp().

Теперь нужно самостоятельно добавить код, определяющий реакцию элемента управления на соответствующие события.

Файл TDCTRLCTL.H

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

// Реализация protected: -CTDCtrlCtrl() ;

void HitTDCtrl(CDC* pdc); // изменение цвета

Далее нужно написать код этой функции.

Возвращаемся к файлу TDCTRLCTL.CPP

При щелчке левой кнопкой мыши на элементе управления должен измениться цвет его прямоугольной области. Частично это событие обрабатывается функцией DoPropExchange(). Ниже показана исправленная версия данной функции в ЛОбав-ленной строкой, которая выделена полужирным шрифтом:

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

// CTDCtrlCtrl::DoPropExchange— Поддержка постоянства элемента void CTDCtrlCtrl::DoPropExchange(CPropExchange* pPX) { ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor)); COleControl::DoPropExchange(pPX);

}

430

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