快速业务通道

深入C++ Builder之编写自己的元件-深入分析VCL继承、消息机制(3)

作者 佚名技术 来源 程序设计 浏览 发布时间 2012-06-30

题外话

很多朋友看了我的前两篇文章后,纷纷来信说能不能介绍一些元件入门的基础知识,因为他们根本找不到相关资料,并询问我是如何知道这些知识的。诚然,网上确实没有这方面的介绍资料,更何况大家是学BCB的,对于Delphi的源代码学习起来更是困难,对于作者来说也不比大家知道多少,我认为最好的方式就是看VCL源代码和去Borland的新闻组提问,至少我是这样解决问题的,希望你也可以。

这里是Borland新闻组地址,如果你英文够好,他们基本是有问必答的:

forums.borland.com

对于那些想学习基础元件知识的朋友,我会在这系列文章的最后部分专门安排2篇文章作为礼物送给你们,一篇是我会实际分析一个专业级元件,来个源代码解剖,把所有细节展示给大家,第二篇是我会实际编写一个简单使用的组件,并介绍全过程,希望大家喜欢。

更多消息处理

已经写了2篇文章了,怎么还是消息处理?是的,编写元件就是处理消息和表露事件,对于一般的消息处理,前面2篇文章介绍的内容已经足够用了,但是很多时候这还是不够的,比如如果在设计时期你更改了元件的Font属性,而你又想根据字体重新绘制。很明显传统的Windows消息处理其不到丝毫作用,这样的消息通常是WM_XXXX的形式。如果你研究过VCL源代码,你会发现很多CN_XXXX和CM_XXXX这样的消息,如果你要完成我上面提到的消息处理,这些消息可以帮助完成任务。

其实,VCL存在一些非API消息以供其内部使用,为什么要这样做呢?这要从WM_COMMAND & WM_NOTIFY消息说起,我们说WM_COMMAND消息并不是直接发给实际产生消息的窗体,而是发送到它的父窗体。但是父窗体几乎不可能用通常方法处理这些根本不知道如何处理的消息,于是父窗体把这个消息加上CN_BASE在分发到实际的子窗体中,然后由实际的子窗体处理。

比如TBitBtn元件为了在按钮表面绘制图象,处理了CN_DRAWITEM消息,这个消息处理函数是这样写的:

FCanvas.Handle := DrawItemStruct.hDC;
  R := ClientRect;

… //省略一部分
  if IsDown then
   OffsetRect(R, 1, 1);
  TButtonGlyph(FGlyph).Draw(FCanvas, R, Point(0,0), Caption, FLayout, FMargin,
   FSpacing, State, False, DrawTextBiDiModeFlags(0));

  if IsFocused and IsDefault then
  begin
   R := ClientRect;
   InflateRect(R, -4, -4);
   FCanvas.Pen.Color := clWindowFrame;
   FCanvas.Brush.Color := clBtnFace;
   DrawFocusRect(FCanvas.Handle, R);
  end;

  FCanvas.Handle := 0;

可以看出这和通常处理Paint的方法差不多,其实都是在HDC上作图。如果你学习过SDK的话,其实我们可以自己处理WM_NOTIFY消息来处理那些由控件产生的消息,只不过VCL替我们封装了一下而已。

还有一些消息是VCL内部控件而产生的,这类消息通常是CM_XXXX的格式,比如CM_FONTCHANGED这个消息就是当字体改变的时候触发,详细的定义你可以在Controls.pas文件中找到,这里就不再详细介绍了

对于上面的CM_FONTCHANGED消息,通常是这样处理的:

procedure TBitBtn.CMFontChanged(var Message: TMessage);

begin

inherited;

Invalidate;

end;

通过上面的讨论,得出一个结论,所有CN/CM消息都可以自己处理,但是他们没有对应的虚函数,所以我们只好用老方法,所以消息映射宏在这里是最好得解决方案,比如像这样:

BEGIN_MESSAGE_MAP

VCL_MESSAGE_HANDLER(CN_DRAWITEM, TWMDrawItem, CNDrawItem)

END_MESSAGE_MAP(TCustomControl)

Void __fastcall CNDrawItem(TWMDrawItem Msg);

定义自己的消息

在上篇文章的结束,我示范了一段元件代码,如果你还记忆犹新的话:

typedef void __fastcall (__closure *THoverShapeEvent)(TObject* Sender,int Index);

type

凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!

分享到: 更多

Copyright ©1999-2011 厦门凌众科技有限公司 厦门优通互联科技开发有限公司 All rights reserved

地址(ADD):厦门软件园二期望海路63号701E(东南融通旁) 邮编(ZIP):361008

电话:0592-5908028 传真:0592-5908039 咨询信箱:web@lingzhong.cn 咨询OICQ:173723134

《中华人民共和国增值电信业务经营许可证》闽B2-20100024  ICP备案:闽ICP备05037997号