首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> Delphi

Delphi 7 資料錄入「攜帶」功能實作:以動態陣列複製記錄加速批次輸入

     編輯:Delphi

前言:為什麼需要「攜帶」功能?

在資料庫應用中,大量資料輸入時,許多欄位(如部門、職稱、聯絡電話、郵遞區號)在連續筆記錄間重複率極高。FoxPro 時代的 SET CARRY ON 允許使用者將上一筆記錄的欄位值「帶入」新記錄,僅修改差異即可存檔,大幅提升輸入效率。本文示範如何在 Delphi 7 + BDE/ADO + TTable/TDataSet 架構下,以動態 Variant 陣列實作同等效果。

核心架構

  1. 動態陣列儲存來源記錄:MyDynamic_Record: Variant(VarArrayCreate 建立,索引 0~FieldCount-1)。
  2. BeforeInsert 事件:讀取當前游標所在記錄的所有非 Blob/Memo 欄位值存入陣列(MyRecordScatTo)。
  3. AfterInsert 事件:將陣列值寫入新插入記錄的對應欄位(MyRecordGatherFrom)。
  4. 使用者修改確認:Post 時檢查主鍵重複等錯誤(My_TablePostError)。

關鍵程式碼模組

1. 表單變數與事件綁定

type
  TForm1 = class(TForm)
    Table1: TTable;
    CheckBox1: TCheckBox;  { 啟用「攜帶」 }
    Button1: TButton;      { 插入新記錄 }
    Button2: TButton;      { 關閉 }
    DBGrid1: TDBGrid;
    procedure FormCreate(Sender: TObject);
    procedure Table1BeforeInsert(DataSet: TDataSet);
    procedure Table1AfterInsert(DataSet: TDataSet);
    procedure Table1PostError(DataSet: TDataSet; E: EDatabaseError; var Action: TDataAction);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    MyDynamic_Record: Variant;
    function MyRecordScatTo(DataSet0: TDataSet; var MyDynamic_Record0: Variant): Boolean;
    function MyRecordGatherFrom(DataSet0: TDataSet; var MyDynamic_Record0: Variant): Boolean;
    procedure My_TablePostError(DataSet: TDataSet; E: EDatabaseError; var Action: TDataAction; sFieldName: string);
  end;

2. 讀取來源記錄 → 動態陣列(BeforeInsert)

function TForm1.MyRecordScatTo(DataSet0: TDataSet; var MyDynamic_Record0: Variant): Boolean;
var
  i: Integer;
begin
  Result := False;
  try
    if not DataSet0.Active then
    begin
      MessageDlg('當前無有效記錄,無法使用「攜帶」!', mtError, [mbOK], 0);
      Exit;
    end;

    MyDynamic_Record0 := VarArrayCreate([0, DataSet0.FieldCount - 1], varVariant);
    with DataSet0 do
      for i := 0 to FieldCount - 1 do
        if Fields[i].DataType <> ftMemo then  { 排除 Blob/Memo }
          MyDynamic_Record0[i] := Fields[i].Value;

    Result := True;
  except
    Result := False;
  end;
end;

procedure TForm1.Table1BeforeInsert(DataSet: TDataSet);
begin
  if CheckBox1.Checked then
    if not MyRecordScatTo(Table1, MyDynamic_Record) then
      CheckBox1.Checked := False;  { 失敗自動關閉功能 }
end;

3. 陣列值 → 新記錄欄位(AfterInsert)

function TForm1.MyRecordGatherFrom(DataSet0: TDataSet; var MyDynamic_Record0: Variant): Boolean;
var
  i: Integer;
begin
  Result := True;
  try
    with DataSet0 do
      for i := 0 to FieldCount - 1 do
        if Fields[i].DataType <> ftMemo then
          Fields[i].Value := MyDynamic_Record0[i];
  except
    Result := False;
  end;
end;

procedure TForm1.Table1AfterInsert(DataSet: TDataSet);
begin
  if CheckBox1.Checked then
    MyRecordGatherFrom(Table1, MyDynamic_Record);
end;

4. 統一錯誤處理(PostError)

procedure TForm1.My_TablePostError(DataSet: TDataSet; E: EDatabaseError; var Action: TDataAction; sFieldName: string);
var
  sMes: string;
begin
  MessageBeep(0);
  sMes := '當前記錄資料錯誤,請修正後再存檔。';
  if Pos(UpperCase('key violation'), UpperCase(E.Message)) > 0 then
    sMes := Format('「%s」值重複,請修改!', [sFieldName]);
  if Pos(UpperCase('must have a value'), UpperCase(E.Message)) > 0 then
    sMes := '必填欄位不可為空!';
  sMes := sMes + #13#10 + '(按 Esc 取消編輯)';
  MessageDlg(sMes, mtError, [mbOK], 0);
  Action := daAbort;
end;

procedure TForm1.Table1PostError(DataSet: TDataSet; E: EDatabaseError; var Action: TDataAction);
begin
  My_TablePostError(DataSet, E, Action, '編號');  { 傳入主鍵欄位名 }
end;

5. 插入與關閉按鈕

procedure TForm1.Button1Click(Sender: TObject);
begin
  Table1.Insert;
  if DBGrid1.CanFocus then DBGrid1.SetFocus;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  Table1.Refresh;
  Table1.Close;
  Close;
end;

執行流程示意

  1. 使用者在 DBGrid 定位到欲複製的來源記錄(如第 2 筆)。
  2. 勾選 「使用攜帶」 CheckBox。
  3. 按 「添加」 按鈕(或 Insert 鍵)觸發 Table1.Insert。
  4. 系統自動帶入來源記錄所有非 Memo 欄位值,游標停留於新記錄第一欄。
  5. 使用者僅修改異動欄位(如姓名、薪資),按 Enter 或點擊導航列 儲存 完成。

攜帶功能執行畫面

擴充建議

  • 支援 TDataSet 後代:將 TTable 改為泛型 TDataSet 參數,即可套用於 TADOTable、TClientDataSet、TFDTable 等。
  • 欄位過濾清單:加入 TStringList 讓使用者勾選哪些欄位「可攜帶」,避免主鍵、流水號等不可重複欄位被複製。
  • 多筆批次帶入:結合 TClientDataSet 的 CloneCursor 或 CopyDataSet 實現一次複製多筆。

結語

「攜帶」功能雖屬小技巧,卻能大幅降低資料輸入人員的重複勞動。以 Variant 動態陣列為媒介,不綁定特定資料集元件、自動適應欄位數量與型別,是 Delphi 快速開發資料庫應用的經典範例。移植至 FireDAC、UniDAC 等現代架構時,僅需替換資料集基類與欄位型別判斷即可無縫復用。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved