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

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

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

ClickIn() и ClickOut().В файле POLYCTL.H в список предков класса CPolyCtl будет добавлен класс CProxy_iPolyCtlEvents, а в схему СОМ-интерфейсов будет помещена запись

COM_INTERFACE_ENTRY_IMPL(IConnectionPointContainer)

Кроме того, будет обновлена схема точек подключения класса CPolyCtl:

BEGIN_CONNECTION_POINT_MAP(CPolyCtl)

CONNECTION_POINT_ENTRY(IID_IPropertyNotifySink)

CONNECTION_POINT_ENTRY(DIID_I PolyCtlEvents)

END_CONNECTION_POINT_MAP()

Добавление обработчика сообщения

Обработчик сообщения wm_lbuttondown необходим для определения момента, когда пользователь щелкает левой кнопкой мыши на элементе управления. Перейдите на вкладку ClassView, щелкните правой кнопкой мыши на элементе CPolyCtl и выберите из контекстного меню команду AddWindowsMessageHandler. В открывшемся диалоговом окне в левом списке выберите сообщение wm_lbuttondown, щелкните на кнопке AddHandler и нажмите кнопку ОК.

В результате в файл POLYCTL.H будет добавлена стандартная реализация метода OnLButtonDown(), а в схеме сообщений класса CPolyCtl появится новая запись:

BEGIN_MSG_MAP(CPolyCtl)

CHAIN_MSG_MAP(CComControl<CPolyCtl>)

DEFAULT_REFLECTION_HANDLER()

MESSAGE_HANDLER(WM_LB0TTONDOWN, OnLButtonDown)

END MSG MAP()

Внесение изменений в файл POLYCTL.H

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

// PolyCtl.h: Объявление класса CPolyCtl #ifndef _POLYCTL_H_

#define _POLYCTL_H_ #include <math.h>

#include "resource.h" // основные константы #include <atlctl.h>

#include "PolygonCP.h"

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

11 CPolyCtl

class ATL_NO_VTABLE CPolyCtl :

public CComObjectRootEx<CComSingleThreadModel>,

public CStockPropImpKCPolyCtl, IPolyCtl, SIID_IPolyCtl, SLIBID_POLYGONLib>,

public CComControl<CPolyCtl>,

public IPersistStreamInitImpl<CPolyCtl>, public I01eControlImpl<CPolyCtl>, public I01eObjectImpl<CPolyCtl>,

public I01eInPlaceActiveObjectImpl<CPolyCtl>, public IViewObjectExImpKCPolyCtl>,

public I01eInPlaceObjectWindowlessImpl<CPolyCtl>, public ISupportErrorlnfo,

public IConnectionPointContainerImpl<CPolyCtl>, public IPersistStorageImpl<CPolyCtl>,

public ISpecifyPropertyPagesImpl<CPolyCtl>, public IQuickActivateImpl<CPolyCtl>, public IDataObjectImpl<CPolyCtl>,

441

public IProvideClassInfo2Impl<SCLSID_PolyCtl, SDIID_IPolyCtlEvents, &LIBID_POLYGONLib>,

public IPropertyNotifySinkCP<CPolyCtl>, public CComCoClass<CPolyCtl, SCLSID_Po.lyCtl>

public CProxy_IPolyCtlEvents< CPolyCtl > { public: CPolyCtl ()

{

m_nSides =6;

// по умолчанию строится шестиугольник

m_clrFillColor = RGB(OxFF, OxFF, 0); // желтый цвет заливки

}

DECLARE_REGISTRY_RESOURCEID(IDR_POLYCTL) DECLARE PROTECT FINAL CONSTRUCT))

BEGIN_COM_MAP(CPolyCtl) COM_INTERFACE_ENTRY(IPolyCtl) COM_INTERFAOE_ENTRY(IDispatch) COM_INTERFACE_ENTRY(IViewObjectEx) COM_INTERFACE_ENTRY(IViewObject2) COM_INTERFACE_ENTRY(IViewObject) COM_INTERFACE_ENTRY(IDlelnPlaceObjectWindowless) COM_INTERFACE_ENTRY(I01eInPlaceObject)

COM_INTERFACE_ENTRY2(IQleWindow, IQlelnPlaceObjectWindowless) COM_INTERFACE_ENTRY(IOleInPlaceActiveObject) COM_INTERFACE_ENTRY(I01eControl) COM_INTERFACE_ENTRY(IQleObject) COM_INTERFACE_ENTRY(IPersistStreamlnit) COM_INTERFACE_ENTRY2(IPersist, IPersistStreamlnit) COM_INTERFACE_ENTRY(ISupportErroriInfo) COM_INTERFACE_ENTRY(IConnectionPointContainer) COM_INTERFACE_ENTRY(ISpecifyPropertyPages) COM_INTERFACE_ENTRY(IQuickActivate) COM_INTERFACE_ENTRY(IPersistStorage) COM_INTERFACE_ENTRY(IDataObject) COM_INTERFACE_ENTRY(IProvideClassInfo) COM_INTERFACE_ENTRY(IProvideClassInfo2)

COM_INTERFACE_ENTRY_IMPL(IConnectionPointContainer) ^ END_COM_MAP()

BEGIN_PROP_MAP(CPolyCtl)

PROP_DATA_ENTRY("_cx",m_sizeExtent.ex, VT_UI4)

PROP_DATA_ENTRY("_Gy",m_sizeExtent.cy, VT_UI4) PROP_ENTRY("FillColor",DISPID_FILLCOLOR, CLSID_StockColorPage)

END_PROP_MAPt) BEGIN_CONNECTION_POINT_MAP(CPolyCtl)

CONNECTION_POINT_ENTRY(IID_IPropertyNotifySink) CONNECTION_POINT_ENTRY(DIID_IPolyCtlEvents)

END_CONNECTION_POINT_MAP () BEGIN_MSG_MAP(CPolyCtl) CHAIN_MSG_MAP(CComControl<CPolyCtl>) DEFAULT_REFLECTION_HANDLER() END_MSG_MAP () // ISupportErrorlnfo

STDMETHOD(InterfaceSupportsErrorInfo) (REFIID riid)

{

static const IID* arr[]=

{

&IID_IPolyCtl,

442

{

for (int i = 0; i < sizeof(arr)/sizeof(arr[0]); i++)

{

if (InlineIsEqualGDID(*arr[i], riid)) return S_OK; } return S_FALSE;

}.

// IViewObjectEx

DECLARE_VIEW_STATUS(VIEWSTATUS_SOLIDBKGND | VIEWSTATOS_OPAQUE) // IPolyCtl public:

STDMETHOD(get_Sides)(/*[out,retval]*/ short *pVal); STDMETHOD(put_Sides) </*[in]*/short newVal);

HRESULT OnDraw(ATL_DRAWINFOS di); LRESULT OnLButtonDown(UINT uMsg,

WPARAM wParam, LPARAM IParam, BOOLS bHandled) OLE_COLOR m_clrFillColor;

short m_nSides; POINT m_arrPoint[10];

};

#endif // _ POLYCTL_H_

В конструкторе класса CpolyCtl устанавливается, что по умолчанию число сторон многоугольника, рисуемого в элементе управления, равно шести (минимальное — 3, максимальное — 10), а для заливки используется желтый цвет. Для вычисления координат вершин многоугольника потребуются тригонометрические функции, поэтому в проект включается библиотека МАТН.Н.

Стандартные реализации функций OnDraw( ) и OnLButtonDown( ) были удалены из файла, так как мы значительно расширим их и включим в файл POLYCTL.CPP.

Реализация методов элемента управления

Ниже приведен текст файла POLYCTL.CPP. Все дополнения и изменения выделены полужирным шрифтом.

//PolyCtl.cpp: Реализация класса CPolyCtl #include "stdafx.h"

#include "Polygon. h" #include "PolyCtl.h"

#include <time.h> #include <string.h>

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

//CPolyCtl

HRESULT CPolyCtl: : OnDraw (ATL_DRAHINFO& di)

{

struct tm *date_time; time_t timer;

static TEXTMETRIC tin;

RECTS rc = *(RECT*)di.prcBounds; HDC hdc = di.hdcDraw; COLORREF colFore;

HBRUSH hOldBrush, hBrush; HPEN hOldPen, hPen;

//Приведение переменной m_clrFillColor к типу COLORREF OleTranslateColor(m_clrFillColor, NULL, ScolFore);

//Выбор пера и кисти для рисования окружности

hPen - (HPEN)GetStockObject(BLACK_PEN); hOldPen = (HPEN)SelectObject (hdc, hPen); hBrush = (HBRUSH)GetStockObject(WHITE_BRUSH); hOldBrush = (HBRUSH)SelectObject(hdc, hBrush);

443

const double pi = 3.14159265358979; POINT ptCenter; double dblRadiusx = (rc.right - rc.left) / 2; double dblRadiusy = (rc.bottom - rc.top) / 2; double dblAngle = 3 * pi / 2;

double dblDiff = 2 * pi / m_nSides; ptCenter.x = (rc.left + rc.right) / 2; ptCenter.у = (rc.top + rc.bottom) / 2; // Вычисление координат вершин

for (int i = 0; i < m_nSides; i++) { m arrPoint[i].x = (long) \

(dblRadiusx*cos(dblAngle)+ptCenter.x+0.5); m_arrPoint[i].y = (long) \

(dblRadiusy*sin (dblAngle) -1-ptCenter. y+0.5) ;

dblAngle += dblDiff; } Ellipse(hdc, rc.left, rc.top, rc.right, rc.bottom);

//Создание и выбор кисти для заливки многоугольника hBrush = CreateSolidBrush(colFore); SelectObject(hdc, hBrush);

Polygon(hdc, Sm_arrPoint[0], m_nSides);

//Вывод даты и времени

time(Stimer);

date_time = localtime(<<timer); const char* strtime;

strtime = asctime(date_time); SetBkMode(hdc, TRANSPARENT);

SetTextAlign(hdc, TA_CENTER | TA_TOP); ExtTextOut(hdc, (rc.left + rc.right)/2,

(rc.top + rc.bottom - tan.tmHeight)/2,

ETO_CLIPPED, Src, strtime, strlen (strtime) -1,NULL);

//Восстановление старых пера и кисти

SelectObject(hdc, hOldPen) ; SelectObject(hdc, hOldBrush) ; DeleteOb ject (hBrush) ; return S_OK;

LRESULt CPolyCtl: : OnLButtonDown (UINT uMsg, WPJUWM wParam, LPARAM 1 Par am, BOOLS bHandled)

{

HRGNhRgn;

WORDxPos= LOWORD(lParam) ; // положение указателя по горизонтали WORDyPos= HIWORD(lParam) ; // положение указателя по вертикали

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

hRgn = CreatePolygonRgn(sm_arrPoint[0] , m_nSides, WINDING);

//Если точка щелчка попадает внутрь многоугольника,

//то генерируется событие Clickln,

//в противном случае - событие ClickOut

if (PtInRegion(hRgn, xPos, yPos) ) Fire_ClickIn (xPos , yPos) ; else Fire_ClickOut (xPos , yPos) ;

// Освобождение дескриптора

DeleteOb ject (hRgn) ; return 0 ;

}

STDMETHODIMP CPolyCtl::get_Sides(short *pVal) (

*pVal = m_nSides;

444

return S_OK; }

STDMETHODIMP CPolyCtl::put_Sides(short newVal)

{

if (newVal > 2 ££ newVal < 11) { m_nSides = newVal; FiifeViewChangeO ;

return S_OK; ) else

return Error(_T("Must have between 3 and 10 sides"));

}

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

Добавление страницы свойств

С помощью того же мастера ATL-объектов можно добавить в элемент управления страницу свойств. Для этого выберите в меню Insert командуNew ATL Object... (рис. 23.13).

Рис. 23.13. С помощью мастера ATL Object Wizard можно добавить в проект страницу свойств

Выделите категорию Controls, в ней — элемент PropertyPageи щелкните на кнопке Next. В следующем окне мастера можно установить параметры, определяющие работу страницы свойств. На вкладке Namesв поле ShortNameвведите имя объекта — PolyProp. Все остальные поля будут заполнены мастером автоматически (рис. 23.14).

445

Рис. 23.14. Задание параметров создаваемой страницы свойств

Теперь перейдите на вкладку Strings и заполните поля Title(текст ярлычка вкладки) и DocString(строка описания), а поле Helpfile (ассоциированный файл справки) очистите (рис. 23.15).

Рис. 23.15. На вкладке Strings следует заполнить поля Title и Doc String

После щелчка на кнопке ОК будут созданы новые файлы POLYPROP.H, POLYPROP.CPPи POLYPROP.RGS. Далее необходимо изменить внешний вид страницы свойств. Откройте с помощью вкладки ResourceViewдиалоговое окно с идентификатором lDD_PObYPROp, поменяйте существующую надпись на Sides: и добавьте текстовое поле с идентификатором

IDC_SIDEs(рис. 23.16).

446

Рис. 23.16. Изменение внешнего вида страницы свойств

Теперь нужно добавить обработчик, управляющий изменением значения поля idc_sides. Для этого выполните щелчок правой кнопкой мыши на поле и выберите в контекстном меню команду Events. В появившемся окне выберите в списке Classorobjecttohandle элемент

IDC_SIDBS, а затем в списке NewWindowsMessages/Events— сообщение EN_CHANGE.

Щелкните на кнопке AddHandler, после чего в открывшемся окне AddMemberFunctionбудет предложено имя обработчика (рис. 23.17).

Рис. 23.17. Добавление обработчика сообщений

Примите предлагаемое имя OnChangeSides и закройте оба окна. В результате в файл POLYPROP.H будет добавлена стандартная реализация данного обработчика, а в схеме сообщений класса CPolyProp появится новая запись:

BEGIN_MSG_MAP(CPolyProp)

CHAIN_MSG_MAP(IPropertyPageImpKCPolyProp>)

COMMAND_HANDLER(IDC_SIDES, EN_CHANGE, OnChangeSides)

END_MSG_MAP ()

447

Следующим шагом будет внесение изменений в файл POLYPROP.H:

// PolyProp.h: Объявление класса CPolyProp #ifndef _POLYPROP_H_

#define _POLYPROP_H_

#include "resource.h"

// основные константы

#include

"Polygon.h"

 

 

EXTERN_C

const CLSID

CLSID_PolyProp;

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

II CPolyProp

class ATL_NO_VTABLE CPolyProp :

public CComObjectRootEx<CComSingleThreadModel>, public CComCoClass<CPolyProp, &CLSID_PolyProp>, public IPropertyPageImpl<CPolyProp>,

public CDialogImpl<CPolyProp> { public: CPolyProp ( ) {

m_dwTitleID = IDSJTITLEPolyProp; m_dwHelpFileID - IDS_HELPFILEPolyProp; m_dwDocStringID = IDS_DOCSTRINGPolyProp;

}

enura (IDD = IDD_POLYPROP};

DECLARE_REGISTRY_RESOURCEID ( IDR_POLYPROP) DECLARE_PROTECT_FINAL_CONSTRUCT ( )

BEGIN_COM_MAP (CPolyProp)

-

COM_INTERFACE_ENTRY ( I Proper tyPage ) END_COM_MAP ( ) BEGIN_MSG_MAP (CPolyProp)

CHAIN_MSG_MAP ( IPropertyPageImpKCPolyProp>) COMMAND_HANDLER(IDC_SIDES, EN_CHANGE, OnChangeSides)

END_MSG_MAP ( )

STDMETHOD (Apply) (void) 1 OSES_CONVERSION ;

ATLTRACE (_T ( "CPolyProp: :Apply\n") ) ; for (UINT i = 0; i < m_nObjects; i++)

{

CComQIPtr<IPolyCtl , SIID_IPolyCtl> pPoly (m_ppOnk[i]) ; short nSides = ( short) GetDlgl temlnt (IDC_SIDES) ;

if FAILED (pPoly->put_Sides (nSides) ) { CComPtr<IErrorInf o> pError ; CComBSTR strError; GetErrorInfo(0, SpError) ;

pError->GetDescription (fistrError) ; MessageBox(OLE2T(strError) , _T ("Error"),

MB_ICONEXCLAMATION) ;

return E_FAIL; } } m_bDirty = FALSE; return S_OK; }

LRESULT OnChangeSides(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) {

SetDirty(TRCE); return 0;

}

};

#endif //_POLYPROP_H_

Страница свойств может быть вызвана сразу несколькими клиентами. Для обслуживания всех клиентов в функции Apply() запускается цикл и в нем вызывается метод put_Sides() для каждого клиента, данные которого были введены в текстовое поле.

448

Страница свойств добавляется в проект с помощью единственной строки в файле

POLYCTL.H:

BEGIN_PROP_MAP(CPolyCtl)

PROP_DATA_ENTRY("_c.x", m_sizeExtent.ex, VT_UI4)

PROP_DATA_ENTRY("_cy", m_sizeExtent.cy, VT_UI4)

PROPJ3NTRY("FillColor", DISPID_FILLCOLOR, CLSID_StockColorPage)

PRQP_ENTRY("Sides", 1, CLSID_PolyProp) END_PROP_MAP 0

Теперь можно приступать к тестированию элемента управления на Web-странице.

Тестирование элемента управления ATLна Web-странице

Мастер ATL-объектов создает исходный элемент управления вместе с тестовым HTMLфайлом, который находится в папке проекта. Он называется POLYCTL.HTM и может быть открыт в броузере Microsoft Internet Explorer. С помощью данного файла можно протестировать созданный нами элемент управления. Но прежде в этот файл следует внести изменения, выделенные ниже полужирным шрифтом:

<HTML>

<HEAD>

<TITLE>ATL 3.0 test page for object PolyCtl</TITLE> </HEAD>

<BODY>

<OBJECT ID="PolyCtl" CLASSID="CLSID:4CBBC676-507F-11DO-B98B-000000000000"> </OBJECT>

<SCRIPT LM>>GOAGE="VBScript"> <! — Sub PolyCtl_ClickIn(x, y) PolyCtl.Sides = PolyCtl.Sides + 1 End Sub

Sub PolyCtl_ClickOut(x, у) PolyCtl.Sides = PolyCtl.Sides - 1 End Sub —>

</SCRIPT>

</BODY>

</HTML>

Теперь запустите Internet Explorer и откройте в нем файл POLYCTL.HTM. Начальное содержимое Web-страницы показано на рис. 23.18.

Выполните несколько щелчков мышью внутри и вне многоугольника. Как вы убедитесь, число вершин станет автоматически увеличиваться >> уменьшаться, если только не будут достигнуты граничные значения 2 и 11 — в этом случае выдается сообщение об ошибке Must have between 3 and 10 sides. На рис. 23.19 показано, как изменится внешний вид элемента управления после двух щелчков внутри многоугольника.

449

Рис. 23.18. Исходный вид созданного вами элемента управления ATL

Примечание

Убедитесь, что в свойствах Internet Explorer установлен низкий уровень безопасности. По умолчанию задается средний уровень, но в этом случае выполнение сценариев неподписанных элементов управления ActiveX запрещено.

450

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