2009-12-08 104 views
4

最近我發現了一段從字符串創建TButton實例的代碼:'TButton'被用作參數。如何從提供類名稱的字符串創建實例?

"Is there a way to instantiate a class by its name in Delphi?"

我想任何對象的published屬性保存到一個XML文件(正常工作),最近我想重新從XML文件中的這些對象。在這個文件中寫入了應該創建哪個類(例如TButton),然後跟隨一個屬性列表,該列表應該加載到此運行時創建的對象中。

上面的例子顯示瞭如何做到這一點,但它不適用於我自己的類。見下面的代碼:

TTripple=class (TPersistent) 
    FFont:TFont; 
    public 
    constructor Create; 
    Destructor Destroy;override; 
    published 
    property Font:TFont read FFont write FFont; 
    end; 
var 
    Form1: TForm1; 


implementation 

{$R *.dfm} 

constructor TTripple.Create; 
    begin 
    inherited; 
    FFont:=TFont.Create; 
    end; 


destructor TTripple.Destroy; 
    begin 
    FFont.Free; 
    inherited; 
    end; 

procedure TForm1.FormCreate(Sender: TObject); 
begin 
RegisterClasses([TButton, TForm, TTripple]); 
end; 

procedure TForm1.Button1Click(Sender: TObject); 
var 
    CRef : TPersistentClass; 
    APer : TPersistent; 
begin 
// CRef := GetClass('TButton'); 
    CRef := GetClass('TTripple'); 
    if CRef<>nil then 
    begin 
    APer := TPersistent(TPersistentClass(CRef).Create); 
    ShowMessage(APer.ClassName); // shows TTripple, what is correct 
    if APer is TTripple then (APer as TTripple).Font.Color:=90; 

    /// Here I get error message, because TTriple was not created... ?!?!?! 

    end; 
end; 

我不能通過。 TTripple對象可能已創建,但其構造函數未使用。

回答

5

TRipple構造函數沒有被調用,因爲它不是虛擬的。

當您從類引用構造對象時,編譯器不知道最終的類類型是什麼,所以它不能在代碼中分配正確的構造函數。它只知道它是從TPersistent降序的,所以它寫出了代碼來調用TPersistent的構造函數,即TObject.Create。如果你想調用正確的構造函數,你必須做到這一點。

已經有一個虛擬構造函數定義爲從類名讀取類。它在TComponent中定義。讓TRipple從TComponent下降並覆蓋它的虛擬構造函數(將Owner作爲參數的構造函數),然後您的代碼將工作。

+0

非常感謝,梅森。它現在的作品....非凡... :-) – lyborko 2009-12-08 14:13:37

+0

很高興能夠幫助! – 2009-12-08 14:27:15

5

您可能不想使用TComponent,並且還有另一種方法來執行此操作。

添加引用您的類

TTrippleClass = class of TTripple; 

那麼你buttonclick變爲:

procedure TForm1.Button1Click(Sender: TObject); 
var 
    CRef : TTrippleClass; 
    APer : TPersistent; 
begin 
    CRef := TTrippleClass(GetClass('TTripple')); 
    if CRef<>nil then 
    begin 
    APer := TTripple(TTrippleClass(CRef).Create); 
    ShowMessage(APer.ClassName); // shows TTripple, what is correct 
    if APer is TTripple then (APer as TTripple).Font.Color:=90; 
    end; 
end; 

現在,你可能需要有一個以上的TRIPPLE類型,然後創建一個自定義的祖先。

TCustomTripple = class(TPersistent) 
public 
    constructor Create;virtual; 
end; 

TCustomTrippleClass = class of TCustomTripple; 

TTripple = class(TCustomTripple) 
strict private 
    fFont : TFont; 
public 
    constructor Create;override; 
    destructor Destroy;override; 
    property Font : TFont read fFont; 
end; 


constructor TCustomTripple.Create; 
begin 
    inherited Create; 
end; 

constructor TTripple.Create; 
begin 
    inherited; 
    fFont := TFont.Create; 
end; 

destructor TTripple.Destroy; 
begin 
    fFont.Free; 
    inherited; 
end; 

procedure TForm1.Button1Click(Sender: TObject); 
var 
    CRef : TCustomTrippleClass; 
    APer : TCustomTripple; 
begin 
    CRef := TCustomTrippleClass(GetClass('TTripple')); 
    if CRef<>nil then 
    begin 
    APer := TCustomTripple(TCustomTrippleClass(CRef).Create); 
    ShowMessage(APer.ClassName); // shows TTripple, what is correct 
    if APer is TTripple then (APer as TTripple).Font.Color:=90; 
    end; 
end; 
+0

您是否嘗試過編譯這個?由於TCustomTripple的雙重聲明(如'TPersistent'和'TCustomTripple類'),它將不起作用。 – 2009-12-08 13:42:26

+0

我做了,但後來複製它(手工),因爲我在另一臺機器上的Delphi到我發佈答案的那臺機器上。我會檢查它。 – Steve 2009-12-08 14:05:11

+0

謝謝你,你的第一個例子工作正常。我很感激。在第二個我無法完成的事情 - 正如你所說的那樣。對於我的puropose梅森的答案是足夠的... – lyborko 2009-12-08 14:18:59

相關問題