2011-07-06 27 views
2

我有一個包含大量事件處理程序的設計和運行時組件。我現在將它稱爲TNewComp。我在TForm上創建了TNewComp實例,並在設計時通過屬性編輯器填充了特定代碼的事件存根,並意識到我希望能夠創建使用當前一組事件處理程序代碼的TNewcomp的新實例。有沒有辦法在Delphi 6中自動分配動態創建的組件的事件處理程序?

現在要做到這一點,我調用TNewComp的構造函數,然後「手動」爲每個新實例的事件處理程序分配駐留在包含在設計時創建的TNewComp實例的窗體上的相應事件存根代碼。所以,如果我有一個分配給一個名爲FNewComp名爲TNewForm形式變量TNewComp的實例,爲每個事件處理程序,我會做:

FNewComp.onSomething = TNewform.onSomething 
(... repeat for each event handler belonging to TNewComp ...) 

這工作得很好,但它是繁瑣,更糟的是,如果我添加TNewComp的新事件處理程序,我必須記住更新我的「newTComp()」函數,以使事件處理程序分配。沖洗並重復此過程,以創建動態創建新實例的每種獨特組件類型。

有沒有辦法使這個過程自動化,也許使用財產檢查或其他一些Delphi 6內省技術?

- roschler

+2

我想我只是使用Alt + F12並在.dfm文件中快速複製/粘貼。除此之外,我不確定這是否適合定製工具。 –

+0

@David Hefferman @David Hefferman - 我不確定當我在運行時創建新實例時,您的解決方案是如何工作的,當運行時實例的數量未知時,它們可能是很多的,並且它們都是在運行時通過TNewComp.Create創建的。 –

+0

我認爲你的問題是在設計時。我不明白爲什麼現在做你做的事很難。你在想什麼需要一些規則來關聯事件和處理程序。你有什麼考慮?基於名稱? –

回答

4

我用下面的代碼。創建時要小心Dest目標所有者,最安全的方法是稍後通過Nil並自行釋放組件。

implementation uses typinfo; 

procedure CopyComponent(Source, Dest: TComponent); 
var 
    Stream: TMemoryStream; 
    TypeData : PTypeData; 
    PropList: PPropList; 
    i, APropCount: integer; 
begin 
    Stream:=TMemoryStream.Create; 
    try 
    Stream.WriteComponent(Source); 
    Stream.Position:=0; 
    Stream.ReadComponent(Dest); 
    finally 
    Stream.Free; 
    end; 

    TypeData := GetTypeData(Source.ClassInfo); 
    if (TypeData <> nil) then 
    begin 
    GetMem(PropList, SizeOf(PPropInfo)*TypeData^.PropCount); 
    try 
     APropCount:=GetPropList(Source.ClassInfo, [tkMethod], PropList); 
     for i:=0 to APropCount-1 do 
     SetMethodProp(Dest, PropList[i], GetMethodProp(Source, PropList[i])) 
    finally 
     FreeMem(PropList); 
    end; 
    end; 
end; 
+0

謝謝,我會試一試這個代碼。我幾乎從不將父母傳遞給動態創建的組件,並選擇自己管理他們的一生。否則,這是一個幾乎保證會話與FastMM後來尋找你指出的雙釋放或過早釋放的對象。 –

2

一種選擇是,以拯救「正確設置組件」成流,然後,就好像它是由Delphi的IDE /運行時間做到這一點的sTREM加載到新的,動態創建的組件。

另一種選擇是使用RTTI,TypInfo單位。您有功能GetPropList女巫將使您能夠查詢可用事件(TypeKind tkMethod),然後您可以使用GetMethodProp和​​將事件處理程序從一個組件複製到其他組件。

1

我調整Maksee的解決方案如下:

function CopyComponent(Source: TComponent; Owner: TComponent = nil): TComponent; 
var 
    Stream: TMemoryStream; 
    TypeData : PTypeData; 
    PropList: PPropList; 
    i, APropCount: integer; 
begin 
    if not Assigned(Source) then 
     raise Exception.Create('(CopyComponent) The Source component is not assigned.'); 

    Result := TComponent.Create(Owner); 

    Stream := TMemoryStream.Create; 

    try 
     Stream.WriteComponent(Source); 
     Stream.Position := 0; 
     Stream.ReadComponent(Result); 
    finally 
     Stream.Free; 
    end; // try() 

    // Get the type data for the Source component. 
    TypeData := GetTypeData(Source.ClassInfo); 

    if (TypeData <> nil) then 
    begin 
     // Get the property information for the source component. 
     GetMem(PropList, SizeOf(PPropInfo) * TypeData^.PropCount); 

     try 
      // Get the properties count. 
      APropCount := GetPropList(Source.ClassInfo, [tkMethod], PropList); 

      // Assign the source property methods to the destination. 
      for i := 0 to APropCount - 1 do 
       SetMethodProp(Result, PropList[i], GetMethodProp(Source, PropList[i])) 

     finally 
      // Free the property information object. 
      FreeMem(PropList); 
     end; // try() 
    end; // if (TypeData <> nil) then 
end; 

這樣一個新的組件是由函數返回,而不是通過在現有的組件引用(在Maksee版的目標參數)。如果任何人都能看到這個變體會導致的缺陷或問題,請評論。

相關問題