程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> Delphi 組件開發教程指南(4)組件生成過程(針對TWinControl繼承而來的組件)

Delphi 組件開發教程指南(4)組件生成過程(針對TWinControl繼承而來的組件)

編輯:Delphi

  還記得在第二章的時候,我用到了procedure CreateParams(var Params: TCreateParams);這個函數的吧!為什麼我會使用這個函數來實現那個對齊的問題呢!現在就來追根底的來看看!這個過程其實是在構建窗口的時候會調用的,當然我說的這個是針對TWincontrol繼承過來的組件說的,從TGraphicontrol等繼承過來的是沒有這個的。這個函數的產生也是Windows組件庫所特有的,如果列為看官有Windows編程的基礎,那麼這個就很容易理解了,記得,在Windows編程的時,注冊這個窗口類之前,我們都會為一個窗口類指定一系列的參數,而這個CreateParams函數就是產生在這個注冊過程之前,目的是用來為創建過程指定參數。

  在講CreateParams的來源之前,我們必須簡略說說組件由生成到顯示在用戶面前的這個過程。這是個灰常糾結的問題,糾結到我不曉得怎麼去說(當然糾結的主要原因還是本人的水平有限,下面大家就簡單看看吧,解說可能有錯,歡迎指正)。由於組件都是依托於Form之上的,所以組件要顯示出來最首要的是要組件所依托的容器顯示出來,那麼最首要,我們需要看看Form的創建然後顯示出來的過程。至於窗口的創建過程可以參考一下黃叉叉的博客,在這裡我在給他的細化一下,便於我們的工作的展開!這個細化應該是在他那個說明的第5步之前,也就是他說的

此處說明一下:

    對 TWinControl 的 Handle 屬性的讀取會觸發 TWinControl.GetHandle;

 可以察看 Property Handle; 的聲明。  

 5、第四步中對 Handle 進行讀取,觸發下述序列:(TWinControl)

     Handle->GetHandle->HandleNeeded   

這個HandleNeeded是在什麼時候第一次調用的,其實他不是在GetHandle的時候第一次調用的,而是在窗口顯示出來之前,也就是 Visible變化的過程中第一次調用的,而這個Visible的變化,是在Delphi讀取Form資源文件的屬性了之後觸發(這個屬性讀取過程,可以參考Delphi 的持續機制淺探)。我們看看Visible這個屬性變化所觸發的過程,這個屬性定義在TControl中,屬性變化對應的過程為

procedure TControl.SetVisible(Value: Boolean);
begin
 if FVisible <> Value then
 begin
  VisibleChanging;
  FVisible := Value;
  Perform(CM_VISIBLECHANGED, Ord(Value), 0);
  RequestAlign;
 end;
end;

  由此可以看到在屬性變化的時候發送了一個CM_VISIBLECHANGE的消息出去,然後我們再去這個消息的觸發過程

procedure TWinControl.CMVisibleChanged(var Message: TMessage);
begin
 if not FVisible and (Parent <> nil) then RemoveFocus(False);
 if not (csDesigning in ComponentState) or
  (csNoDesignVisible in ControlStyle) then UpdateControlState;
end;

  本過程在TControl中也有,但是在TWinControl中被重寫了,所以我這裡只列出了TWinControl的,在Visible變化的時候會調用UpdateControlState函數來更新控件狀態,然後這個更新過程中調用了另外一個更新控件顯示的函數UpdateShowing,我們來看看UpdateShowing這個過程

procedure TWinControl.UpdateShowing;
var
 ShowControl: Boolean;
 I: Integer;
begin
 ShowControl := (FVisible and (not (csDesigning in ComponentState) or not (csDesignerHide in ControlState)) or
  ((csDesigning in ComponentState) and not (csDesignerHide in ControlState)) and
  not (csNoDesignVisible in ControlStyle)) and
  not (csReadingState in ControlState) and not (csDestroying in ComponentState);
 if ShowControl then
 begin //這個時候如果是第一次顯示,FHandle為0,就會調用CreateHandle來創建一個窗口句柄了,也就是說
 //在這個時候才真真實實的創建Windows的標准控件!
  if FHandle = 0 then CreateHandle;
  if FWinControls <> nil then
   for I := 0 to FWinControls.Count - 1 do
    TWinControl(FWinControls[I]).UpdateShowing;//之後會更新屬於這個控件容器的所有子控件顯示
 end;
 if FHandle <> 0 then
  if FShowing <> ShowControl then
  begin
   FShowing := ShowControl;
   try
    SetPerformingShowingChanged(Self);
    try
     Perform(CM_SHOWINGCHANGED, 0, 0);
    finally
     ClearPerformingShowingChanged(Self);
    end;
   except
    FShowing := not ShowControl;
    raise;
   end;
  end;
end;

  CreateHandle過程中調用了CreateWnd,然後CreateWnd得時候就調用我們上面聲明的CreateParams來為標准控件傳遞參數。上面說了控件的最終容器Form的創建到顯示過程,那麼我們現在再來說說一般控件的創建顯示過程,其實也就和TForm的創建顯示過程一樣!只是 TForm的顯示從讀取了屬性之後觸發,而一般控件由他所在的容器觸發,也就是上面的UpdateShowing過程中的實現過程,後面會遍歷子控件,然後更新他們的顯示,第一次顯示的時候都會觸發CreateHandle的過程,所以Windows組件的真實創建過程實際上應該是在組件的第一次顯示的過程中創建,而不是我們調用Create的時候,在Delphi中,我們Create的時候,僅僅是為這個組件提供了一些初始化信息以及各種參數而已。說到這裡,那麼,第二章中的CreateParams的實現方法也就相當順其自然了,因為在CreateParams中為Edit指定其他的擴展樣式時,實際上Windows的真實Edit控件實際上還沒有創建出來。那麼當指定了新樣式,當他創建出來的時候,就自然具備了我們指定的擴展樣式了。然後,我在設置新樣式的時候,調用了一個RecreateWnd的方法,這個方法的目的是重建句柄,也就是重建Windows組件,這個函數的實現過程相當簡單,僅僅就是發送了一個組件重建的消息CM_RECREATEWND,然後我們看看這個消息過程的實現方法

procedure TWinControl.CMRecreateWnd(var Message: TMessage);
var
 WasFocused: Boolean;
begin
 WasFocused := Focused;//先保存控件是否是焦點狀態
 UpdateRecreatingFlag(True);//這個函數,我就不貼他的代碼了,從他的代碼中,我們可以看出來,這個函數
 //的目的是為所有的子控件打上重建的標記
 try
  DestroyHandle;//釋放句柄,同時釋放所有子控件的句柄
  UpdateControlState;//更新控件狀態,這個函數上面已經分析,會建立句柄,同時子控件句柄。
 finally
  UpdateRecreatingFlag(False);//重建狀態完成
 end;
 if WasFocused and (FHandle <> 0) then
  Windows.SetFocus(FHandle);//如果重建成功,並且原先有焦點,就恢復原先的焦點狀態
end;


  可見,這個重建的過程,如果你是一個容器控件,內部有很多子控件的話,使用這個方式來實現某些效果,效率是灰常低下的,所以容器類不建議頻繁使用重建方法!

  至此為止,組件的生成過程就講解完畢,歡迎專家指正!

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved