ActiveX的MFC设计之旅-第2步 .
我晕,就因为我没写摘要,也不至于把我写的这一大段给全删没了吧,这Blog也做的太菜了吧
前面说要转向属性页,突然想起好象还有一个比较有意思的东东没看,所以就先不转了,再往前走那么一小步吧
这次要看的是枚举 在VB中,我们会看到,好多控件在编辑代码的时候,会列出某一属性,或方法参数的许多可选值来,如 ListView1.BorderStyle =写到这时就会列出来ccFixedSingle和ccNone两个可选项来 它们是怎么来的呢,是的,就是枚举 在C++中,枚举的使用是很简单的,抄msdn上一段 enum Days // Declare enum type Days { saturday,// saturday = 0 by default sunday = 0,// sunday = 0 as well monday,// monday = 1 tuesday,// tuesday = 2 wednesday,// etc. thursday, friday } today; 那么这里我们要怎么弄呢,也象上面一样用吗?用到哪? 用关键字enum查查msdn就能查到用法了,下面是msdn中的一个例子 typedef [uuid(DEADF00D-C0DE-B1FF-F001-A100FF001ED),helpstring("Farm Animals are friendly"),helpcontext(234)] enum { [helpstring("Moo")] cows = 1,pigs = 2 } ANIMALS;在例子中,我们现在要加上一个滚动条,滚动条的枚举共4个,none,horz,vert和both 1.使用VC的Guid工具,(不出意外的话,在Tools菜单下就能找到)生成一个GUID,拷贝下来 2.打开LiteGrid.odl,在ICell接口的前面(之所以要加到前面,是因为这些枚举,可能其它接口会用到)加上 typedef [ uuid(C9A2BD1A-AEA5-459a-BA59-5C8C3C01E403) ] enum { lgnone = 0, lghorz = 1, lgvert = 2, lgboth = 3 } lgScroll; 上面的uuid是我生成的,如果不幸有哪位朋友也跟着想试试,请用自己生成的UUID 3.接下来定义一个属性ScrollBars,定义的时候,你并不能找到lgScroll类型,所以可以用long类型 4.接着在LiteGrid.odl中找到ScrollBars属性,将它的long类型改为lgScroll 5.编译,在VB中试试,是不是列出来了 就这么简单了 6.不过好象设置这些值没有用,当然了,没有实现代码啊,在OnScrollBarsChanged加上 if(!::IsWindow(m_hWnd)) return; long l = GetWindowLong(m_hWnd,GWL_STYLE); if(m_scrollBars & 0x01){ l |= WS_HSCROLL; } else{ l &= ~WS_HSCROLL; } if(m_scrollBars & 0x02){ l |= WS_VSCROLL; } else{ l &= ~WS_VSCROLL; } SetWindowLong(m_hWnd,GWL_STYLE,l); SetWindowPos(NULL,SWP_NOMOVE | SWP_NOZORDER | SWP_NOSIZE | SWP_FRAMECHANGED); SetModifiedFlag(); 再编译,再试,出来了吧 呵呵,这一步就走到这了,要下班了,88了
那么这回就来看一下网上说的挺多的传递自定义结构的问题吧,这个问题在早期不支持DCOM的操作系统中是没办法解决的,不过就目前的流行操作系统来说,应该是不成问题的。
其实网上讨论很多的,不过还是推荐一些网址: 第一个是微软的msdn,应该蛮正宗的吧,http://windowssdk.msdn.microsoft.com/library/default.asp?url=/library/en-us/Automat/htm/chap12_3rcj.asp 第二个是我偶尔看到的,在csdn上,感觉蛮不错的,中文的嘛,呵呵 http://dev.csdn.net/article/67/67955.shtm 其它的稀奇古怪的就不说了,各位可以自己网上搜搜,一大把的 那咱就照着这些资料开始我们自己的自定义结构的传递了,我们要定义的结构是RECT,用来确定Cell的尺寸位置,在VC中已经有了结构RECT,但是VB中却没有,没关系,我们自己给它定义一个。 1.打开LiteGrid.odl文件,在ICell接口的定义前面(其它位置也没关系)加上 typedef [ uuid(6BF5EE0C-373A-4893-89EB-2C0208D3D4EB) ] struct tagtRECT { long left; long top; long right; long bottom; }Rect; UUID用GUID生成工具生成,就不多说了了,以后也不说了 这里本来用tagRECT的,结果居然提示说有重复定义,同样也没用RECT,而用Rect了。 2.为CCell添加成员变量CRect m_rect;在构造函数中初始化为{0,0} 3.为CCell添加Get/Set属性Rect,类型为VARIANT 4.在LiteGrid.odl中,将该属性的类型VARIANT改为Rect 5.Get/Set函数定义如下: void CCell::SetRect(const VARIANT FAR& newValue) { // TODO: Add your property handler here COleVariant ar(newValue); if(ar.vt == VT_RECORD){ IRecordInfo* pri = ar.pRecInfo; pri->RecordCopy(ar.pvRecord,(PVOID)&m_rect); } } VARIANT CCell::GetRect() { VARIANT vaResult; VariantInit(&vaResult); // TODO: Add your property handler here IRecordInfo* pRecInfo = NULL; GetRecordInfoFromGuids(GUID_Lib,1,LOCALE_USER_DEFAULT,GUID_Rect,&pRecInfo); vaResult.vt = VT_RECORD; vaResult.pvRecord = (PVOID)&m_rect; vaResult.pRecInfo = pRecInfo; return vaResult; } 6.编译通过 7.新建VB工程,添加LiteGrid控件,在Form_Load中添加代码如下: Dim rc As Rect Dim rc1 As Rect Dim ce As Cell Set ce = LiteGrid1.Cell(0,0) If Not ce Is Nothing Then rc = ce.Rect ce.Rect.Left = 100 rc = ce.Rect rc.Left = 10 rc.Top = 29 rc.Right = 12 rc.bottom = 439 ce.Rect = rc rc1 = ce.Rect End If 运行观察一下几次rc和rc1的值,可以发现结果完全正确 OK,搞定 但是,不知道什么原因,从控件调试环境运行时,却发现以上代码调试出错,只保留rc = ce.Rect或只保留ce.Rect = rc代码时却不会出错,不知何原因,郁闷。 另外,对于GetRect中的pRecordInfo,不知是否需要Release,有待确定。 嘿嘿,咱不管了,懒得弄了,继续旅程了。
到目前为止,我们的例子中都没有一点Grid的影子,这趟改造一下程序,稍微能象点样,顺便加上一个也蛮流行的话题,传递数组问题,或者说是SAFEARRAY吧
struct SAFEARRAY { 基本上它的操作函数也就是对这个结构的操作了 SAFEARRAY * SafeArrayCreate(VARTYPE vt,UINT cDims,SAFEARRAYBOUND * aDims); 这组函数不用多说了,建立一个SAFEARRAY,不过这个函数有个缺陷,它只能处理类型是VARIANT类型子集中的元素。 HRESULT SafeArrayAllocDescriptor(UINT cDims,SAFEARRAY ** ppsaOut); 这组函数就提供了更多,更灵活的元素类型,但是用起来就稍微复杂一些了,何况一般在COM中也用不了这种复杂的数据类型。 HRESULT SafeArrayLock(SAFEARRAY * psa); 这组函数只是对结构中cLocks值+1和-1,为什么要用这组函数,目前为止好象也不是非常理解,可能是为了防止在操作数据时删除数组吧,另外在已经 SafeArrayLock后,还可以再在其它地方SafeArrayLock来对数组进行操作,只要记得用完后SafeArrayUnlcok一下就可 以了。 HRESULT SafeArrayGetElement(SAFEARRAY * psa,long * aiIndex,void * pvElem); 这组函数是得到数组中的某一个值,aiIndex就是下标索引了,这组函数在每次调用的时候都自动调用SafeArrayLock和 SafeArrayUnlock,所以在需要遍历数组中的元素时,最好先用SafeArrayLock,再直接操作数据,最后用 SafeArrayUnlock。该组函数的用法举例如下: HRESULT SafeArrayPtrOfIndex(SAFEARRAY * psa,void ** ppv); 这个函数主要用在多维数组中,一维数组可以用,不过没什么意思吧,这个函数其实和SafeArrayGetElement类似,不过是一个有Lock,一个没Lock,所以用这个函数前,最好先SafeArrayLock一下,用完了,再SafeArrayUnlock。 HRESULT SafeArrayAccessData (SAFEARRAY * psa,void ** ppvData); 这组函数只是简单的Lock和Unlock,加上返回SAFEARRAY结构的pvData成员而已,并不包含维数信息,所以,想不出什么理由来使用它,当然要使用那也是你的事。(这是文摘中的话,个人觉得在用一维数组时,这组函数非常有用) UINT SafeArrayGetDim(SAFEARRAY * psa); 这两个函数,第一个返回数组的维数,第二个返回数组中每个元素的大小,比如long就是4了。 6.在VB的Form_Load中添加如下代码 运行后可以发现10*10个网格,每个网格上都有纵横坐标字样 这篇好象稍微长了些,主要是SAFEARRAY的用法解释的多了些,应该不会烦到哪去吧。那就到这里了。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |