全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:1199
推到 Plurk!
推到 Facebook!

如何讓 TList 的衍生物件, 專門放入特定 Class Object?

尚未結案
Diviner
初階會員


發表:36
回覆:112
積分:34
註冊:2002-03-13

發送簡訊給我
#1 引用回覆 回覆 發表時間:2004-04-20 19:13:44 IP:218.103.xxx.xxx 未訂閱
有沒有辦法把 TList Inherit 出一個新的 TMyList class, 而它專門存取一個特定的 Class Object (例如 TMyObj) 呢? 即是說, 我若果寫 MyList1.Add(Button1), 而 Button1 不是 TMyObj class 的話會出 compile error, 又 MyList1[0] 不用做 Type casting 就可以使用 TObj 的 property/method, 可以嗎? -- 小卜子 發表人 - diviner 於 2004/04/20 19:15:03
------
--
小卜子
change.jian
版主


發表:29
回覆:620
積分:439
註冊:2003-06-02

發送簡訊給我
#2 引用回覆 回覆 發表時間:2004-04-20 21:05:36 IP:218.169.xxx.xxx 未訂閱
您好,我建議不要從TList繼承下來,改建另一個,底下是範例:
unit Unit1;    interface    uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;    type      TMyObj = class(TComponent)
  private
    FProp:String ;
    FName: TComponentName;
    procedure SetProp(const Value: string);
    procedure SetName(const Value: TComponentName);
  public
    property Name: TComponentName read FName write SetName;
    property Prop:string read FProp write SetProp;
  end;      TMyList = class(TObject)
  private
    FList:TStringList;
    function GetItem(Index: Integer): TMyObj;
    procedure SetItem(Index: Integer; const Value: TMyObj);
  public
    constructor Create;
    destructor Destroy;override;
    property Items[Index:Integer]:TMyObj read GetItem write SetItem;
    function Add(MyObj:TMyObj):Integer;
  end;      TForm1 = class(TForm)
    ListBox1: TListBox;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure ListBox1DblClick(Sender: TObject);
  private
    List:TMyList;
  public
    { Public declarations }
  end;    var
  Form1: TForm1;    implementation    {$R *.dfm}    { TMyList }    function TMyList.Add(MyObj: TMyObj): Integer;
begin
  FList.AddObject(MyObj.Name,MyObj);
end;    constructor TMyList.Create;
begin
  FList:=TStringList.Create;
end;    destructor TMyList.Destroy;
begin
  FList.Free;
  inherited;
end;    function TMyList.GetItem(Index: Integer): TMyObj;
begin
  Result:=TMyObj(FList.Objects[Index]);
end;    procedure TMyList.SetItem(Index: Integer; const Value: TMyObj);
begin
  FList.Objects[Index]:=Value;
end;    { TMyObj }    procedure TMyObj.SetName(const Value: TComponentName);
begin
  FName := Value;
  if FProp = '' then
    FProp := Value;
  inherited;
end;    procedure TMyObj.SetProp(const Value: string);
begin
  FProp := Value;
end;    procedure TForm1.Button1Click(Sender: TObject);
var
  sName:String;
  MyObj:TMyObj;
begin
  sName:='MyObj';
  if InputQuery('輸入物件的名字','新建的TMyObj名字',sName) then
  begin
    MyObj:=TMyObj.Create(Self);
    MyObj.Name:=sName;
    List.Add(MyObj);
    ListBox1.Items.Add(MyObj.Name);
  end;
end;    procedure TForm1.FormCreate(Sender: TObject);
begin
  List:=TMyList.Create;
end;    procedure TForm1.FormDestroy(Sender: TObject);
begin
  List.Free;
end;    procedure TForm1.ListBox1DblClick(Sender: TObject);
var
  Index:Integer;
begin
  Index:=ListBox1.ItemIndex;
  if Index>-1 then
    ShowMessage(List.Items[Index].Prop);
end;    end.
在procedure TForm1.ListBox1DblClick(Sender: TObject)裡,就是你要的,不用經過Type casting就可以直接叫用TObj的方法/屬性
Diviner
初階會員


發表:36
回覆:112
積分:34
註冊:2002-03-13

