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

property設計上的一個問題

答題得分者是:syntax
P.D.
版主


發表:603
回覆:4038
積分:3874
註冊:2006-10-31

發送簡訊給我
#1 引用回覆 回覆 發表時間:2005-03-21 01:36:52 IP:61.71.xxx.xxx 未訂閱
請問各位!    我現有一個案子需要對Navigator 的caption做可設定的異動, 我希望改寫publish中的功能, 雖已做出選項, 但我不知道要如何如下圖可以設定成string來填入所要的內容, 這一部份未曾有實作過的經驗, 不知道各位是否可提供一些資料, 謝謝!
syntax
尊榮會員


發表:26
回覆:1139
積分:1258
註冊:2002-04-23

發送簡訊給我
#2 引用回覆 回覆 發表時間:2005-03-21 08:12:12 IP:61.64.xxx.xxx 未訂閱
property iamcaption: String read getCap write SetCap; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 將這行放在 publish,然後按下 Ctrl Shift C 會自動產生 getCap 與 SetCap 在 private ,當然妳也可以自己 key in 這樣就是了,不用特別處理,只要妳宣告的是 String , Delphi 會幫妳處理剩下的,除非妳要特別什麼功能,不然不用自己寫 然後在 getCap 中將妳要的 Cap 傳出來 在 SetCap 設回去 function getCap:String; begin Result := the_cap_you_want.Caption; end; procedure SetCap(const Value: String); begin the_cap_you_want.Caption := Value; end; 這樣妳就可以在 objectinspactor 上修改 不過如果妳要向那樣加以 group 的話,那必須特別再處理,也不難,只要用另一個 class 來宣告與修改那些 caption 然後在主 class 內的property 改成 property groupcap: yourclass; 而該 class 是 yourclass = class function getA...... function getB...... property SetA...... property SetB...... property a:string read getA write SetA; property b:string read getB write SetB; ...... ...... ...... as many as you want end; 同樣的剩下 Delphi 會幫妳處理
P.D.
版主


發表:603
回覆:4038
積分:3874
註冊:2006-10-31

發送簡訊給我
#3 引用回覆 回覆 發表時間:2005-03-21 23:56:42 IP:61.71.xxx.xxx 未訂閱
謝謝 syntax 指導, 我大致已做出樣子, 但現有另一個問題, 就是我改了properity的內容, 並無法使元件上的button.caption同步異動, 以下是部份截錄, 不知那裡有疏漏, 請指教(.... 符號代表類似的寫法) ps:問題發生在改 properity 無法觸發 setCaption 事件 謝謝!    
unit NAVIGATOR;    interface    uses SysUtils, Classes, DBctrls, Dialogs, Db, DBtables, Messages, Windows;    var
    fFirstCap: string;
    fPriorCap: string;
    ...... 
type
  TCaptionSet = Class(TPersistent)
  private
    function GetFirstCap: string;
    function GetPriorCap: string;
    .....
    procedure setFirstCap(Value: string);
    procedure setPriorCap(Value: string);
    ....
    constructor Create;
  published
    property First: string read getFirstCap write setFirstCap;
    property Prior: string read getPriorCap write setPriorCap;
    property Next: string
    ....
  end;      TmNavigator = class (TDBNavigator)
  private
     fBtnCaptions: TCaptionSet;
     function GetCaption: TCaptionSet;
     procedure SetCaption(const Value: TCaptionSet);
     .....
  public
     ....
     Constructor Create(Aowner:TComponent);override;
     destructor Destroy; override;
  published
     ....
     property CaptionSet: TCaptionSet read GetCaption write SetCaption;
  end;    procedure Register;    implementation    procedure Register;
....
Constructor TmNavigator.Create(Aowner:TComponent);
var
 i:TNavigateBtn;
begin
  inherited Create(Aowner);
  fFontSize:= 9;
  fBtnCaptions:= TCaptionSet.Create;
  Buttons[nbFirst].Caption  := fBtnCaptions.First;
  Buttons[nbPrior].Caption  := fBtnCaptions.Prior;
  .....
end;
....    function TmNavigator.GetCaption;
begin
     fBtnCaptions.First  := fFirstCap;
     fBtnCaptions.Prior  := fPriorCap;
     .....
     result:= fBtnCaptions;
end;    procedure TmNavigator.SetCaption(const Value: TCaptionSet);
begin
    Buttons[nbFirst].Caption  := Value.First;
    Buttons[nbPrior].Caption  := Value.Prior;
    .....
end;    { TCaptionSet }    constructor TCaptionSet.Create;
begin
   fFirstCap  := '首筆';
   fPriorCap  := '上筆';
    ....
end;    function TCaptionSet.GetFirstCap: string;
begin
     result:= fFirstCap;
end;    function TCaptionSet.GetPriorCap: string;
begin
     result:= fPriorCap;
end;
.....
procedure TCaptionSet.setFirstCap(Value: string);
begin
     fFirstCap:= Value;
end;
procedure TCaptionSet.setPriorCap(Value: string);
begin
     fPriorCap:= Value;
end;    end.    這是做出來的樣式
syntax
尊榮會員


發表:26
回覆:1139
積分:1258
註冊:2002-04-23

發送簡訊給我
#4 引用回覆 回覆 發表時間:2005-03-22 21:53:49 IP:61.64.xxx.xxx 未訂閱
妳做得都沒錯,已經是正確的 proterty 原形 只是妳的程式設計邏輯出問題 你設計了一個 property 但是該 property 會去修改 ??? 以下是妳的程式流程 1.讀取 CaptionSet 發現是 Class 所以帶入 Class property Editor 因此有個加號產生,同時可以展開 2.展開後顯示 First 發現要經由 getFirstCap 來讀取,所以程式呼叫 getFirstCap 3.getFirstCap 傳回其值,根據妳的程式 result = fFirstCap,而 fFirstCap 是一個全域的變數,是你在 Create 時有設定初值為"首筆" 4.當妳要設定 First 時,呼叫的是 setFristCap ,會將數值經由 Value 傳入 setFirstCap 5.setFirstCap 會將 Value 設定到 fFirstCap 這就是妳的程式流程,以上略過 SetCaption 與 GetCaption,因為那是不必要的,妳一件事做了兩次,不過那不是主要問題 到這裡,妳知道問題在哪裡了嗎? 問題在於,妳創造了一個全域變數,同時設計了存取那個變數的 property 這樣跟妳想修改的 button.caption 有什麼關係? 所以整理一下妳的設計缺點 1.妳沒有確實改到妳要的東西 2.每一個妳放到 Form 上的 Navigator 都會對那個全域變數作存取,如果 Nav A 設 "1";Nav B 設 "2" ; Nav C 設 "3",最後 fFirstCap 是哪一個? 喔~是的 fFirstCap 將會是 "3",如果今天你可以同步更新,妳將會問,為什麼 Nav 間的 property 會互相影響? 因為根本就是改到同一個東西 3.妳同一件做了兩次 property CaptionSet: TCaptionSet read GetCaption write SetCaption; 是不需要再另寫程式來存取 直接使用 property CaptionSet: TCaptionSet read fBtnCaptions write fBtnCaptions; 即可 這個比較沒有關係,不影響程式的正確性,邏輯也正確,只是不需要做兩次,同時還必須冒兩個風險 --a.妳可能使用看似正確但結果將不會是你想要的語法,在這裡,差一點就差很多,一個是位址的傳遞,一個是數值的傳遞,會差很多 --b.不過你選擇的作法,可以避過 a. 的問題,但是要是你有 1000000 個直要設定,那 fBtnCaptions.First := fFirstCap 這種東西,妳就必須有 1000000 行,這種會造成你維護與修改的難度與時間上的浪費 以下給妳參考 1.class 的選用,通常直接用 class 就可以了,除非妳需要其他能力,不然就這樣用,這裡我們可能會需要資訊流的能力,所以加上(TPersistent),如需元件的能力就加上(TComponent) 吧 2.如何設計? ---a.採用 TString ,這樣可以如 Hint 的方式透過一個編輯視窗來統一,一起設定 ---b.不果妳要求的是要有個收納功能,這樣若是使用 TString ,勢必重新設計一個 Editor 來達到妳的要求,這樣難度會比較高 ---c.如果妳不介意,其實所有的 cap 也不算多,雖然也不少,直接寫在 Nav 內,會比較簡單(應該是簡單許多),只是在事件檢視器內會多那8行,且不能收納 ---d.使用之前所說的採用 Delphi 的優勢,盡量使用已經有的功能 a. b. c. 與 d. 3 種方法各有優缺,沒有說哪種最好,只有妳喜歡與妳需要哪種 以下以 d. 來說,此時我們必須設計一個 Meta class 來達到我們的要求,所以該 class 必需要知道是那個 Nav 擁有他,這樣才有辦法,來處理 而原本我們是希望可以直接在 Meta class 就完全設定好,但是我們發現,並沒有一個直接的方法可以存取那些 Caption,因為 Botton 是在 Nav 的 protected 區段 只有其子代可以存取,所以我們有兩個選擇:(1).將 botton 的可見度改到 public (2).將實際設定的方法寫在 Nav 內,Meta Class 只是一個橋樑與Group整理用 因為 (1) 會破壞程式原來的 OOP 原則,也就是會改到可見度的原規劃,這種選擇應該是最後的選擇 所以我們以 (2) 來實做,以下是範例 TNavCapGroup = class(TPersistent) //** 用來做 Group 的 Meta Class private { Private declarations } FOwner: TComponent; function GetFirstCap: String; procedure SetFirstCap(const Value: String); protected { protected declarations } public { Public declarations } constructor Create(AOwner: TComponent); virtual; //** 用來設定 FOwner published { published declarations } property FirstCap: String read getFirstCap write setFirstCap; //** ..... 其餘妳自己來囉 end; TDBNavigator_Ex = class(TDBNavigator) private { Private declarations } FtheNavCap: TNavCapGroup; function GetCaptions(const BtnType: TNavigateBtn): String; procedure SetCaptions(const BtnType: TNavigateBtn;const Value: String); //** 實際做設定的程式碼 protected { protected declarations } public { Public declarations } procedure AfterConstruction; override; procedure BeforeDestruction; override; 妳也可以改在 create 與 destory 做處理,只要時間正確,不要有未 create 就去存取,或是 destory 但尚未完成時還去存取 published { published declarations } property BtnCaptions: TNavCapGroup read FtheNavCap write FtheNavCap; end; { TDBNavigator_Ex } procedure TDBNavigator_Ex.AfterConstruction; begin inherited; FtheNavCap := TNavCapGroup.Create(Self); end; procedure TDBNavigator_Ex.BeforeDestruction; begin FreeAndNil(FtheNavCap); inherited; end; function TDBNavigator_Ex.GetCaptions(const BtnType: TNavigateBtn): String; begin Result := Buttons[BtnType].Caption; end; procedure TDBNavigator_Ex.SetCaptions(const BtnType: TNavigateBtn;const Value: String); begin Buttons[BtnType].Caption := Value; end; { TNavCapGroup } constructor TNavCapGroup.Create(AOwner: TComponent); begin if AOwner <> nil then if AOwner.ClassType = TDBNavigator_Ex then FOwner := AOwner else raise Exception.Create('只有 TDBNavigator_Ex 能做為擁有者,因為其才有對應的程式碼') else raise Exception.Create('擁有者,未知,無法運作'); end; function TNavCapGroup.GetFirstCap: String; begin TDBNavigator_Ex(FOwner).GetCaptions(nbFirst); end; procedure TNavCapGroup.SetFirstCap(const Value: String); begin TDBNavigator_Ex(FOwner).SetCaptions(nbFirst,Value); end; end. 這樣就可以做到你要的成果囉,只是這樣還有幾件事要做 1.妳的修改不會被儲存,所以妳必須自己寫入資料流,不然就白做囉 2.當修改後,妳必須重新設定 Btn 的大小來調整,不然妳的自會被截斷,同時當 Nav 大小修改時,也必須重新計算是否要可以繼續縮小,如果不行,就限制其最小的大小,目的也是讓妳輸入的字可以完整顯示 要注意,如果同時有圖形顯示,看是你要取消圖形的顯示,或是聽圖形與字同時顯示,將會影響計算完的大小 這兩點做好後,就是一個完整的功能啦
P.D.
版主


發表:603
回覆:4038
積分:3874
註冊:2006-10-31

發送簡訊給我
#5 引用回覆 回覆 發表時間:2005-03-22 22:59:25 IP:61.71.xxx.xxx 未訂閱
感謝 syntax 鼎力相助, 因為property的class設計方式以前從沒有接觸過, 所以完全無法切入重點運作, 之前我也是用Hints來取代, 也用過你提到的每一個都寫一組property方式, 不過一直對class的設計方式十分好奇, 藉由本次機會總算有一點認識, 不過你提到的內容有一些我還不是很能貫通明白, 可能還要多一點經驗值後才能提昇功力吧! 依你的內容指示, 我修改後已有樣子出現, 等其他部份處理好, 再分享給各位, 謝謝!
syntax
尊榮會員


發表:26
回覆:1139
積分:1258
註冊:2002-04-23

發送簡訊給我
#6 引用回覆 回覆 發表時間:2005-03-23 02:57:09 IP:61.64.xxx.xxx 未訂閱
我已經做好一個了 但是等你做完,回個文,或是 PM 給我 我再把我做的貼上來給妳比較 這樣你就會更清楚
P.D.
版主


發表:603
回覆:4038
積分:3874
註冊:2006-10-31

發送簡訊給我
#7 引用回覆 回覆 發表時間:2005-03-23 18:36:25 IP:61.71.xxx.xxx 未訂閱
十分感激, 由於不知道class要如何可以存資料, 我改了下面的做法, 可以讓設定存起來 如圖
type
  TCaptionSet = Class(TPersistent)
  private
    FOwner: TComponent;
    fFirst: string;
    FPrior: string;
    fNext: string;
    fInsert: string;
    fDelete: string;
    fLast: string;
    fEdit: string;
    fPost: string;
    fCancel: string;
    fRefresh: string;
    procedure setFirstCap(const Value: string);
    .....
  public
    constructor Create(AOwner: TComponent); virtual;
  published
    property First: string
       read  fFirst
       write setFirstCap;
    ....      TmNavigator = class (TDBNavigator)
  private
     fFontSize:integer;
     fShowType:ShowTypeName;
     fBtnCaptions: TCaptionSet;
     procedure SetCaptions(const BtnType: TNavigateBtn; const Value: String);
  public
     procedure SetBounds(ALeft,ATop,AWidth,AHeight:integer);override;
     .....
     Constructor Create(Aowner:TComponent); override;
     destructor Destroy; override;
  published
     property CaptionSet: TCaptionSet read fBtnCaptions write fBtnCaptions;    ....    procedure Register;    implementation    const
   BtnCapArray: Array [TNavigateBtn] of String
    = ('首筆','上筆','下筆','末筆','新增','刪除','修改','寫入','取消','更新');
....    Constructor TmNavigator.Create(Aowner:TComponent);
            var i: TNavigateBtn;
begin
     inherited Create(Aowner);
     fBtnCaptions:= TCaptionSet.Create(self);
     fFontSize:= 9;
     for i:=Low(Buttons) to High(Buttons) do begin
         Buttons[i].Glyph.Assign(nil);
         Buttons[i].Font.Size:= fFontSize;
         Buttons[i].Caption:= BtnCapArray[i];
     end;
end;    destructor TmNavigator.Destroy;
begin
     inherited;
      FreeandNil(fBtnCaptions);
end;    procedure TmNavigator.SetCaptions(const BtnType: TNavigateBtn;
  const Value: String);
begin
     Buttons[BtnType].Caption:= Value;
end;    { TCaptionSet }    constructor TCaptionSet.Create(AOwner: TComponent);
begin
     if AOwner <> nil then
        if AOwner.ClassType = TmNavigator then FOwner:= AOwner
        else raise Exception.Create('只有 TmNavigator 能做為擁有者')
     else raise Exception.Create('擁有者--未知,無法運作');
     fFirst  := '首筆';
     fPrior  := '上筆';
     fNext   := '下筆';
     fLast   := '末筆';
     fInsert := '新增';
     fDelete := '刪除';
     fEdit   := '修改';
     fPost   := '寫入';
     fCancel := '取消';
     fRefresh:= '更新';
end;    ....
procedure TCaptionSet.setFirstCap(const Value: string);
begin
     TmNavigator(FOwner).SetCaptions(nbFirst, Value);
     fFirst:= Value;
end;    
雖然有點土法煉鋼, 不過結果是可以達成我想要的方式, 期待觀摩syntax的做法!
syntax
尊榮會員


發表:26
回覆:1139
積分:1258
註冊:2002-04-23

發送簡訊給我
#8 引用回覆 回覆 發表時間:2005-03-23 21:27:53 IP:61.64.xxx.xxx 未訂閱
我是這樣做的,程式碼如下: 注意: 1.我有使用一個資源檔,其資源名稱是以 DBN_CHT_為開頭 結合BtnTypeName 陣列中名稱而成為完整資源名稱 2.預設文字在上,圖形在下,以減少計算顯示完整文字的時間消耗 3. GetFirstCap , SetFirstCap 經由改成泛用形,已經不是專給 First 設定用了,不過完成後才發現,又是一個懶得改的地方,可以改成 GetBtnCap , SetBtnCap ,這樣就不會混淆囉    有待補強的地方: 1.尚未給予所有的 Btn 初值,恩,偷懶沒做 2.應該設計可以選擇使用,文字、圖形,或同時使用的 property ,所以可以看到,文字與圖形同時出現,上一行是文字,下方是圖形     那個有紅色的按鈕,是執行時的圖,上方式設計時,左方是 Object Inspector
unit DBCtrls_Ex;    //** 建立日期 : 20031208
//** 修改日期 : 20040204,20050323
//**   設計者 : Syntax
//**     名稱 : VCL-Data-Controls Extension
//**     功能 :
//**            元件自訂加強能力    {$R 'Data Controls.RES'}    interface    uses
  DBCtrls, Classes, Messages;    type      TNavCapGroup = class(TPersistent)
  private
    { Private declarations }
    FOwner: TComponent;
    function GetFirstCap(const BtnType: TNavigateBtn): String;
    procedure SetFirstCap(const BtnType: TNavigateBtn;const Value: String);
    
  protected
    { protected declarations }      public
    { Public declarations }
    constructor Create(AOwner: TComponent); virtual;      published
    { published declarations }
    //** 因為是 String 型別, Delphi 已有處理方式,只要宣告在 pbulished ,就會被自動儲存囉~ 真好,不用自己再處理 defineproperty 等類似的咚咚
    property c0_First: String index nbFirst read GetFirstCap write SetFirstCap;
    property c1_Prior: String index nbPrior read GetFirstCap write SetFirstCap;
    property c2_Next: String index nbNext read GetFirstCap write SetFirstCap;
    property c3_Last: String index nbLast read GetFirstCap write SetFirstCap;
    property c4_Insert: String index nbInsert read GetFirstCap write SetFirstCap;
    property c5_Delete: String index nbDelete read GetFirstCap write SetFirstCap;
    property c6_Edit: String index nbEdit read GetFirstCap write SetFirstCap;
    property c7_Post: String index nbPost read GetFirstCap write SetFirstCap;
    property c8_Cancel: String index nbCancel read GetFirstCap write SetFirstCap;
    property c9_Refresh: String index nbRefresh read GetFirstCap write SetFirstCap;
    //** 這樣做可以減少需要 Key in 的數量 ^_^,利用 Deplhi 本來就有寫好的程式碼,加上 property 的特性
    //**  等於,快樂的 key in 時間,整個程式幾乎就在 Copy & Past 中渡過 ,超快,至於那個 c0 ~ c9 
    //**  是為了在 object inspector 中能夠依我想要的方式排列,注意,程式碼中 property 的寫作順序
    //**  就是其創立與讀取的順序,不過 object inspector 就是會重新排列,為了好看,所以加入 cx 字頭
  end;      TDBNavigator_Ex = class(TDBNavigator)
  private
    { Private declarations }
    FtheNavCap: TNavCapGroup;
    procedure ReDefineBTG;
    procedure ReDefineHints;
    //** Redefinexxx 是之前做好玩的功能,只是將圖形換一換,提示改成中文
    function GetCaptions(const BtnType: TNavigateBtn): String;
    procedure SetCaptions(const BtnType: TNavigateBtn;const Value: String);
    procedure WMSize(var Message: TWMSize);  message WM_SIZE;
    //** 用來避免,縮的太小,造成字被切斷或遮住,如果不介意那樣,那這個程序可以刪掉
  protected
    { protected declarations }      public
    { Public declarations }
     procedure AfterConstruction; override;
     procedure BeforeDestruction; override;
     //** 可以用 create and destory 來取代
  published
    { published declarations }
    property BtnCaptions: TNavCapGroup read FtheNavCap write FtheNavCap;
    //** 這樣做可以直接讀取元件,但是要小心,千萬不可以下BthCaptions.Free 喔 ~ 不然.....
    //** 這就是當 property 使用 class 時的缺點,有時不小心會 Free 到不該 Free 的地方,容易造成錯誤與盲點
    //** 不過改成另一種寫法後可以避免,但是卻會造成另一個問題,而該問題也是同樣的性質
    //** 所以哪種方式都一樣,使用時都有要小心的地方    
  end;    procedure Register;    implementation    uses
  SysUtils, Buttons, Forms, Controls;    var
  BtnTypeName: array[TNavigateBtn] of AnsiString = ('FIRST', 'PRIOR', 'NEXT',
  'LAST', 'INSERT', 'DELETE', 'EDIT', 'POST', 'CANCEL', 'REFRESH');    procedure Register;
begin     RegisterComponents('Samples',[TDBNavigator_Ex]);    end;    { TDBNavigator_Ex }    procedure TDBNavigator_Ex.AfterConstruction;
begin     inherited;
 FtheNavCap := TNavCapGroup.Create(Self);
 Height := 38;
 ReDefineBTG;
 ReDefineHints;
 ShowHint := True;    end;    procedure TDBNavigator_Ex.BeforeDestruction;
begin     FreeAndNil(FtheNavCap);
 inherited;    end;    function TDBNavigator_Ex.GetCaptions(const BtnType: TNavigateBtn): String;
begin     Result := Buttons[BtnType].Caption;    end;    procedure TDBNavigator_Ex.ReDefineBTG;
var
  I: TNavigateBtn;
  ResName: string;    begin     //** Load Graph
 for I := Low(Buttons) to High(Buttons) do
  begin       FmtStr(ResName, 'DBN_CHT_%s', [BtnTypeName[I]]);
   Buttons[I].Glyph.LoadFromResourceName(HInstance, ResName);
   Buttons[I].NumGlyphs := 4;
   Buttons[I].Layout := blGlyphBottom;      end;    end;    procedure TDBNavigator_Ex.ReDefineHints;
begin     Hints.Text := '首筆 資料' + #13#10 +
               '前一筆 資料' + #13#10 +
               '次一筆 資料' + #13#10 +
               '尾筆 資料' + #13#10 +
               '新增 資料' + #13#10 +
               '刪除 資料' + #13#10 +
               '編輯 資料' + #13#10 +
               '確定/儲存 資料' + #13#10 +
               '放棄修改 資料' + #13#10 +
               '資料顯示 更新';    end;    procedure TDBNavigator_Ex.SetCaptions(const BtnType: TNavigateBtn;const Value: String);
