您的位置:首页 > 其它

关于ActiveX Control开发总结 MFC篇

2015-05-19 15:43 204 查看
为了方便的移植及重用自己编写的控件,这时候我们就要用到ActiveX控件技术来封装自己的控件类。

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

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

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

3、控件事件的通知。

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

5、控件的绘制。

6、异常处理。

添加用户设置属性方法:

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

在idl文件自动生成代码:

[cpp] view
plaincopy

library ScribbleLib

{

importlib(STDOLE_TLB);

// Primary dispatch interface for CScribbleCtrl

[ uuid(9B217CBB-3D90-444A-898B-271B9EF1B36A),

helpstring("Dispatch interface for Scribble Control")]

dispinterface _DScribble

{

properties:

[id(1) , helpstring("画笔颜色")] OLE_COLOR PenColor;

methods:

};

如果需要怎加自定义的枚举属性可以在之前定义

[cpp] view
plaincopy

#include <olectl.h>

#include <idispids.h>

typedef enum { Blank, SmallGrid, MediumGrid, LargeGrid } GridType;

[

uuid(0A33EFF3-46C9-4B38-B2DC-05C42C99D093), version(1.0),

helpfile("Scribble.hlp"),

helpstring("Scribble ActiveX Control module"),

control

]

............

属性这样声明:

[cpp] view
plaincopy

properties:

[id(1) , helpstring("画笔颜色")] OLE_COLOR PenColor;

[id(2) , helpstring("显示网格")] GridType ShowGird;

...........

在控件头文件中生成代码

[cpp] view
plaincopy

class CScribbleCtrl : public COleControl

{

DECLARE_DYNCREATE(CScribbleCtrl)

// Constructor

public:

CScribbleCtrl();

// Implementation

protected:

~CScribbleCtrl();

.......................

// Dispatch and event IDs

public:

enum {

dispidShowGird = 2,

dispidPenColor = 1

};

protected:

// 根据向导的选择如果选择get/put则生成get/put函数,选择变量形式则为当前代码

OLE_COLOR m_PenColor;

void OnPenColorChanged(void);

USHORT m_ShowGird;

void OnShowGirdChanged(void);

.................................

};

在控件cpp文件中生成代码

[cpp] view
plaincopy

// Dispatch map

BEGIN_DISPATCH_MAP(CScribbleCtrl, COleControl)

DISP_PROPERTY_NOTIFY_ID(CScribbleCtrl, "ShowGird", dispidShowGird, m_ShowGird, OnShowGirdChanged, VT_UI2)

DISP_PROPERTY_NOTIFY_ID(CScribbleCtrl, "PenColor", dispidPenColor, m_PenColor, OnPenColorChanged, VT_COLOR)

DISP_PROPERTY_NOTIFY_ID(CScribbleCtrl, "DrawPen", dispiddrawPen, m_DrawPen, OndrawPenChanged, VT_UI2)

END_DISPATCH_MAP()

// CScribbleCtrl::DoPropExchange - Persistence support

void CScribbleCtrl::DoPropExchange(CPropExchange* pPX)

{

ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));

COleControl::DoPropExchange(pPX);

// 绑定控件属性默认值,显示在控件属性页中

PX_UShort(pPX, _T("ShowGird"), m_ShowGird, Blank);

PX_Color(pPX, _T("PenColor"), m_PenColor, RGB(0, 0, 0));

if (pPX->IsLoading())

{

// 加载用户在控件属性页中设置的控件属性值

}

}

// CScribbleCtrl message handlers

void CScribbleCtrl::OnShowGirdChanged(void)

{

Refresh(); // 刷新控件

}

void CScribbleCtrl::OnPenColorChanged(void)

{

}

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

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

[cpp] view
plaincopy

// idl 代码段

dispinterface _DScribble

{

properties:

......................

methods:

[id(3), helpstring("method GetScribbleBmp")] ULONG GetScribbleHBITMAP(void);

.......................

//头文件代码段

.......................

// Dispatch and event IDs

public:

enum {

dispidGetScribbleBmp = 4L,

dispidPenColor = 2,

dispidShowGird = 1

};

........................

protected:

ULONG GetScribbleHBITMAP(void);

.......................

//cpp文件代码段

........................

// Dispatch map

BEGIN_DISPATCH_MAP(CScribbleCtrl, COleControl)

.....................

DISP_FUNCTION_ID(CScribbleCtrl, "GetScribbleHBITMAP", dispidGetScribbleBmp, GetScribbleHBITMAP, VT_UI4, VTS_NONE)

END_DISPATCH_MAP()

ULONG CScribbleCtrl::GetScribbleHBITMAP(void)

{

.............

}

.............

添加控件事件的通知

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

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

事件映射宏如下:

[cpp] view
plaincopy

EVENT_STOCK_CLICK()

EVENT_STOCK_DBLCLICK()

EVENT_STOCK_KEYDOWN()

EVENT_STOCK_KEYPRESS()

EVENT_STOCK_KEYUP()

EVENT_STOCK_MOUSEDOWN()

EVENT_STOCK_MOUSEMOVE()

EVENT_STOCK_MOUSEUP()

EVENT_STOCK_ERROREVENT()

EVENT_STOCK_READYSTATECHANGE()

函数原型

[cpp] view
plaincopy

// Firing functions for stock events

void FireKeyDown(USHORT* pnChar, short nShiftState);

void FireKeyUp(USHORT* pnChar, short nShiftState);

void FireKeyPress(USHORT* pnChar);

void FireMouseDown(short nButton, short nShiftState,

OLE_XPOS_PIXELS x, OLE_YPOS_PIXELS y);

void FireMouseUp(short nButton, short nShiftState,

OLE_XPOS_PIXELS x, OLE_YPOS_PIXELS y);

void FireMouseMove(short nButton, short nShiftState,

OLE_XPOS_PIXELS x, OLE_YPOS_PIXELS y);

void FireClick();

void FireDblClick();

void FireError(SCODE scode, LPCTSTR lpszDescription, UINT nHelpID = 0);

void FireReadyStateChange();

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

[cpp] view
plaincopy

//idl代码段

// Event dispatch interface for CScribbleCtrl

[ uuid(DA9841E5-98B9-4674-939E-8EC6BEE35273),

helpstring("Event interface for Scribble Control") ]

dispinterface _DScribbleEvents

{

properties:

// Event interface has no properties

methods:

[id(1), helpstring("method ScribbleChange")] void ScribbleChange(VARIANT_BOOL bIsEmpty);

};

//头文件

//同样会自动生成一个id

// Dispatch and event IDs

public:

enum {

dispidScribbleChange = 1L,

..............

}

........

void ScribbleChange(VARIANT_BOOL bIsEmpty);

........

//cpp

// 会自动在函数影射中增加这一条,注释掉没有用

// Dispatch map

BEGIN_DISPATCH_MAP(CScribbleCtrl, COleControl)

//DISP_FUNCTION_ID(CScribbleCtrl, "ScribbleChange", dispidScribbleChange, ScribbleChange, VT_EMPTY, VTS_BOOL)

END_DISPATCH_MAP()

//需要手工在事件映射内添加代码,要不然使用控件的地方得不到事件通知

// Event map

BEGIN_EVENT_MAP(CScribbleCtrl, COleControl)

EVENT_CUSTOM_ID("ScribbleChange", dispidScribbleChange, ScribbleChange, VTS_BOOL)

END_EVENT_MAP()

// 时间函数实现

void CScribbleCtrl::ScribbleChange(VARIANT_BOOL bIsEmpty)

{

FireEvent(dispidScribbleChange, EVENT_PARAM(VTS_BOOL), bIsEmpty);

}

//如果控件触发了这个事件需要对控件的容器进行事件通知可以直接调用

{

.........

ScribbleChange(FALSE);

}

控件响应用户的操作:

一般来说需要响应的是

WM_MOUSEMOVE;WM_LBUTTONDOWN;WM_LBUTTONUP;WM_MOUSELEAVE;WM_RBUTTONDOWN

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

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

[cpp] view
plaincopy

if (!m_bSetTrack)

{

TRACKMOUSEEVENT trackm;

ZeroMemory(&trackm, sizeof TRACKMOUSEEVENT);

trackm.cbSize = sizeof TRACKMOUSEEVENT;

trackm.dwFlags = TME_HOVER | TME_LEAVE;

trackm.hwndTrack = m_hWnd;

m_bSetTrack = TrackMouseEvent(&trackm);

}

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

控件的绘制:

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

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

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

包装类如下

[cpp] view
plaincopy

#ifndef _MEMDC_H_

#define _MEMDC_H_

// WTL CMemeryDC for MFC use

namespace MFC

{

class CMemDC : public CDC

{

public:

// Data members

CDC * m_pDCOriginal;

RECT m_rcPaint;

CBitmap m_bmp;

CBitmap* m_pBmpOld;

// Constructor/destructor

CMemDC(CDC *pDC, const RECT& rcPaint) : m_pDCOriginal(pDC), m_pBmpOld(NULL)

{

m_rcPaint = rcPaint;

CreateCompatibleDC(m_pDCOriginal);

ASSERT(m_hDC != NULL);

m_bmp .CreateCompatibleBitmap(m_pDCOriginal, m_rcPaint.right - m_rcPaint.left, m_rcPaint.bottom - m_rcPaint.top);

ASSERT(m_bmp.m_hObject != NULL);

m_pBmpOld = SelectObject(&m_bmp);

SetViewportOrg(-m_rcPaint.left, -m_rcPaint.top);

}

~CMemDC()

{

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);

SelectObject(m_pBmpOld);

}

};

}

#endif

调用例子

[cpp] view
plaincopy

void CScribbleCtrl::OnDraw(

CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)

{

if (!pdc)

return;

// TODO: Replace the following code with your own drawing code.

MFC::CMemDC dcMem(pdc, rcInvalid);

dcMem.FillSolidRect(rcBounds, RGB(255,255,255));

// 绘制控件

.......

}

异常处理:

控件异常处理一般来说我基本上没有考虑,但是这个肯定是需要的
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: