程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> 通用Delphi數據庫輸入控件DBPanel的實現

通用Delphi數據庫輸入控件DBPanel的實現

編輯:Delphi
無論是開發什麼樣的程序,數據輸入是不可缺少的。快速地生成一個美觀的輸入界面無疑會大大提高程序開發的效率。系統原有的控件,往往不盡人意。在Delphi中,如果針對某字段,可選的控件有DBLabel, DBEdit等;如果針對全表的輸入,有DBGrid。使用Dbedit等控件時,用戶必須全面安排各字段的位置,雖然能夠達到美觀的效果,但是,如果字段數多,無疑是很麻煩的。如果采用DBGrid,無論多少個字段,只用一個控件就夠了,簡單倒是簡單,但是各字段是一字排列的,使用起來有點不方便。對於一般的用戶來說,采用表格形式的錄入,既方便,又美觀。這就是本文所要解決的問題。
  
  ---- 技術關鍵
  
  ---- 本控件的主要功能是實現對數據庫字段的編輯。按照一般的規律,控件中應包含TdataLink對象,還應該實現與TdataLink相關得一系列方法;但是,那樣會耗費大量的代碼。代碼量越大,系統就越復雜,出錯的可能性就越大。本控件的開發思路是以最少的代碼實現最多的功能。所以,對數據字段的編輯直接使用TDBComboBox控件。
  
  ---- 為了實現通用性,在控件內部維護了一個字段編輯控件數組和字段標題數組。如下:
  
  Editors: array of TDBComboBox;    
  - >具體進行編輯所用的數據控件數組,動態生成
  Labels: array of TLabel;        
  - >各字段的標題,動態生成
  
  ---- 采用TDBComboBox優點是它不僅能具有一般的編輯功能,還能為各字段添加相應的提示信息。代碼如下:
  { 為第I字段增加提示信息的方法}
  procedure TDBPanel.AddHits
  (ItemIndex: Integer; Hits: array of string);
  var
    m,n,i: Integer;
  begin
    n := Length(Editors);
    m := Length(Hits);
    if ItemIndex< n then begin
      for i:=0 to m-1 do Editors[ItemIndex].Items.Add(Hits[i]);
    end;
  end;
  
  ---- 具體的應用是千差萬別的,所以,控件還需要給程序員留有足夠的事件處理接口,以實現具體應用時的特殊功能。這就需要在控件中定義一定的事件處理方法供用戶實現。這裡提供的是一個OnOkClick事件,即當所有字段編輯完成後所執行的處理。代碼如下:
     
  OkButton: TButton;                
  - >最後增加的確定按鈕,用於實現提交動作。
  property OnOkClick: TNotifyEvent read FClick write FClick;
  
  ---- 通過實現OnOKClick方法,用戶可以完成提交、數據合理性檢驗等各種處理工作。另外一個需要特殊處理的是控制在各個字段間的轉換。缺省的情況是用鼠標點擊。但是,用戶的習慣往往是用鍵盤中的"上、下、左、右"四個箭頭鍵。要實現這一功能需定義以下兩個方法:
     
  procedure AKeyPress(Sender: TObject; var Key: Char);
  procedure AKeyDown(Sender: TObject;
  var Key: Word; Shift: TShiftState);
  
  ---- 將以上兩個方法賦值給動態生成的Editors,從而實現對箭頭鍵的響應。
  ---- 不同的表字段數不同,有可能出現顯示不下的情況,這就需要有滾動的功能。所以,在控件中插入了一個TscrollBox控件。最後一個需要注意的是動態控件的撤消及內存的釋放。控件數組的撤消及內存的釋放是有順序的--與創建完全相反的順序。否則會出錯。
  
  ----控件的使用
  
  ---- 先將DBPanel控件放在窗體上,然後設置數據源屬性、數據輸入表格的列數等屬性。在程序中,打開數據源後,調用創建數據編輯控件的方法即可。即:
  
  Query1.Open;- >打開數據源
  DBPanel1.CreateEditors; - >創建各字段的編輯控件
  DBPanel1.AddHits(0,['1111','11222','eeee']);    
  - >為某字段設置提示信息
  DBPanel1.AddHits(1,['1111','11222','eeee']); 
  - >為某字段設置提示信息
  該控件及示例程序在Win98+Delphi 5.0環境下調試通過。
  
  
  ---- 附件:TDBPanel的源代碼
  
  unit DBPanel;
  interface
  uses
  Windows, Messages, SysUtils, Classes,
  Graphics, Controls, Forms, Dialogs,
    ExtCtrls, dbctrls, stdctrls, db;
  type
    TDBPanel = class(TPanel)
    private
      { Private declarations }
      FLeft: Integer;
      FTop: Integer;
      maxTextLen: Integer;
      maxLabelLen: Integer;
      FScrollBox: TScrollBox;        {滾動控件}
      FLineHeight: Integer;
      FClick: TNotifyEvent;
      Editors: array of TDBComboBox;    
  - >具體進行編輯所用的數據控件數組,動態生成
      Labels: array of TLabel;        
  - >各字段的標題,動態生成
      OkButton: TButton;                
  - >最後增加的確定按鈕,用於實現提交動作。
      { 數據源}
      FDataSource: TDataSource;
      FColumns: Integer;                
  - >輸入表格的列數
      protected
      { Protected declarations }
      procedure FreeEditors;            
  - >釋放數據輸入控件的內存
      public
      procedure CreateEditors;//
      (DS: TDataSource; ColCount: Integer);
  - >創建各字段的數據輸入控件
      constructor Create(AOwner:
      TComponent); override;
      destructor Destroy; override;
      procedure AKeyPress(Sender:
      TObject; var Key: Char);
      procedure AKeyDown(Sender:
      TObject; var Key: Word; Shift:
      TShiftState);
      procedure ClearHits(ItemIndex: Integer);
      procedure AddHits(ItemIndex:
      Integer; Hits: array of string);
      function Editor(Index: Integer):
      TDBComboBox;
      { Public declarations }
      published
      property LeftLimit: Integer read
      FLeft write FLeft default 10;
      property TopLimit: Integer read
      FTop write FTop default 10;
      property EditorLen: Integer read
      maxTextLen write maxTextLen;
      property LabelLen: Integer read
      maxLabelLen write maxLabelLen    default 100;
      property LineHeight: Integer read
      FLineHeight write FLineHeight    default 15;
      property OnOkClick: TNotifyEvent
      read FClick write FClick;
      property DataSource: TDataSource
      read FDataSource write    FDataSource;
  - >數據源
      property Columns: Integer read
      FColumns write FColumns;- >表列數
      { Published declarations }
    end;
  
  procedure Register;
  
  implementation
  
  procedure Register;
  begin
    RegisterComponents('Additional', [TDBPanel]);
  end;
  
  { 為第I字段增加提示信息的方法}
  procedure TDBPanel.AddHits(ItemIndex:
  Integer; Hits: array of string);
  var
    m,n,i: Integer;
  begin
    n := Length(Editors);
    m := Length(Hits);
    if ItemIndex< n then begin
      for i:=0 to m-1 do Editors[ItemIndex].Items.Add(Hits[i]);
    end;
  end;
  
  procedure TDBPanel.AKeyDown
  (Sender: TObject; var Key: Word;
    Shift: TShiftState);
  begin
    if (Sender is TDBComboBox) then begin
      case Key of
        VK_Next: (Sender as TDBComboBox)
        .DataSource.DataSet.Next;
        VK_PRIOR: (Sender as TDBComboBox)
        .DataSource.DataSet.Prior;
      end;
    end;
  end;
  
  procedure TDBPanel.AKeyPress(Sender: TObject; var Key: Char);
  begin
    if (Sender is TDBComboBox) then begin
  if Key=#13 then (Owner as TForm).Perform(WM_NEXTDLGCTL, 0, 0);
    end;
  end;
  
  procedure TDBPanel.ClearHits(ItemIndex: Integer);
  var
    n: Integer;
  begin
    n := Length(Editors);
    if ItemIndex< n then Editors[ItemIndex].Items.Clear;
  end;
  
  constructor TDBPanel.Create(AOwner: TComponent);
  begin
    Inherited Create(AOWner);
    FLeft :=10;
    FTop := 10;
    maxTextLen := 100;
    maxLabelLen := 100;
    FLineHeight := 15;
  end;
  
  { 創建各字段的數據輸入控件的方法}
  procedure TDBPanel.CreateEditors;//
  (DS: TDataSource; ColCount: Integer);
  var
    i, n, RowCount: Integer;
    TextHeight: Integer;
  begin
    if DataSource.DataSet.Active then begin
      n := DataSource.DataSet.FIEldCount;
      { 計算最大的標題長度及顯示長度}
      DataSource.DataSet.First;
      { 計算高度}
      TextHeight := Canvas.TextHeight(DataSource
      .DataSet.FIElds[0].DisplayLabel) + FLineHeight; //10;
      { 計算行列數}
      RowCount := n div Columns;
      if n mod Columns <  > 0 then inc(RowCount);
      { 分配內存}
      FreeEditors;
      SetLength(Editors, n);
      SetLength(Labels, n);
      { 創建滾動盒}
      FScrollBox := TScrollBox.Create(Owner);
      FScrollBox.Parent := Self;
      FScrollBox.Align := alClIEnt;
      { 創建編輯}
      for i:=0 to n-1 do begin
        { 創建標題}
        Labels[i] := TLabel.Create(Owner);
        Labels[i].Parent := FScrollBox; //Self;
  Labels[i].Caption := DataSource.DataSet.FIElds[i].DisplayLabel;
        Labels[i].Left := FLeft + (maxLabelLen +
        maxTextLen + 10) * (i div RowCount);
        Labels[i].Width := maxLabelLen;
  Labels[i].Top := FTop + (i mod RowCount) * TextHeight + 5;
        { 創建編輯對象}
        Editors[i] := TDBComboBox.Create(Owner);
        Editors[i].Parent := FScrollBox; //Self;
        Editors[i].Left := Labels[i].Left + Labels[i].Width;
        Editors[i].Width := maxTextLen;
        Editors[i].Top := FTop + (i mod RowCount) * TextHeight;
        Editors[i].DataSource := DataSource;
  Editors[i].DataField := DataSource.DataSet.Fields[i].FIEldName;
        Editors[i].OnKeyPress := AKeyPress;
        Editors[i].OnKeyDown := AKeyDown;
      end;
      { 創建Ok按鈕}
      OkButton := TButton.Create(Owner);
      OkButton.Parent := FScrollBox;
      OkButton.Left := Editors[n-1].Left;
      OkButton.Top := Editors[n-1].Top + TextHeight;
      OkButton.Caption := '確定';
      OKButton.OnClick := FClick;
    end;
  end;
  
  destructor TDBPanel.Destroy;
  begin
    FreeEditors;
    Inherited Destroy;
  end;
  
  function TDBPanel.Editor(Index: Integer): TDBComboBox;
  begin
    if Index< Length(Editors) then Result := Editors[Index]
    else Result := nil;
  end;
  
  procedure TDBPanel.FreeEditors;
  var
    i,n: Integer;
  begin
    { 內存的釋放是要有順序的!必須以創建的相反的順序進行!
    尤其是當組件之間有父子關系時}
    if OkButton<  >nil then OkButton.Free;
    if Editors<  >nil then begin
      n := Length(Editors);
      for i:=0 to n-1 do Editors[i].free;
      Editors := nil;
      n := Length(Labels);
      for i:=0 to n-1 do Labels[i].Free;
      Labels := nil;
    end;
    if FScrollBox<  >nil then begin
      FScrollBox.Free;
      FScrollBox := nil;
    end;
  end;
  
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved