ActiveX控件的MFC设计之旅

发布时间 : 星期四 文章ActiveX控件的MFC设计之旅更新完毕开始阅读

if(m_pctrl) return m_pctrl->m_saItems.GetSize(); return 0; }

4.编译,新建一VB工程,在 VB下测试,可以发现没有问题

5.在ActiveX Control Container下测试,咦,出问题了,没有反应,为什么?

根据最后给出的资料上中的意思,大致是因为容器聚合了控件的原因(呵呵,懒得去想了,有兴趣的自己思考吧)

6.为控件添加一只读属性long CtrlPtr long CToppCtrl::GetCtrlPtr() {

// TODO: Add your property handler here return reinterpret_cast(this); return 0; }

7.编译,在ClassWizard的Automation下,点击Add Class,然后选择From a type library,找到编译时为控件生成的.tlb文件,这里应该是在\\Debug目录下,选择这个topp.tlb,然后只选择其中的_DTopp,点确定,这样将生成一个_DTopp类,和我们上一步中的介绍比较一下,可以发现,其实就是派生自一个COleDispatchDriver类,也就是说,只是一个帮助我们调用控件属性和方法的类(也就是说,我们上一步中其实完全不用自己来编代码的,ClassWizard可以为我们生成一个方便的可操作的类:))。

8.修改属性页的GetCtrlPtr函数如下: CToppCtrl* CToppPropPage::GetCtrlPtr() {

ULONG ulObjects;

LPDISPATCH* lpObjectArray = GetObjectArray( &ulObjects ); ASSERT( lpObjectArray != NULL ); LPDISPATCH lpdisp = NULL;

if(ulObjects > 0){//在这个函数中,并不一定能保证就有控件.

lpdisp = lpObjectArray[0];//这里省事了,就假设只有一个控件了 }

CToppCtrl* pctrl = NULL; if(lpdisp){

pctrl = (CToppCtrl*)CCmdTarget::FromIDispatch(lpdisp); if(!pctrl){

long ControlPointer; _DTopp control(lpdisp);

// GetObjectArray() docs state must not release pointer. control.m_bAutoRelease = FALSE; ControlPointer = control.GetCtrlPtr();

pctrl = reinterpret_cast(ControlPointer);

//这里其实可以简单用如下的方法调用,之所以用上面的方法,只是用来介绍而已

/* long p;

GetPropText(\

pctrl = reinterpret_cast(p); */ } }

return pctrl; }

9.编译,在ActiveX Control Container中测试,OK! 注释:这里用ClassWizard导入了一个辅助类是用来帮助从IDispatch中获得控件的CtrlPtr属性值的,其实并不一定需要这个辅助类的,见CToppCtrl* CToppPropPage::GetCtrlPtr()函数中被注释掉的代码,之所以引入这个辅助类,也是介绍起见。

参考资料:

http://support.microsoft.com/kb/205670/

一般情况下,我们在设计状态下设计控件时,会打开属性页,然后输入几个值,来初始化控件,然后关闭属性页,这样在属性页中输入的值就保存起来了,然后下次再打开属性页,这些值又会加载进来,这个过程有个术语叫持久化。

从表面上看,控件的持久化是在属性页中完成的呢,但事实上控件的持久化需要各方的配合,最终是由控件的容器来完成真正的持久化操作(保存或加载到某种介质,如磁盘文件等)。

属性页在控件的持久化中并没有做多少的工作,它的主要工作是获得和设置控件的属性(有时候可能会调用控件的方法等),在MFC中,一般基本上是在DoDataExchange中完成的(加载控件的时候会调用,保存控件的时候也会调用),有时候,可能会在其它地方完成,前面几步已经讲了在其它地方访问控件属性的方法了。

控件做了大部分的持久化工作,在MFC中,它们是在DoPropExchange中完成的。MFC提供了下面的一些函数来帮助完成持久化工作

BOOL AFX_CDECL PX_Short(CPropExchange* pPX, LPCTSTR pszPropName, short& sValue); BOOL AFX_CDECL PX_Short(CPropExchange* pPX, LPCTSTR pszPropName, short& sValue, short sDefault);

BOOL AFX_CDECL PX_UShort(CPropExchange* pPX, LPCTSTR pszPropName, USHORT& usValue); BOOL AFX_CDECL PX_UShort(CPropExchange* pPX, LPCTSTR pszPropName, USHORT& usValue, USHORT usDefault);

BOOL AFX_CDECL PX_Long(CPropExchange* pPX, LPCTSTR pszPropName, long& lValue); BOOL AFX_CDECL PX_Long(CPropExchange* pPX, LPCTSTR pszPropName, long& lValue, long lDefault);

BOOL AFX_CDECL PX_ULong(CPropExchange* pPX, LPCTSTR pszPropName, ULONG& ulValue);

BOOL AFX_CDECL PX_ULong(CPropExchange* pPX, LPCTSTR pszPropName, ULONG& ulValue, ULONG ulDefault);

BOOL AFX_CDECL PX_Color(CPropExchange* pPX, LPCTSTR pszPropName, OLE_COLOR& clrValue);

BOOL AFX_CDECL PX_Color(CPropExchange* pPX, LPCTSTR pszPropName, OLE_COLOR& clrValue, OLE_COLOR clrDefault);

BOOL AFX_CDECL PX_Bool(CPropExchange* pPX, LPCTSTR pszPropName, BOOL& bValue); BOOL AFX_CDECL PX_Bool(CPropExchange* pPX, LPCTSTR pszPropName, BOOL& bValue, BOOL bDefault);

BOOL AFX_CDECL PX_String(CPropExchange* pPX, LPCTSTR pszPropName, CString& strValue); BOOL AFX_CDECL PX_String(CPropExchange* pPX, LPCTSTR pszPropName, CString& strValue, const CString& strDefault);

BOOL AFX_CDECL PX_String(CPropExchange* pPX, LPCTSTR pszPropName, CString& strValue, LPCTSTR lpszDefault);

BOOL AFX_CDECL PX_Currency(CPropExchange* pPX, LPCTSTR pszPropName, CY& cyValue); BOOL AFX_CDECL PX_Currency(CPropExchange* pPX, LPCTSTR pszPropName, CY& cyValue, CY cyDefault);

BOOL AFX_CDECL PX_Float(CPropExchange* pPX, LPCTSTR pszPropName, float& floatValue); BOOL AFX_CDECL PX_Float(CPropExchange* pPX, LPCTSTR pszPropName, float& floatValue, float floatDefault);

BOOL AFX_CDECL PX_Double(CPropExchange* pPX, LPCTSTR pszPropName, double& doubleValue);

BOOL AFX_CDECL PX_Double(CPropExchange* pPX, LPCTSTR pszPropName, double& doubleValue,

double doubleDefault);

BOOL AFX_CDECL PX_Blob(CPropExchange* pPX, LPCTSTR pszPropName, HGLOBAL& hBlob, HGLOBAL hBlobDefault = NULL);

BOOL AFX_CDECL PX_Font(CPropExchange* pPX, LPCTSTR pszPropName, CFontHolder& font, const FONTDESC* pFontDesc = NULL, LPFONTDISP pFontDispAmbient = NULL);

BOOL AFX_CDECL PX_Picture(CPropExchange* pPX, LPCTSTR pszPropName, CPictureHolder& pict);

BOOL AFX_CDECL PX_Picture(CPropExchange* pPX, LPCTSTR pszPropName, CPictureHolder& pict, CPictureHolder& pictDefault);

BOOL AFX_CDECL PX_IUnknown(CPropExchange* pPX, LPCTSTR pszPropName, LPUNKNOWN& pUnk,

REFIID iid, LPUNKNOWN pUnkDefault = NULL);

BOOL AFX_CDECL PX_VBXFontConvert(CPropExchange* pPX, CFontHolder& font); BOOL AFX_CDECL PX_DataPath(CPropExchange* pPX, LPCTSTR pszPropName, CDataPathProperty& dataPathProp, LPCTSTR pszDefault = NULL);

BOOL AFX_CDECL PX_DataPath(CPropExchange* pPX, LPCTSTR pszPropName, CDataPathProperty& dataPathProp, const CString& strDefault);

看起来很多,其实最终都是调用到了CPropExchange的几个函数

virtual BOOL ExchangeVersion(DWORD& dwVersionLoaded, DWORD dwVersionDefault, BOOL bConvert);

virtual BOOL ExchangeProp(LPCTSTR pszPropName, VARTYPE vtProp, void* pvProp, const void* pvDefault = NULL) = 0;

virtual BOOL ExchangeBlobProp(LPCTSTR pszPropName, HGLOBAL* phBlob, HGLOBAL hBlobDefault = NULL) = 0;

virtual BOOL ExchangeFontProp(LPCTSTR pszPropName, CFontHolder& font, const FONTDESC* pFontDesc,

LPFONTDISP pFontDispAmbient) = 0;

virtual BOOL ExchangePersistentProp(LPCTSTR pszPropName,

LPUNKNOWN* ppUnk, REFIID iid, LPUNKNOWN pUnkDefault) = 0;

或者更确切些说,只有三个比较重要的,其它的也都是简单的调用下面三个函数的 ExchangeProp,ExchangeBlobProp,ExchangePersistentProp

好象有点说远了,回到主题:一般的属性持久化,就不多说了,这里要说的是无法用普通属性的方法来持久化的控件中的信息,该如何持久化呢。

我们来看上一步中的例子topp,我想持久化里面的字符串数组,怎么办呢?

办法是有的,用PX_Blob,可以说,PX_Blob几乎能持久化任何你想要持久化的信息。 首先,为了能看到持久化后的效果,我们来稍微调整一下控件

1.添加OnDraw代码,以显示一个以Color属性为底色的背景,然后一行一行显示所有的字符串,有几个字符串就显示几行 void CToppCtrl::OnDraw(

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

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

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

pdc->FillRect(&rcBounds, &CBrush(TranslateColor(m_color))); int nhei = 18; int y = 2;

for(int i=0; i

CRect rect(rcBounds.left + 4, y+2, rcBounds.right - 4, y + nhei); pdc->FillRect(&rect, &CBrush(RGB(255, 255, 255))); pdc->TextOut(rcBounds.left + 4, y + 2, m_saItems); } }

2.调整几个控件的属性代码,以便更改属性时,能反应到界面上来,说白了,就是加几个InvaldiateControl()

void CToppCtrl::OnColorChanged() {

// TODO: Add notification handler code InvalidateControl();

联系合同范文客服:xxxxx#qq.com(#替换为@)