Data-Browse型Data-Aware控制元件的製作 (轉)

worldblog發表於2007-12-12
Data-Browse型Data-Aware控制元件的製作 (轉)[@more@]

Data-Browse型Data-Aware的製作


在MIS中,使用得最常見的當屬資料感知控制元件了。學習如何編寫自已的,一條很重要的原則就是從自己熟悉的
元件入手,派生出新的合乎自己要求的控制元件。在資料感知控制元件中,Data-Browse型是非常簡單而又實用的。所以下面
我們就講解一個一個自定義的TSunText(功能等同於TDBText)的編寫:

TSunDBText = class(TCustomLabel)
 {...}
end;

因為DBText僅起著顯示資料的作用,即是個具有資料感知功能的標籤,又根據的習慣,從Custom系列控制元件派生,
所以我們選擇了TCustomLabel。

如何具有資料感知功能,其實大部分的書上都沒有講得很明白,包括Delphi Help。大致上有這麼幾點,我們慢慢敘述:
一:選擇一個能資料感知的DataLink,通常我們選用TFieldDataLink,表示僅與一個欄位關聯
二:元件必須提供Data和DataField兩個設計時可讀寫屬性
三:元件必須處理FDataLink的OnDataChange事件,以反映資料欄位的變化
四:必須提供Notification過載方法,以便當關聯的TDataSource元件在設計期或者執行期刪除時,能得到通知,並且
  反映出這種改變
五:習慣上,我們還要處理CM_GETDATALINK訊息,以符合VCL內部通訊的要求
六:為了元件的靈活性,建議提供一個Field屬性,以便可以利用TField的方法來增強的適用性

下面我們就來一一講解:
private
  FDataLink:TFieldDataLink;
 
constructor Create(AOwner:TComponent);overr;
begin
  inherited;
  FDataLink := TFieldDataLink.Create; {建立一個TFieldDataLink的物件}
  FDataLink.OnDataChange := DataChange;
  {
 
  將TFieldDataLink物件的OnDataChange事件處理交給TSunDBText的DataChange來處理
  這樣就要以感知資料庫欄位的變化,並且進行自己想要的處理
 
  }
end;

destructor Destroy;override;
begin
  {
  這裡很簡單,僅僅是回收資源而已
  }
  FDataLink.Free;
  FDataLink := nil;
  inherited;
end;

從上面我們已經看到,資料感知的關鍵就在於DataChange事件,大致上我們可以知道,是需要將該欄位的顯示值賦予
本標籤元件的Caption屬性即可,所以下面的程式碼便是做這部分工作的。
(注意,之所以要用GetFieldText來完成賦值工作,是出於多方面的考慮,包括設計期和執行期,及異常情況)
procedure TSunDBText.DataChange(Sender: T);
begin
  Caption := GetFieldText; {read only displaytext when make an data browing component}
end;

function TSunDBText.GetFieldText: String;
begin
  {
 
  正常情況下,只需要取得FDataLink所代表的Field的DisplayText即可,如果你開發的不是Data-Browse控制元件,請用其他
  Field屬性
 
  }
  if(FDataLink <> nil) then
  Result := FDataLink.Field.DisplayText
  else if(csDesigning in ComponentState) then Result := Name else Result := ';
  {
  如果是處在設計期,則標籤中顯示的是元件的名稱,如果是執行期,則標籤為空;當然,這只是習慣而已,但對於使用Delphi IDE的人來說,
  幾乎就是規則。
  }
end;

如果沒有DataSource和DataField這兩個屬性,那麼控制元件幾乎就沒法使用了。這也是重要步驟。

  property DataSource:TDataSource read GetDataSource write SetDataSource;
  property DataField:String read GetDataField write SetDataField;
 
  這些方法十分簡單,只要存取TFieldDataLink之DataSource和FieldName屬性則可。
 
 function TSunDBText.GetDataSource: TDataSource;
begin
  Result := FDataLink.DataSource;
  {僅需簡單地返回TFieldDataLink之DataSource屬性
  從這就可以看出,DataSource屬性的寫方法也是對FDataLink賦值}
end;

procedure TSunDBText.SetDataSource(Value: TDataSource);
begin
  FDataLink.DataSource := Value; {如上所云,對DataSource屬性賦值}

  if(Value <> nil) then Value.FreeNotification(self);
  {
  這裡很重要,TComponent提供了一個FreeNotification(AComponent:TComponent)方法,這樣,當Value釋放時,就會自動AComponent的Notification
  方法,我們就可以調整對應的Data-Browse控制元件,以反映這種變化。如TSunDBText對應的DataSource元件刪除掉,則應該反映在標籤上
  }
end;

function TSunDBText.GetDataField: String;
begin
  Result := FDataLink.FieldName;  {獲得TFieldDataLink之FieldName屬性,也就知道了連線的是哪一個資料庫欄位名稱}
end;

procedure TSunDBText.SetDataField(const Value: String);
begin
  FDataLink.FieldName := Value; {這應該不用解釋了}
end;

接上面的,我們說過Notification的由來,下面就進行相關的處理:
procedure TSunDBText.Notification(AComponent: TComponent;
  Operation: TOperation);
begin
  inherited;
  if(Operation = opRemove) and (FDataLink <> nil) and (AComponent = DataSource) then
  DataSource := nil;
end;

當關聯元件被刪除時,而且被刪除的正好是本身關聯的DataSource元件,就應該設定其DataSource屬性為空

function TSunDBText.GetField: TField;
begin
  Result := FDataLink.Field;
end;

最後,資料感知控制元件還要響應CM_GETDATALINK訊息。通常處理是將TDataLink作為Message的Result域返回
procedure CMGetDataLink(var Message:TMessage);message CM_GETDATALINK;

procedure CMGetDataLink(var Message:TMessage);
begin
  Message.Result := Integer(FDataLink);
end;
到此,基本上元件的功能就已齊備了,然而,有一點許多元件編寫者都沒有注意到,即Action的應用。如果自定義元件能融入VCL的Action機制,
必然可以使自定義控制元件的功能更強大,更為一些高階使用者喜歡。

下一次,我們就來講一講Action之來龍去脈。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-992025/,如需轉載,請註明出處,否則將追究法律責任。

相關文章