当前位置:天才代写 > tutorial > C语言/C++ 教程 > 深入C++ Builder之编写本身的元件-深入阐明VCL担任、动静机制(3)

深入C++ Builder之编写本身的元件-深入阐明VCL担任、动静机制(3)

2017-11-05 08:00 星期日 所属: C语言/C++ 教程 浏览:492

副标题#e#

题外话

许多伴侣看了我的前两篇文章后,纷纷来信说能不能先容一些元件入门的基本常识,因为他们基础找不到相关资料,并询问我是如何知道这些常识的。诚然,网上确实没有这方面的先容资料,更况且各人是学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);

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

是否还记得上面的代码?


#p#副标题#e#

或许来说那是函数指针的申明,对付初学者来说,上面的申明真的很艰涩,我来表明一下:THoverShapeEvent是一个函数指针,该函数的返回值是void , 挪用范例是__fastcall,有2个行参,别离是TObject*和int,要害在于赤色的__closure要害字,什么意思?

在BCB的辅佐我我找到了如下说明:

The keyword __closure was added to support the VCL and is used when declaring event handler functions.

就是如此简朴,险些没有提供任何信息,只知道__closure提供对事件处理惩罚函数的支持,下面我来具体先容一下:

不知道你有没有写过这样的代码:

我们设计了一个类,好比遍历磁盘,有一个数据成员是回调函数指针,当我们遍历磁盘的的函数找到了一个文件时挪用这个回调函数,凡是环境下,我们这个回调函数需要申明在类的外面,那么照旧指针需要这样申明:

typedef void __fastcall (*BDCallBack)(String path,int type);

可是这显然不切合OO设计原则,假如你想把一个类的成员函数指定为这个成员函数,那么你将需要这样申明:

typedef void __fastcall (base::* BDCallBack)(String path,int type);

同时你需要这样赋值:

BDCallBack m=&bass::func;

#p#分页标题#e#

语法越来越艰涩了,这还不是最重要的,假如有许多类的成员函数都需要指定为回调函数呢?你需要为每一个类申明一个雷同的函数指针,我想你已经瓦解了。

__closure这个时候就有用武之地了,假如你这样申明:

typedef void __fastcall (__closure *BDCallBack)(String path,int type);

那么所有问题都办理了,它可以利便的透过工具直接会见成员函数,在所有的类中你都可以这样做:

class A
{
BDCallBack func;
Void DoSometing()
{
    …
    func(“Find it”,0);
}
};
class B
{
    Funcb()
    {
        A a;
        a.func=this.callback;
    }
    void __fastcall callback(String path,int type)
    {
    %

 

    关键字:

天才代写-代写联系方式