关于ActiveX Control开发总结 MFC篇

为了方便的移植及重用自己编写的控件,这时候我们就要用到ActiveX控件技术来封装自己的控件类。

封装一个ActiveX控件需要考虑:

1、提供用户设置的属性。

2、提供用户使用的接口函数。

3、控件事件的通知。

4、控件响应用户的操作。

5、控件的绘制。

6、异常处理。

 

 

添加用户设置属性方法:

 

打开类视图展开XXlib选择控件接口右键菜单添加-〉添加属性打开属性添加向导,设置属性后完成。

在idl文件自动生成代码:

[cpp]  view plain copy
  1. library ScribbleLib  
  2. {  
  3.     importlib(STDOLE_TLB);  
  4.     //  Primary dispatch interface for CScribbleCtrl  
  5.     [ uuid(9B217CBB-3D90-444A-898B-271B9EF1B36A),  
  6.       helpstring("Dispatch interface for Scribble Control")]  
  7.     dispinterface _DScribble  
  8.     {  
  9.         properties:  
  10.             [id(1) , helpstring("画笔颜色")] OLE_COLOR PenColor;  
  11.         methods:  
  12.     };  
 如果需要怎加自定义的枚举属性可以在之前定义

[cpp]  view plain copy
  1. #include <olectl.h>  
  2. #include <idispids.h>  
  3. typedef enum { Blank, SmallGrid, MediumGrid, LargeGrid } GridType;  
  4. [   
  5.     uuid(0A33EFF3-46C9-4B38-B2DC-05C42C99D093), version(1.0),  
  6.     helpfile("Scribble.hlp"),  
  7.     helpstring("Scribble ActiveX Control module"),  
  8.     control   
  9. ]  
  10. ............  

属性这样声明:

[cpp]  view plain copy
  1. properties:  
  2. [id(1) , helpstring("画笔颜色")] OLE_COLOR PenColor;  
  3. [id(2) , helpstring("显示网格")] GridType ShowGird;  
  4. ...........  
 

在控件头文件中生成代码

[cpp]  view plain copy
  1. class CScribbleCtrl : public COleControl  
  2. {  
  3.     DECLARE_DYNCREATE(CScribbleCtrl)  
  4.     // Constructor  
  5. public:  
  6.     CScribbleCtrl();  
  7.     // Implementation  
  8. protected:  
  9.     ~CScribbleCtrl();  
  10. .......................  
  11.     // Dispatch and event IDs  
  12. public:  
  13.     enum {  
  14.         dispidShowGird = 2,  
  15.         dispidPenColor = 1  
  16.     };  
  17. protected:  
  18.     // 根据向导的选择如果选择get/put则生成get/put函数,选择变量形式则为当前代码  
  19.     OLE_COLOR m_PenColor;     
  20.     void OnPenColorChanged(void);   
  21.     USHORT m_ShowGird;  
  22.     void OnShowGirdChanged(void);  
  23. .................................  
  24. };  
 

在控件cpp文件中生成代码

[cpp]  view plain copy
  1. // Dispatch map  
  2. BEGIN_DISPATCH_MAP(CScribbleCtrl, COleControl)  
  3.     DISP_PROPERTY_NOTIFY_ID(CScribbleCtrl, "ShowGird", dispidShowGird, m_ShowGird, OnShowGirdChanged, VT_UI2)  
  4.     DISP_PROPERTY_NOTIFY_ID(CScribbleCtrl, "PenColor", dispidPenColor, m_PenColor, OnPenColorChanged, VT_COLOR)  
  5.     DISP_PROPERTY_NOTIFY_ID(CScribbleCtrl, "DrawPen", dispiddrawPen, m_DrawPen, OndrawPenChanged, VT_UI2)  
  6. END_DISPATCH_MAP()  
  7. // CScribbleCtrl::DoPropExchange - Persistence support  
  8. void CScribbleCtrl::DoPropExchange(CPropExchange* pPX)  
  9. {  
  10.     ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));  
  11.     COleControl::DoPropExchange(pPX);  
  12.     // 绑定控件属性默认值,显示在控件属性页中  
  13.     PX_UShort(pPX, _T("ShowGird"), m_ShowGird, Blank);  
  14.     PX_Color(pPX, _T("PenColor"), m_PenColor, RGB(0, 0, 0));  
  15.     if (pPX->IsLoading())  
  16.     {     
  17.         // 加载用户在控件属性页中设置的控件属性值  
  18.     }  
  19. }  
  20. // CScribbleCtrl message handlers  
  21. void CScribbleCtrl::OnShowGirdChanged(void)  
  22. {  
  23.     Refresh(); // 刷新控件  
  24. }  
  25. void CScribbleCtrl::OnPenColorChanged(void)  
  26. {  
  27. }  
 

添加用户使用的接口函数:

 

与添加属性的方法一样,在添加菜单选择添加方法。

[cpp]  view plain copy
  1. // idl 代码段  
  2. dispinterface _DScribble  
  3. {  
  4. properties:  
  5. ......................  
  6. methods:  
  7.     [id(3), helpstring("method GetScribbleBmp")] ULONG GetScribbleHBITMAP(void);  
  8. .......................  
  9. //头文件代码段  
  10. .......................  
  11. // Dispatch and event IDs  
  12. public:  
  13.     enum {  
  14.         dispidGetScribbleBmp = 4L,  
  15.         dispidPenColor = 2,  
  16.         dispidShowGird = 1  
  17.     };  
  18. ........................  
  19. protected:  
  20.     ULONG GetScribbleHBITMAP(void);  
  21. .......................  
  22. //cpp文件代码段  
  23. ........................  
  24. // Dispatch map  
  25. BEGIN_DISPATCH_MAP(CScribbleCtrl, COleControl)  
  26.     .....................  
  27.     DISP_FUNCTION_ID(CScribbleCtrl, "GetScribbleHBITMAP", dispidGetScribbleBmp, GetScribbleHBITMAP, VT_UI4, VTS_NONE)  
  28. END_DISPATCH_MAP()  
  29. ULONG CScribbleCtrl::GetScribbleHBITMAP(void)  
  30. {  
  31.     .............  
  32. }  
  33. .............  
 

添加控件事件的通知

 

打开类视图展开XXlib选择控件事件接口(一般为_DXXXXEvents)右键菜单添加-〉添加方法打开方法添加向导,设置后完成。

COleControl 已经封装了一些内置的事件

事件映射宏如下:

[cpp]  view plain copy
  1. EVENT_STOCK_CLICK()  
  2. EVENT_STOCK_DBLCLICK()   
  3. EVENT_STOCK_KEYDOWN()   
  4. EVENT_STOCK_KEYPRESS()   
  5. EVENT_STOCK_KEYUP()  
  6. EVENT_STOCK_MOUSEDOWN()  
  7. EVENT_STOCK_MOUSEMOVE()   
  8. EVENT_STOCK_MOUSEUP()   
  9. EVENT_STOCK_ERROREVENT()   
  10. EVENT_STOCK_READYSTATECHANGE()   
 

函数原型

[cpp]  view plain copy
  1. // Firing functions for stock events  
  2. void FireKeyDown(USHORT* pnChar, short nShiftState);  
  3. void FireKeyUp(USHORT* pnChar, short nShiftState);  
  4. void FireKeyPress(USHORT* pnChar);  
  5. void FireMouseDown(short nButton, short nShiftState,  
  6.     OLE_XPOS_PIXELS x, OLE_YPOS_PIXELS y);  
  7. void FireMouseUp(short nButton, short nShiftState,  
  8.     OLE_XPOS_PIXELS x, OLE_YPOS_PIXELS y);  
  9. void FireMouseMove(short nButton, short nShiftState,  
  10.     OLE_XPOS_PIXELS x, OLE_YPOS_PIXELS y);  
  11. void FireClick();  
  12. void FireDblClick();  
  13. void FireError(SCODE scode, LPCTSTR lpszDescription, UINT nHelpID = 0);  
  14. void FireReadyStateChange();  
 

添加自定义的事件通知使用向导后需要编写一些代码,看代码段

[cpp]  view plain copy
  1. //idl代码段  
  2. //  Event dispatch interface for CScribbleCtrl  
  3. uuid(DA9841E5-98B9-4674-939E-8EC6BEE35273),  
  4. helpstring("Event interface for Scribble Control") ]  
  5. dispinterface _DScribbleEvents  
  6. {  
  7. properties:  
  8.     //  Event interface has no properties  
  9. methods:  
  10.     [id(1), helpstring("method ScribbleChange")] void ScribbleChange(VARIANT_BOOL bIsEmpty);  
  11. };  
  12. //头文件  
  13. //同样会自动生成一个id  
  14. // Dispatch and event IDs  
  15. public:  
  16.     enum {  
  17.         dispidScribbleChange = 1L,  
  18. ..............  
  19.     }  
  20. ........  
  21.     void ScribbleChange(VARIANT_BOOL bIsEmpty);  
  22. ........  
  23. //cpp  
  24. // 会自动在函数影射中增加这一条,注释掉没有用  
  25. // Dispatch map  
  26. BEGIN_DISPATCH_MAP(CScribbleCtrl, COleControl)  
  27.     //DISP_FUNCTION_ID(CScribbleCtrl, "ScribbleChange", dispidScribbleChange, ScribbleChange, VT_EMPTY, VTS_BOOL)  
  28. END_DISPATCH_MAP()  
  29. //需要手工在事件映射内添加代码,要不然使用控件的地方得不到事件通知  
  30. // Event map  
  31. BEGIN_EVENT_MAP(CScribbleCtrl, COleControl)  
  32.     EVENT_CUSTOM_ID("ScribbleChange", dispidScribbleChange, ScribbleChange,  VTS_BOOL)  
  33. END_EVENT_MAP()  
  34. // 时间函数实现  
  35. void CScribbleCtrl::ScribbleChange(VARIANT_BOOL bIsEmpty)  
  36. {  
  37.     FireEvent(dispidScribbleChange, EVENT_PARAM(VTS_BOOL), bIsEmpty);   
  38. }  
  39. //如果控件触发了这个事件需要对控件的容器进行事件通知可以直接调用  
  40. {  
  41.     .........  
  42.     ScribbleChange(FALSE);  
  43. }  
 

 

控件响应用户的操作:

一般来说需要响应的是

WM_MOUSEMOVE;WM_LBUTTONDOWN;WM_LBUTTONUP;WM_MOUSELEAVE;WM_RBUTTONDOWN

这里只补充一下关于WM_MOUSELEAVE响应的方法;

首先在MOUSEMOVE函数中使用如下方法让系统通知WM_MOUSELEAVE

[cpp]  view plain copy
  1. if (!m_bSetTrack)  
  2. {  
  3.     TRACKMOUSEEVENT trackm;  
  4.     ZeroMemory(&trackm, sizeof TRACKMOUSEEVENT);  
  5.     trackm.cbSize = sizeof TRACKMOUSEEVENT;  
  6.     trackm.dwFlags = TME_HOVER | TME_LEAVE;  
  7.     trackm.hwndTrack = m_hWnd;  
  8.     m_bSetTrack = TrackMouseEvent(&trackm);  
  9. }  
 

然后在响应WM_MOUSELEAVE消息后把m_bSetTrack变量重置一下即可

 

控件的绘制:

 

 

void OnDraw(CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)

rcBounds为控件绘制大小其实就是控件客户区域,rcInvalid为更新绘制区域

 

 

一般可以使用包装的双缓冲类进行绘制

包装类如下

[cpp]  view plain copy
  1. #ifndef _MEMDC_H_  
  2. #define _MEMDC_H_  
  3. // WTL CMemeryDC for MFC use  
  4. namespace MFC  
  5. {  
  6.     class CMemDC : public CDC  
  7.     {  
  8.     public:  
  9.         // Data members  
  10.         CDC * m_pDCOriginal;  
  11.         RECT m_rcPaint;  
  12.         CBitmap m_bmp;  
  13.         CBitmap* m_pBmpOld;  
  14.         // Constructor/destructor  
  15.         CMemDC(CDC *pDC, const RECT& rcPaint) : m_pDCOriginal(pDC), m_pBmpOld(NULL)  
  16.         {  
  17.             m_rcPaint = rcPaint;  
  18.             CreateCompatibleDC(m_pDCOriginal);  
  19.             ASSERT(m_hDC != NULL);  
  20.             m_bmp .CreateCompatibleBitmap(m_pDCOriginal, m_rcPaint.right - m_rcPaint.left, m_rcPaint.bottom - m_rcPaint.top);  
  21.             ASSERT(m_bmp.m_hObject != NULL);  
  22.             m_pBmpOld = SelectObject(&m_bmp);  
  23.             SetViewportOrg(-m_rcPaint.left, -m_rcPaint.top);  
  24.         }  
  25.         ~CMemDC()  
  26.         {  
  27.             m_pDCOriginal->BitBlt(m_rcPaint.left, m_rcPaint.top, m_rcPaint.right - m_rcPaint.left, m_rcPaint.bottom - m_rcPaint.top, this, m_rcPaint.left, m_rcPaint.top, SRCCOPY);  
  28.             SelectObject(m_pBmpOld);  
  29.         }  
  30.     };  
  31. }  
  32. #endif  
 

 

调用例子

[cpp]  view plain copy
  1. void CScribbleCtrl::OnDraw(  
  2.             CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)  
  3. {  
  4.     if (!pdc)  
  5.         return;  
  6.     // TODO: Replace the following code with your own drawing code.  
  7.     MFC::CMemDC dcMem(pdc, rcInvalid);  
  8.     dcMem.FillSolidRect(rcBounds, RGB(255,255,255));  
  9. // 绘制控件  
  10. .......  
  11. }  
 

 

 

异常处理:

 

控件异常处理一般来说我基本上没有考虑,但是这个肯定是需要的

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值