發送簡訊給我
#3 引用回覆 回覆 發表時間:2004-04-21 11:29:19 IP:218.103.xxx.xxx 未訂閱
回 change.jian,    先謝謝您。    若我 Inherit TList, 而這樣寫(如下), 應該會好一點, 因為你的方法是把 Is A 化為 Has A, 於是很多 TList 的特性都消失掉, 例如連 Count 都失去了, 於是, 我的 TMyList 便要橋接很多 Property 及 Method 才行。不如你看看我以下的程式碼, 看看好不好, 有沒有副作用:
unit Unit1;    interface    uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;    type
  TMyObj = class
    name: String;
    constructor Create(const s: String);
    procedure ShowName;
  end;      TMyList = class(TList)
  protected
    function Get(Index: Integer): TMyObj;
    procedure Put(Index: Integer; Item: TMyObj);
  public
    function Add(Item: TMyObj): Integer;
    property Items[Index:Integer]:TMyObj read Get write Put; default;
  end;      TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;    var
  Form1: TForm1;    implementation    {$R *.dfm}    { TMyObj }    constructor TMyObj.Create(const s: String);
begin
  name := s;
end;    procedure TMyObj.ShowName;
begin
  ShowMessage(name);
end;    { TMyList }    function TMyList.Add(Item: TMyObj): Integer;
begin
  result := Inherited Add(Item);
end;    function TMyList.Get(Index: Integer): TMyObj;
begin
  result := Inherited Get(Index);
end;    procedure TMyList.Put(Index: Integer; Item: TMyObj);
begin
  Inherited Put(Index, Item);
end;    procedure TForm1.Button1Click(Sender: TObject);
var
  o1, o2: TMyObj;
  List: TMyList;
  i: Integer;
begin
  o1 := TMyObj.Create('o1');
  o2 := TMyObj.Create('o2');
  List := TMyList.Create;      List.Add(o1);
  List.Add(o2);      for i := 0 to List.Count - 1 do
    List.Items[i].ShowName;
    // 也可直接寫成 List[i].ShowName;      List.Free;
  o1.free;
  o2.free;
end;    end.
-- 小卜子 發表人 - diviner 於 2004/04/21 11:31:27
------
--
小卜子
change.jian
版主


發表:29
回覆:620
積分:439
註冊:2003-06-02

發送簡訊給我
#4 引用回覆 回覆 發表時間:2004-04-21 12:07:35 IP:61.222.xxx.xxx 未訂閱
嗯,不錯,確實簡潔許多.只是以我一向的經驗,我都是直接從TObject繼承下來,因為常常會有客戶要改變需求,或者有一些功能當初沒想到,如果從TList繼承下來的話,那麼物件就一定會長成TList的形狀,當然,後面也可以自己再新增... 如果我的話,我會把這個物件定義成一個manager的角色,負責管理TMyObj物件,包含TMyObj.Create及TMyObjFree等全由這個物件控制,這樣程式碼的管理會更方便
Diviner
初階會員


發表:36
回覆:112
積分:34
註冊:2002-03-13

發送簡訊給我
#5 引用回覆 回覆 發表時間:2004-04-21 16:33:25 IP:218.103.xxx.xxx 未訂閱
引言: 嗯,不錯,確實簡潔許多.只是以我一向的經驗,我都是直接從TObject繼承下來,因為常常會有客戶要改變需求,或者有一些功能當初沒想到,如果從TList繼承下來的話,那麼物件就一定會長成TList的形狀,當然,後面也可以自己再新增... 如果我的話,我會把這個物件定義成一個manager的角色,負責管理TMyObj物件,包含TMyObj.Create及TMyObjFree等全由這個物件控制,這樣程式碼的管理會更方便
我認為是這樣, 當原來的 TMyList 已發展到超越了 List 的本質的時候, 其實是另一個物件了。介時, 應該建立一個新的 Class, 來管理這個 TMyList 不遲。 無論如何, 謝謝您回答。 -- 小卜子 發表人 - diviner 於 2004/04/21 16:40:18
------
--
小卜子
change.jian
版主


發表:29
回覆:620
積分:439
註冊:2003-06-02

發送簡訊給我
#6 引用回覆 回覆 發表時間:2004-04-21 21:27:21 IP:61.229.xxx.xxx 未訂閱
引言: 我認為是這樣, 當原來的 TMyList 已發展到超越了 List 的本質的時候, 其實是另一個物件了。介時, 應該建立一個新的 Class, 來管理這個 TMyList 不遲。 無論如何, 謝謝您回答。 -- 小卜子 發表人 - diviner 於 2004/04/21 16:40:18
我突然想到,如果屆時才用另一個新的物件的話,那麼原本呼叫TMyList的所有程式不是得要一併跟著修改才行....,還是另有其他的方法解決?
yangshengfa
一般會員


發表:1
回覆:16
積分:3
註冊:2003-09-06

發送簡訊給我
#7 引用回覆 回覆 發表時間:2004-04-22 03:00:43 IP:218.169.xxx.xxx 未訂閱
另一種實作方式,宣告TMyList 繼承 TObject,然後在TMyList 內加入 TList 管理 List。
ccchen
版主


發表:61
回覆:940
積分:1394
註冊:2002-04-15

發送簡訊給我
#8 引用回覆 回覆 發表時間:2004-04-22 10:42:24 IP:218.163.xxx.xxx 未訂閱
如果要專門存取一個特定的 Class Object,可以考慮繼承TCollection及TCollectionItem, 因為這正是此兩Class設計的目的啊
Diviner
初階會員


發表:36
回覆:112
積分:34
註冊:2002-03-13

發送簡訊給我
#9 引用回覆 回覆 發表時間:2004-05-02 23:45:58 IP:61.10.xxx.xxx 未訂閱
引言:
引言: 我認為是這樣, 當原來的 TMyList 已發展到超越了 List 的本質的時候, 其實是另一個物件了。介時, 應該建立一個新的 Class, 來管理這個 TMyList 不遲。 無論如何, 謝謝您回答。 -- 小卜子 發表人 - diviner 於 2004/04/21 16:40:18
我突然想到,如果屆時才用另一個新的物件的話,那麼原本呼叫TMyList的所有程式不是得要一併跟著修改才行....,還是另有其他的方法解決?
我想到這個, 只是我也想到, 若一個 List 發展到 List 無論如何承繼都不敷應用的時候, 那麼它跟本就不是一個 List, 而是一個「內含 List 的另一件東西」, 那麼, 舊的使用 TMyList 的部份, 應該是無需改變的, 而新的物件 (例如是 TMyObject) 應該不是舊有的程式部份的要求, 而是新的程式部份, 有新的要求, 所以才需要 TMyObject 的誕生來應付… 若有個具體一點的例子或者會好說一點。 -- 小卜子
------
--
小卜子
Diviner
初階會員


發表:36
回覆:112
積分:34
註冊:2002-03-13

發送簡訊給我
#10 引用回覆 回覆 發表時間:2004-05-02 23:48:07 IP:61.10.xxx.xxx 未訂閱
引言: 如果要專門存取一個特定的 Class Object,可以考慮繼承TCollection及TCollectionItem, 因為這正是此兩Class設計的目的啊
我不知道這個, 舉個小例子好嗎? -- 小卜子
------
--
小卜子
ccchen
版主


發表:61
回覆:940
積分:1394
註冊:2002-04-15

發送簡訊給我
#11 引用回覆 回覆 發表時間:2004-05-03 08:35:46 IP:218.163.xxx.xxx 未訂閱
引言:
引言: 如果要專門存取一個特定的 Class Object,可以考慮繼承TCollection及TCollectionItem, 因為這正是此兩Class設計的目的啊
我不知道這個, 舉個小例子好嗎?
Delphi的Souce Code內有很多例子, 例如StatusBar上之Panels, TListView之Columns, 或TDBGrid之Columns均是, 你可以看看SouceCode(Statusbar及TListView均在Comctrls.pas中) 主要關鍵在於 1. 繼承至TCollectionItem之Class須Override Assign method(其他看須要而定) 2. 繼承至TCollection之Class須Implement Item[] property, 及其Read/write method 看看Source code中此3 method之implement, 應該就可以知道如何做了
ccchen
版主


發表:61
回覆:940
積分:1394
註冊:2002-04-15

發送簡訊給我
#12 引用回覆 回覆 發表時間:2004-05-03 08:53:09 IP:218.163.xxx.xxx 未訂閱
引言:
引言: 如果要專門存取一個特定的 Class Object,可以考慮繼承TCollection及TCollectionItem, 因為這正是此兩Class設計的目的啊
我不知道這個, 舉個小例子好嗎?
Delphi的Souce Code內有很多例子, 例如StatusBar上之Panels, TListView之Columns, 或TDBGrid之Columns均是, 你可以看看SouceCode(Statusbar及TListView均在Comctrls.pas中) 主要關鍵在於 1. 繼承至TCollectionItem之Class須Override Assign method(其他看須要而定) 2. 繼承至TCollection之Class須Implement Item[] property, 及其Read/write method 看看Source code中此3 method之implement, 應該就可以知道如何做了
系統時間:2024-07-05 7:01:21
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!