線上訂房服務-台灣趴趴狗聯合訂房中心
發文 回覆 瀏覽次數:955
推到 Plurk!
推到 Facebook!

如何把 Available DataSet 放進 Property Editor?

尚未結案
Diviner
初階會員


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

發送簡訊給我
#1 引用回覆 回覆 發表時間:2004-05-13 15:31:58 IP:218.103.xxx.xxx 未訂閱
我已初步懂得製作 Property Editor, 例如我已知道如何把字串放入 ComboBox, 放入 Object inspector 中讓人選擇:  
  TKeyFieldProperty = class(TStringProperty)
  private
  public
    function GetAttributes: TPropertyAttributes; override;
    procedure GetValues(Proc: TGetStrProc); override;
  end;    procedure Register;
begin
  RegisterComponents('Example', [TMyClientDataSet]);
  RegisterPropertyEditor(TypeInfo(String), TMyClientDataSet,
                         'PrimaryKey', TKeyFieldProperty);
end;    function TKeyFieldProperty.GetAttributes: TPropertyAttributes;
begin
  Result := inherited GetAttributes   [paValueList];
end;    procedure TKeyFieldProperty.GetValues(Proc: TGetStrProc);
begin
  Proc('Field1');
  Proc('Field2');
end;
現在我想把候選 DataSet 放入 ComboBox 中, 而不是上例的 String, 該如何做呢? -- 小卜子
------
--
小卜子
william
版主


發表:66
回覆:2535
積分:3048
註冊:2002-07-11

發送簡訊給我
#2 引用回覆 回覆 發表時間:2004-05-13 16:11:50 IP:147.8.xxx.xxx 未訂閱
Perhaps it could give you some hints:  >>... < class="code">unit MyTest; interface uses SysUtils, Classes, StdCtrls; type TMyTest = class(TComponent) private FLabel: TLabel; protected public published property ALabel: TLabel read FLabel write FLabel; end; procedure Register; implementation uses TypInfo, DesignIntf, DesignEditors; procedure Register; begin RegisterComponents('Samples', [TMyTest]); RegisterPropertyEditor(TypeInfo(TLabel),TMyTest,'ALabel',TComponentProperty); end; end.
l630521
資深會員


發表:15
回覆:349
積分:372
註冊:2003-02-17

發送簡訊給我
#3 引用回覆 回覆 發表時間:2004-05-13 16:27:23 IP:210.66.xxx.xxx 未訂閱
不好意思!你如果要把可選取的DataSet在Object inspector可讓人選取的話
unit Test;    interface    uses
  SysUtils, Classes, DB;    type
  TTest = class(TComponent)
  private
    { Private declarations }
    FDataSet: TDataSet;
  protected
    { Protected declarations }
  public
    { Public declarations }
  published
    { Published declarations }
    property DateSet: TDataSet read FDataSet write FDataSet;
  end;    procedure Register;    implementation    procedure Register;
begin
  RegisterComponents('Test', [TTest]);
end;    end.
直接設一property是TDataSet型態,Delphi就會自動把所有可用的DataSet讓你選取了不是嗎?為什麼還要特別去處理呢?請問你的目的為何啊? Ian
Diviner
初階會員


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

發送簡訊給我
#4 引用回覆 回覆 發表時間:2004-05-14 14:28:49 IP:218.103.xxx.xxx 未訂閱
引言: 不好意思!你如果要把可選取的DataSet在Object inspector可讓人選取的話
unit Test;    interface    uses
  SysUtils, Classes, DB;    type
  TTest = class(TComponent)
  private
    { Private declarations }
    FDataSet: TDataSet;
  protected
    { Protected declarations }
  public
    { Public declarations }
  published
    { Published declarations }
    property DateSet: TDataSet read FDataSet write FDataSet;
  end;    procedure Register;    implementation    procedure Register;
begin
  RegisterComponents('Test', [TTest]);
end;    end.
直接設一property是TDataSet型態,Delphi就會自動把所有可用的DataSet讓你選取了不是嗎?為什麼還要特別去處理呢?請問你的目的為何啊? Ian
啊, 是的, 的碓是自動做了給我, 那麼, 若果我想讓可選 DataSet 做些篩選, 例如只讓 TClientDataSet 才出現在這 DataSet ComboBox 中, 又如何處理呢? -- 小卜子
------
--
小卜子
Diviner
初階會員


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

發送簡訊給我
#5 引用回覆 回覆 發表時間:2004-05-14 14:29:18 IP:218.103.xxx.xxx 未訂閱
引言: 不好意思!你如果要把可選取的DataSet在Object inspector可讓人選取的話
unit Test;    interface    uses
  SysUtils, Classes, DB;    type
  TTest = class(TComponent)
  private
    { Private declarations }
    FDataSet: TDataSet;
  protected
    { Protected declarations }
  public
    { Public declarations }
  published
    { Published declarations }
    property DateSet: TDataSet read FDataSet write FDataSet;
  end;    procedure Register;    implementation    procedure Register;
begin
  RegisterComponents('Test', [TTest]);
end;    end.
直接設一property是TDataSet型態,Delphi就會自動把所有可用的DataSet讓你選取了不是嗎?為什麼還要特別去處理呢?請問你的目的為何啊? Ian
啊, 是的, 的確是自動做了給我, 那麼, 若果我想讓可選 DataSet 做些篩選, 例如只讓 TClientDataSet 才出現在這 DataSet ComboBox 中, 又如何處理呢? -- 小卜子
------
--
小卜子
l630521
資深會員


發表:15
回覆:349
積分:372
註冊:2003-02-17

發送簡訊給我
#6 引用回覆 回覆 發表時間:2004-05-14 14:37:52 IP:210.66.xxx.xxx 未訂閱
unit Test;    interface    uses
  SysUtils, Classes, DB;    type
  TTest = class(TComponent)
  private
    { Private declarations }
    FDataSet: TClientDataSet;
  protected
    { Protected declarations }
  public
    { Public declarations }
  published
    { Published declarations }
    property DateSet: TClientDataSet read FDataSet write FDataSet;
  end;    procedure Register;    implementation    procedure Register;
begin
  RegisterComponents('Test', [TTest]);
end;    end.
把TDataSet改成TClientDataSet就可以了! Ian
hahalin
版主


發表:295
回覆:1698
積分:823
註冊:2002-04-14

發送簡訊給我
#7 引用回覆 回覆 發表時間:2004-05-14 14:39:24 IP:210.243.xxx.xxx 未訂閱
    type
  TTest = class(TComponent)
  private
    { Private declarations }
    FDataSet: TClientDataSet;
  protected
    { Protected declarations }
  public
    { Public declarations }
  published
    { Published declarations }
    property DateSet: TClientDataSet read FDataSet write FDataSet;
  end;    
hahalin
版主


發表:295
回覆:1698
積分:823
註冊:2002-04-14

發送簡訊給我
#8 引用回覆 回覆 發表時間:2004-05-14 14:41:43 IP:210.243.xxx.xxx 未訂閱
sorry 回覆後才發現已經有標準答案了
Diviner
初階會員


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

發送簡訊給我
#9 引用回覆 回覆 發表時間:2004-05-17 12:36:17 IP:218.103.xxx.xxx 未訂閱
引言:
unit Test;    interface    uses
  SysUtils, Classes, DB;    type
  TTest = class(TComponent)
  private
    { Private declarations }
    FDataSet: TClientDataSet;
  protected
    { Protected declarations }
  public
    { Public declarations }
  published
    { Published declarations }
    property DateSet: TClientDataSet read FDataSet write FDataSet;
  end;    procedure Register;    implementation    procedure Register;
begin
  RegisterComponents('Test', [TTest]);
end;    end.
把TDataSet改成TClientDataSet就可以了! Ian
不行。 說來話要長一點, 因為, 我實際要放入這個 TTest 中的 DataSet, 並非 TDataSet, 亦非 TClientDataSet, 而是小弟自己寫的 TXClientDataSet, 而這個 TTest.DataSet 屬性, 便是供給放入 TXClientDataSet 物件, 而 TTest.DataSet 屬性的類別, 我是使用 TDataSet 就算了, 之所以不直接把 DataSet 屬性設定為 TXClientDataSet, 是有點苦衷的, 因為 TTest Class 與 TXClientDataSet Class 出現了 "Cyclic unit reference" 問題, 這是一直困擾著我的難題, 就例如現在這兩個 Class, 我的 TTest 中大量的使用著 TXClientDataSet, 而 TXClientDataSet 卻只有其中一個屬性指向 TTest, 結果兩者都要在 interface 區域的 uses 中加入對方的 Class reference, 結果就出現了 "Cyclic unit reference" 問題。 我懂得的解決方法只有兩個: 1. 某一方的 Class 中使用對方的 Class 的父類別, 然後在 Implementation 中不斷使用 Type casting 來解決。例如現在, 我就是採取了這方法, 我把 TTest 中的 DataSet 不設為 TXClientDataSet, 而只設為 TClientDataSet (或 TDataSet, 沒所謂); 2. 把兩個 Class 擠進一個 unit 中, 這個方法我覺得甚劣, 因為兩個 Class 的程式碼均甚多, 並有繼續發展之勢。我嘗試過使用 #include 來把併合了的大怪物分柝, 但效果不好, 因為 #include 使用上有很多限制。 所以, 若能解決這個 Cyclic unit reference 問題, 這條題便自然迎刃而解了, 可是, 即使我到 Borland newsgroup 找解決方案, 都找不出第三個方案出來, 你有建議嗎? 否則, 便要用老方法, 想想如何讓 Property inspector 把 TXClientDataSet 篩選出來, 放入 TDataSet (或 TClientDataSet) 類別的屬性之中了。 -- 小卜子
------
--
小卜子
hahalin
版主


發表:295
回覆:1698
積分:823
註冊:2002-04-14

發送簡訊給我
#10 引用回覆 回覆 發表時間:2004-05-17 13:05:34 IP:210.243.xxx.xxx 未訂閱
unit Test;    interface    uses
  SysUtils, Classes, DB;    type
  TTest = class(TComponent)
  private
    { Private declarations }
    FDataSet: TDataSet;
    procedure setfdataset(value:tdataset);
  protected
    { Protected declarations }
  public
    { Public declarations }
  published
    { Published declarations }
    property DateSet: TDataSet read FDataSet write   setFDataSet;
  end;    procedure Register;    implementation    procedure Register;
begin
  RegisterComponents('Test', [TTest]);
end;    procedure TTest.setFdataset(value:tdataset);
begin
   
   if value <> fdataset then begin
      if (uppercase(fdataset.classname)='TXClIENTDATASET') then 
      begin
         fdataset:=value;
      end;
   end;    end;        end.
發表人 - hahalin 於 2004/05/17 13:30:52
speedup
資深會員


發表:19
回覆:259
積分:280
註冊:2003-07-04

發送簡訊給我
#11 引用回覆 回覆 發表時間:2004-05-17 15:01:10 IP:61.224.xxx.xxx 未訂閱
  TMyDataSetProperty = class(TComponentProperty)
  private
  public
    function GetAttributes: TPropertyAttributes; override;
    procedure GetValues(Proc: TGetStrProc); override;
  end;    procedure Register;
begin
  RegisterComponents('Example', [TXClientDataSet]);
  RegisterPropertyEditor(TypeInfo(TDataSet), TXClientDataSet,
                         'XXXProperty', TMyDataSetProperty);
end;    function TMyDataSetProperty.GetAttributes: TPropertyAttributes;
begin
  Result := inherited GetAttributes   [paValueList];
end;    procedure TMyDataSetProperty.GetValues(Proc: TGetStrProc);
begin     Designer.GetComponentNames(GetTypeData(TypeInfo(TXClientDataSet)),Proc);    end;
混心雜欲 棄修身~唉
------
唉~
hahalin
版主


發表:295
回覆:1698
積分:823
註冊:2002-04-14

發送簡訊給我
#12 引用回覆 回覆 發表時間:2004-05-17 15:06:19 IP:210.243.xxx.xxx 未訂閱
speedup的手法很高阿 可否簡單說明一下呢 好讓小弟也能有機會學習
Diviner
初階會員


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

發送簡訊給我
#13 引用回覆 回覆 發表時間:2004-05-17 15:08:40 IP:218.103.xxx.xxx 未訂閱
引言:
unit Test;    interface    uses
  SysUtils, Classes, DB;    type
  TTest = class(TComponent)
  private
    { Private declarations }
    FDataSet: TDataSet;
    procedure setfdataset(value:tdataset);
  protected
    { Protected declarations }
  public
    { Public declarations }
  published
    { Published declarations }
    property DateSet: TDataSet read FDataSet write   setFDataSet;
  end;    procedure Register;    implementation    procedure Register;
begin
  RegisterComponents('Test', [TTest]);
end;    procedure TTest.setFdataset(value:tdataset);
begin
   
   if value <> fdataset then begin
      if (uppercase(fdataset.classname)='TXClIENTDATASET') then 
      begin
         fdataset:=value;
      end;
   end;    end;        end.
發表人 - hahalin 於 2004/05/17 13:30:52
謝謝你的回答。 事實上, 我已經這樣做了。這個做法可以達致「用戶選了 TXClientDataSet 以外的 DataSet Class object 時, 會 Prompt error」, 而未能做到一開始便只把 TXClientDataSet objects 放在 ComboBox 內讓人選擇。 不過, 現在我也算是得到解決了, 因為我一開始時不知道, 只要是 TDataSet 的屬性, Property Inspector 便會自動將之變成 ComboBox 讓人選擇。 在此一併多謝 William, 你的方法我往後寫 Component 時必會用得上。 -- 小卜子
------
--
小卜子
speedup
資深會員


發表:19
回覆:259
積分:280
註冊:2003-07-04

發送簡訊給我
#14 引用回覆 回覆 發表時間:2004-05-17 15:12:58 IP:61.224.xxx.xxx 未訂閱
引言: 我懂得的解決方法只有兩個: 1. 某一方的 Class 中使用對方的 Class 的父類別, 然後在 Implementation 中不斷使用 Type casting 來解決。例如現在, 我就是採取了這方法, 我把 TTest 中的 DataSet 不設為 TXClientDataSet, 而只設為 TClientDataSet (或 TDataSet, 沒所謂); 2. 把兩個 Class 擠進一個 unit 中, 這個方法我覺得甚劣, 因為兩個 Class 的程式碼均甚多, 並有繼續發展之勢。我嘗試過使用 #include 來把併合了的大怪物分柝, 但效果不好, 因為 #include 使用上有很多限制。 所以, 若能解決這個 Cyclic unit reference 問題, 這條題便自然迎刃而解了, 可是, 即使我到 Borland newsgroup 找解決方案, 都找不出第三個方案出來, 你有建議嗎?
你可以考慮用Interface /(或先建立abstract 祖先類別), 不過用Interface雖然可有效降低類別間相互Reference的複雜度,但要付出較多的程式碼實做代價,對初學者而言可能不習慣 另一種解法就是往上一層建立抽象祖先,不過在寫法上可能和你說的第一種寫法差不到哪裡去 混心雜欲 棄修身~唉
------
唉~
hahalin
版主


發表:295
回覆:1698
積分:823
註冊:2002-04-14

發送簡訊給我
#15 引用回覆 回覆 發表時間:2004-05-17 15:14:50 IP:210.243.xxx.xxx 未訂閱
    procedure TTest.setFdataset(value:tdataset);
begin
   
   if value <> fdataset then begin
      if (uppercase(fdataset.classname)='TXClIENTDATASET') then 
      begin
         fdataset:=value;
      end
      else begin
         raise exception.Create('元件型態不符合');
      end;
   end;    end;        
Diviner
初階會員


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

發送簡訊給我
#16 引用回覆 回覆 發表時間:2004-05-17 15:27:30 IP:218.103.xxx.xxx 未訂閱
引言:
  TMyDataSetProperty = class(TComponentProperty)
  private
  public
    function GetAttributes: TPropertyAttributes; override;
    procedure GetValues(Proc: TGetStrProc); override;
  end;    procedure Register;
begin
  RegisterComponents('Example', [TXClientDataSet]);
  RegisterPropertyEditor(TypeInfo(TDataSet), TXClientDataSet,
                         'XXXProperty', TMyDataSetProperty);
end;    function TMyDataSetProperty.GetAttributes: TPropertyAttributes;
begin
  Result := inherited GetAttributes   [paValueList];
end;    procedure TMyDataSetProperty.GetValues(Proc: TGetStrProc);
begin     Designer.GetComponentNames(GetTypeData(TypeInfo(TXClientDataSet)),Proc);    end;
混心雜欲 棄修身~唉
我看懂了這段程式碼, 然而試用之後, 沒有效果(可選到全部 DataSets), 你試過嗎? -- 小卜子 發表人 - diviner 於 2004/05/17 16:06:55
------
--
小卜子
speedup
資深會員


發表:19
回覆:259
積分:280
註冊:2003-07-04

發送簡訊給我
#17 引用回覆 回覆 發表時間:2004-05-18 09:24:12 IP:61.224.xxx.xxx 未訂閱
引言: 我看懂了這段程式碼, 然而試用之後, 沒有效果(可選到全部 DataSets), 你試過嗎?
我剛試寫一下,沒問題,將篩選出TXClientDataSet 附圖 測試程式碼
unit XClientDataSet;    interface    uses
  SysUtils, Classes, DB, DBClient,TypInfo,DesignEditors,DesignIntf;    type
  TXClientDataSet = class(TClientDataSet)
  private
    FXDataSet: TDataSet;
    procedure SetXDataSet(const Value: TDataSet);
  published
    property XDataSet:TDataSet read FXDataSet write SetXDataSet;
  end;      TMyDataSetProperty = class(TComponentProperty)
  private
  public
    function GetAttributes: TPropertyAttributes; override;
    procedure GetValues(Proc: TGetStrProc); override;
  end;        procedure Register;    implementation    procedure Register;
begin
  RegisterComponents('Sample', [TXClientDataSet]);
  RegisterPropertyEditor(TypeInfo(TDataSet), TXClientDataSet,
                         'XDataSet', TMyDataSetProperty);
end;    { TXClientDataSet }    procedure TXClientDataSet.SetXDataSet(const Value: TDataSet);
begin
  FXDataSet := Value;
end;    { TMyDataSetProperty }
function TMyDataSetProperty.GetAttributes: TPropertyAttributes;
begin
  Result := inherited GetAttributes + [paValueList];
end;    procedure TMyDataSetProperty.GetValues(Proc: TGetStrProc);
begin
 Designer.GetComponentNames(GetTypeData(TypeInfo(TXClientDataSet)),Proc);
end;    end. 
混心雜欲 棄修身~唉
------
唉~
Diviner
初階會員


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

發送簡訊給我
#18 引用回覆 回覆 發表時間:2004-05-18 12:41:20 IP:218.103.xxx.xxx 未訂閱
引言: 我剛試寫一下,沒問題,將篩選出TXClientDataSet ... 測試程式碼 ... procedure Register; begin RegisterComponents('Sample', [TXClientDataSet]); RegisterPropertyEditor(TypeInfo(TDataSet), TXClientDataSet, 'XDataSet', TMyDataSetProperty); end;
原來是我打錯字, 上面紅色的部份, 我用了 String 的 TypeInfo, 當然是學習過程中從某處抄來的, 忘了換過來。現在完全正常了, 不好意思讓你麻煩了做個 Demo 出來。 謝謝您。 -- 小卜子
------
--
小卜子
Diviner
初階會員


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

發送簡訊給我
#19 引用回覆 回覆 發表時間:2004-05-18 12:48:36 IP:218.103.xxx.xxx 未訂閱
引言: 你可以考慮用Interface /(或先建立abstract 祖先類別), 不過用Interface雖然可有效降低類別間相互Reference的複雜度,但要付出較多的程式碼實做代價,對初學者而言可能不習慣 另一種解法就是往上一層建立抽象祖先,不過在寫法上可能和你說的第一種寫法差不到哪裡去 混心雜欲 棄修身~唉
是的, 我也考慮過這個方法, 所以現正學習使用 Interface, 希望 speedup 君以後再不吝賜教了。 其實, 我正是因為不希望 TXClientDataSet 日後因功能不斷增加而令程式碼不斷膨脹, 所以才分成兩個 Component, 再用各自的屬性連結起來, 這樣做, 你覺得作法如何? -- 小卜子
------
--
小卜子
speedup
資深會員


發表:19
回覆:259
積分:280
註冊:2003-07-04

發送簡訊給我
#20 引用回覆 回覆 發表時間:2004-05-18 15:41:34 IP:61.224.xxx.xxx 未訂閱
引言: 其實, 我正是因為不希望 TXClientDataSet 日後因功能不斷增加而令程式碼不斷膨脹, 所以才分成兩個 Component, 再用各自的屬性連結起來, 這樣做, 你覺得作法如何? -- 小卜子
大哉問,我不清楚你要設計的元件功能,所已大概無法給啥建議,基本上解決問題的方法很多種,但好的架構的確有助於日後維護,如果有時間可以看看Design Pattern 或Refactor的書,搞不好你的問題已經被解決 另外你的問題有點頃向牽涉到實體分割的問題,這和Delphi的專案架構,與語言架構有點關係,如Delphi本身不支援Firend,兩個類別若要相互引用最簡單的方式就是放在同一個pas之中(但也代表這兩個Class關係太過複雜的確造成日後維護困然),重新檢視兩個類別的關係,重新設計成類似Delphi的(TDataSet/TDataSource/TDataLink or TControl/TWinControl or TCollection/TCollectionItem or TComponent)或許能夠解決問題。 舉個簡單的例子,這就有點類似在資料庫關聯中,通常若出現兩個多對多的表格時,這種狀況,通常會加入第三個表格使其變成兩個一對多的架構 相同的,你設計的架構若兩Class太複雜,可考慮將其中某部份切出成為負責連結關係的類別 混心雜欲 棄修身~唉
------
唉~
系統時間:2024-07-07 1:25:22
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!