var
  CT: TMEssage;
  A: TControl;    begin     Buttons[BtnType].Caption := Value;
 CT.LParamLo := Width;
 CT.LParamHi := Height;
 Perform(WM_SIZE,0,CT.LParam);
 //** Nav 整體的 maintain 是由 messege of WM_SIZE --> SetSize __> CalM..._-> SetSize --> Return 來達成
  //** 已經有的東西,拿來用就好,直接傳個 Msg ,所有 Btn 就會自動排好,不是很棒嗎?
 if csDesigning in ComponentState then UpDate;
 //** 至於這行,是要給 Design time 時通知 Delphi 該 UpDate 該物件囉,不然會面不會統一,至於執行時,就不用了
 //** 因為 Msg 已經做好了,而一件事不用作兩次
end;    procedure TDBNavigator_Ex.WMSize(var Message: TWMSize);
var
  Count,TextW,Temp,W,L: Integer;
  I: TNavigateBtn;    begin     if Buttons[nbFirst] <> nil then
  begin       Count := 0;
   TextW := 0;
   for I := Low(Buttons) to High(Buttons) do
    begin         if Buttons[I].Visible then
      begin           Inc(Count);
       Temp := Canvas.TextWidth(Buttons[I].Caption + '  ');
       if TextW < Temp then TextW := Temp;          end;        end;       Temp := TextW * Count;      end;
 //** 計算最長字串所需寬度
 
 if Message.Width < Temp then Width := Temp
 else inherited;     
 //** 因為其他屬性與變數都是不可見的,所以只能用 Width 來修正大小,但是卻會造成重複呼叫,這裡不用擔心會造成無限回圈
 //** 因為 Delphi 在 Width直沒有變化的狀況下,即使妳去設定他,也不會做任何事
 //** 不過能然會造成 WM_SIZE 被呼叫 2 次,我不喜歡那一次多做的事,所以加個條件來處理,剛好設定 width 與 inherited 可以處理成如上
 //** 若是設定 width 則會引發另一個 Msg 則這個 Msg 的 inherited 就可以不用呼叫,省了一個
 //** 不過還是可以做的更好,在加個變數與檢查,就可以再減少一次計算最長字串所需寬度,這裡我偷懶囉    end;    { TNavCapGroup }    constructor TNavCapGroup.Create(AOwner: TComponent);
begin     if AOwner <> nil then
  if AOwner.ClassType = TDBNavigator_Ex then
   FOwner := AOwner
  else
   raise Exception.Create('只有 TDBNavigator_Ex 能做為擁有者,因為其才有對應的程式碼')
 else raise Exception.Create('擁有者,未知,無法運作');    end;    function TNavCapGroup.GetFirstCap(const BtnType: TNavigateBtn): String;
begin     Result := TDBNavigator_Ex(FOwner).GetCaptions(BtnType);    end;    procedure TNavCapGroup.SetFirstCap(const BtnType: TNavigateBtn;const Value: String);
begin     TDBNavigator_Ex(FOwner).SetCaptions(BtnType,Value);    end;    end.
發表人 - syntax 於 2005/03/23 21:33:37 發表人 - syntax 於 2005/03/23 21:41:07
系統時間:2024-07-01 5:45:35
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!