国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

深入VCL理解BCB的消息機制2

2019-11-17 05:32:44
字體:
來源:轉載
供稿:網友

  重載TControl的WndPRoc方法

還是先談談VCL的繼續策略。VCL中的繼續鏈的頂部是TObject基類。一切的VCL組件和對象都繼續自TObject。

打開BCB幫助查看TControl的繼續關系:

TObject->TPersistent->TComponent->TControl

呵呵,原來TControl是從TPersistent類的子類TComponent類繼續而來的。TPersistent抽象基類具有使用流stream來存取類的屬性的能力。

TComponent類則是所有VCL組件的父類。

這就是所有的VCL組件包括您的自定義組件可以使用dfm文件存取屬性的原因『當然要是TPersistent的子類,我想您很少需要直接從TObject類來派生您的自定義組件吧』。

TControl類的重要性并不亞于它的父類們。在BCB的繼續關系中,TControl類的是所有VCL可視化組件的父類。實際上就是控件的意思吧。所謂可視化是指您可以在運行期間看到和操縱的控件。這類控件所具有的一些基本屬性和方法都在TControl類中進行定義。

TControl的實現在/Borland/CBuilder5/Source/Vcl/control.pas中可以找到。『可能會有朋友問你怎么知道在那里?使用BCB提供的Search -> Find in files很輕易找到。或者使用第三方插件的grep功能。』

好了,進入VCL的源碼吧。說到這里免不了要抱怨一下Borland。哎,為什么要用pascal實現這一切.....:-(

TControl繼續但并沒有重寫TObject的Dispatch()方法。反而提供了一個新的方法就是xycleo提到的WndProc()。一起來看看Borland的工程師們是怎么寫的吧。

procedure TControl.WndProc(var Message: TMessage);
var
  Form: TCustomForm;
begin
//由擁有control的窗體來處理設計期間的消息
  if (csDesigning in ComponentState) then
  begin
    Form := GetParentForm(Self);
    if (Form <> nil) and (Form.Designer <> nil) and
      Form.Designer.IsDesignMsg(Self, Message) then Exit;
  end
//假如需要,鍵盤消息交由擁有control的窗體來處理
  else if (Message.Msg >= WM_KEYFIRST) and (Message.Msg <= WM_KEYLAST) then
  begin
    Form := GetParentForm(Self);
    if (Form <> nil) and Form.WantChildKey(Self, Message) then Exit;
  end
//處理鼠標消息
  else if (Message.Msg >= WM_MOUSEFIRST) and (Message.Msg <= WM_MOUSELAST) then
  begin
    if not (csDoubleClicks in ControlStyle) then
      case Message.Msg of
        WM_LBUTTONDBLCLK, WM_RBUTTONDBLCLK, WM_MBUTTONDBLCLK:
          Dec(Message.Msg, WM_LBUTTONDBLCLK - WM_LBUTTONDOWN);
      end;
    case Message.Msg of
      WM_MOUSEMOVE: application.HintMouseMessage(Self, Message);
      WM_LBUTTONDOWN, WM_LBUTTONDBLCLK:
        begin
          if FDragMode = dmAutomatic then
          begin
            BeginAutoDrag;

            Exit;
          end;
          Include(FControlState, csLButtonDown);
        end;
      WM_LBUTTONUP:
        Exclude(FControlState, csLButtonDown);
    end;
  end
// 下面一行有點非凡。假如您仔細的話會看到這個消息是CM_VISIBLECHANGED.
// 而不是我們熟悉的WM_開頭的標準Windows消息.
// 盡管Borland沒有在它的幫助中提到有這一類的CM消息存在。但很顯然這是BCB的
// 自定義消息。呵呵,假如您對此有愛好可以在VCL源碼中查找相關的內容。一定會有不小的收獲。
  else if Message.Msg = CM_VISIBLECHANGED then
    with Message do
      SendDockNotification(Msg, WParam, LParam);
// 最后調用dispatch方法。
  Dispatch(Message);
end;
看完這段代碼,你會發現TControl類實際上只處理了鼠標消息,沒有處理的消息最后都轉入Dispatch()來處理。

但這里需要強調指出的是TControl自己并沒有獲得焦點Focus的能力。TControl的子類TWinControl才具有這樣的能力。我憑什么這樣講?呵呵,還是打開BCB的幫助。很多朋友抱怨BCB的幫助實在不如VC的MSDN。毋庸諱言,的確差遠了。而且這個幫助還經常有問題。但有總比沒有好啊。

言歸正傳,在幫助的The TWinControl Branch 分支下,您可以看到關于TWinControl類的簡介。指出TWinControl類是所有窗體類控件的基類。所謂窗體類控件指的是這樣一類控件:

1. 可以在程序運行時取得焦點的控件。

2. 其他的控件可以顯示數據,但只有窗體類控件才能和用戶發生鍵盤交互。

3. 窗體類控件能夠包含其他控件(容器)。

4. 包含其他控件的控件又稱做父控件。只有窗體類控件才能夠作為其他控件的父控件。

5. 窗體類控件擁有句柄。

除了能夠接受焦點之外,TWinControl的一切都跟TControl沒什么分別。這一點意味著TwinControl可以對許多的標準事件作出響應,Windows也必須為它分配一個句柄。并且與這個主題相關的最重要的是,這里提到是由BCB負責來對控件進行重畫以及消息處理。這就是說,TwinControl封裝了這一切。

似乎扯的太遠了。但我要提出來的問題是TControl類的WndProc方法中處理了鼠標消息。但這個消息只有它的子類TwinControl才能夠得到啊!?

這怎么可以呢... Borland是如何實現這一切的呢?這個問題實在很奧妙。為了看個究竟,再次深入VCL吧。

還是在control.pas中,TWinControl繼續了TControl的WndProc方法。源碼如下:

procedure TWinControl.WndProc(var Message: TMessage);
var
  Form: TCustomForm;
  KeyState: TKeyboardState;
  WheelMsg: TCMMouseWheel;
begin
  case Message.Msg of
    WM_SETFOCUS:
      begin
        Form := GetParentForm(Self);
        if (Form <> nil) and not Form.SetFocusedControl(Self) then Exit;
      end;
    WM_KILLFOCUS:
      if csFocusing in ControlState then Exit;
    WM_NCH99vTEST:
      begin
        inherited WndProc(Message);
        if (Message.Result = HTTRANSPARENT) and (ControlAtPos(ScreenToClient(

          SmallPointToPoint(TWMNCHitTest(Message).Pos)), False) <> nil) then
          Message.Result := HTCLIENT;
        Exit;
      end;
    WM_MOUSEFIRST..WM_MOUSELAST:
      //下面這一句話指出,鼠標消息實際上轉入IsControlMouseMsg方法來處理了。
      if IsControlMouseMsg(TWMMouse(Message)) then
      begin
        if Message.Result = 0 then
          DefWindowProc(Handle, Message.Msg, Message.wParam, Message.lParam);
        Exit;
      en

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 合川市| 陇川县| 珠海市| 扶余县| 西乌珠穆沁旗| 老河口市| 福安市| 汝南县| 衡阳市| 云龙县| 云林县| 清流县| 阳江市| 赣州市| 孝昌县| 罗江县| 新龙县| 东兰县| 公主岭市| 来宾市| 宿迁市| 岗巴县| 桂平市| 类乌齐县| 河津市| 瑞安市| 阜宁县| 偃师市| 宜兰县| 泾源县| 信丰县| 南投市| 昌黎县| 阜康市| 庆元县| 葫芦岛市| 探索| 饶阳县| 绥滨县| 南宁市| 伊春市|