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

Delphi 建立簡單資料庫應用與 MASTAPP 範例詳解

     編輯:Delphi

前言

Delphi 內建的資料庫開發工具(如 Database Form Expert)功能強大,讓開發者無需撰寫任何程式碼,即可快速建立簡單的資料庫應用程式,甚至能建立基於多個資料表的主從式應用。本文將介紹使用 Delphi 開發簡單資料庫應用的一般方法與步驟,並以安裝目錄下的 MASTAPP 範例為基礎,帶領讀者逐步掌握從單表瀏覽到多表關聯、欄位物件操作、資料查詢與修改等核心技術。

14.1 簡單的單表資料庫應用

14.1.1 選擇相關元件

啟動新專案,將 Form1 的 Caption 設為 CustomerForm1,Name 設為 CustomerForm1。從元件選擇版的 Data Access 頁面拖入一個 TDataSource 和一個 TTable 元件(它們是非可視元件,僅在設計時顯示圖示);再從 Data Controls 頁面拖入一個 TDBGrid 放在兩者下方。完成後表單如圖 14.1 所示。

14.1.2 設定元件屬性

為了讓 TDBGrid 顯示 Customer.db 表的內容,必須正確設定三個元件的關鍵屬性,如下表:

元件.屬性屬性值
DataSource1.AutoEditFalse
DataSource1.DataSetTable1
Table1.DatabaseNameDBDEMOS
Table1.TableNameCUSTOMER.DB
Table1.ActiveTrue
DBGrid1.DataSourceDataSource1

注意事項:

  • DBDEMOS 是 Delphi 預設安裝時 C:\Delphi\Demos\DB\Mastapp 目錄的別名,請確認路徑正確。
  • DataSource1.DataSet、Table1.TableName、DBGrid1.DataSource 皆提供下拉清單,方便選取,不易出錯。
  • DataSource1.AutoEdit = False 可防止使用者直接修改資料;若需允許編輯,改為 True 即可。
  • Table1.Active = True 時會開啟資料表;若資料表不存在或為空,會彈出錯誤並自動將 Active 設回 False。欲修改 DatabaseName 或 TableName,必須先將 Active 設為 False。

14.1.3 執行程式

儲存單元為 Cust.pas,專案為 CustPrj.dpr,按 F9 編譯執行。執行後可用捲軸或鍵盤方向鍵瀏覽記錄,但無法修改資料(因 AutoEdit 為 False)。

三個元件各司其職:

  • TTable:連接實體資料表與應用程式的管道,提供開啟、關閉、讀取、更新等方法。
  • TDataSource:連接 TTable 與資料瀏覽元件(如 TDBGrid)的橋樑。
  • TDBGrid:提供直觀的網格介面顯示資料,支援捲動瀏覽、編輯、新增、刪除等操作。

若需更友善的介面,可改用 TDBEdit、TDBNavigator 等單獨資料瀏覽元件。

14.2 利用 TDBNavigator 建立導覽程式

14.2.1 建立應用程式表單

新增專案,表單 Name 設為 CustomerForm2,Caption 同。放置 TDataSource、TTable 於右上角,TDBNavigator 於左上角。依圖 14.3 配置 TDBEdit 與 TLabel,分別命名為 EditCustNo、EditCompany、EditAddr1…EditContact。設定所有資料瀏覽元件的 DataSource 為 DataSource1,並將每個 TDBEdit 的 DataField 屬性對應至資料表對應欄位(如 EditCustNo 對應 CustNo)。儲存單元為 Cust2.pas,專案為 CustPrj2.dpr。

14.2.2 使用 TDBNavigator 移動記錄指標

執行後顯示第一筆記錄。按 Tab 鍵可在欄位間移動,但無法編輯(Table1.AutoEdit = False)。若需編輯、新增、刪除或瀏覽其他記錄,需點擊 TDBNavigator 上對應按鈕。各按鈕功能如圖 14.4 所示,Navigator 會自動偵測是否位於首/尾記錄,並啟用/停用對應按鈕。

  • 編輯流程:點擊 Edit 按鈕 → 修改欄位 → 點擊 Post 寫入資料庫(或 Cancel 取消)。移動到其他記錄時會自動 Post。
  • 新增記錄:移至網格底端空白列輸入,或定位既有記錄後按 Ins 插入。
  • 刪除記錄:定位目標記錄按 Ctrl+Del,會彈出確認對話框。

若要禁止任何修改,可設 DBGrid.ReadOnly = True 且 Options.dgEditing = False。

14.2.3 自訂 TDBNavigator

  • ShowHint = True:滑鼠停留按鈕顯示提示。
  • Hints 屬性:自訂各按鈕提示文字。
  • VisibleButtons:隱藏不需要的按鈕(如不允許修改時隱藏 Add、Delete、Post、Cancel、Refresh)。
  • ConfirmDelete = True(預設):刪除前彈出確認框;設為 False 則不提示。

14.3 建立主從式資料庫應用

14.3.1 一對多關聯的主從應用

主表(如 Customer.db)存放綜合資訊,明細表(如 Orders.db)存放詳細資訊,兩者透過共同欄位(如 CustNo)關聯。建立兩個 TTable、兩個 TDataSource、兩個 TDBGrid、一個 TDBNavigator,屬性設定如表 14.2:

元件屬性值備註
Table1 (主表)ActiveTrue
DatabaseNameDBDEMOS
TableNameCUSTOMER.DB
DataSource1DataSetTable1
AutoEditFalse
Table2 (明細表)ActiveTrue
DatabaseNameDBDEMOS
TableNameORDERS.DB
IndexFieldNamesCUSTNO指定索引欄位
MasterFieldsCUSTNO與主表關聯欄位
MasterSourceDataSource1主表資料來源
DataSource2DataSetTable2
AutoEditFalse
DBGrid1DataSourceDataSource1對應主表
DBGrid2DataSourceDataSource2對應明細表
DBNavigator1DataSourceDataSource1控制主表導覽

操作 DBNavigator 移動主表記錄時,DBGrid2 會自動顯示該客戶的所有訂單明細。

14.3.2 一對多對多關聯應用

擴展為三層:Customer.db → Orders.db → Items.db。Orders 同時扮演 Customer 的明細表與 Items 的主表。需三組 Table/DataSource/DBGrid,關鍵屬性如表 14.3:

  • Table1:Customer.db
  • Table2:Orders.db,IndexFieldNames=CUSTNO,MasterFields=CUSTNO,MasterSource=DataSource1
  • Table3:Items.db,IndexFieldNames=ORDERNO,MasterFields=ORDERNO,MasterSource=DataSource2
  • DBGrid1 顯示 Items 明細,DBNavigator 控制 Customer 主表

14.4 欄位物件的使用

14.4.1 欄位物件類型

TField 物件對應資料表各欄位,常見類型見表 14.4:

類型對應資料型別
TBooleanField布林
TCurrencyField貨幣
TStringField字串
TIntegerField整數
TBlobField大型二進位物件

程式碼中無須關心實際類型,主要差異在於內部儲存與傳遞的資料型別。

14.4.2 建立永久欄位物件

  1. 建立基於 Customer.db 的表單,放置 DBGrid 顯示所有欄位(參考 14.1)。
  2. 設 Table1.Active = True 顯示資料。
  3. 雙擊 Table1 開啟 Fields Editor,預設欄位清單為空。
  4. 右鍵選 Add Fields,勾選欲顯示的欄位(如 CustNo、Company、Phone、LastInvoiceDate),按 OK。DBGrid 僅顯示這四個欄位。
  5. 拖曳調整欄位順序(如將 LastInvoiceDate 移至 Company 與 Phone 之間)。
  6. 關閉 Fields Editor,按 F9 執行。

14.4.3 欄位物件屬性設定

選取 Table1 → 雙擊開啟 Fields Editor → 選取欄位 → 在 Object Inspector 修改屬性。常用屬性見表 14.5:

屬性說明
Alignment顯示對齊:左、右、置中
CalculatedTrue 表示為計算欄位
DisplayLabel網格顯示的標題(預設為欄位名)
DisplayWidth網格欄寬(字元數)
DisplayFormat / EditMask顯示格式與輸入遮罩
FieldName資料表中對應欄位名
Index欄位在資料集中的邏輯位置(從 0 起算)
Name欄位物件名稱(如 Table1CUSTNO),可用 Table1CUSTNO.Value 存取值
ReadOnlyTrue 時不可修改
VisibleTrue 時在網格中顯示

範例修改 DisplayLabel 為中文標題(表 14.6),執行結果如圖 14.10。

14.4.4 欄位物件存取

動態欄位物件

透過 Table1.Fields[索引] 或 Table1.FieldByName('欄位名') 存取。例如:

Table1.Fields[0].DisplayLabel := '客戶編號';
Table1.FieldByName('Company').DisplayLabel := '公司名稱';

在 FormCreate 事件中批次設定:

procedure TForm1.FormCreate(Sender: TObject);
begin
  with Table1 do begin
    Fields[0].DisplayLabel := '客戶編號';
    FieldByName('Company').DisplayLabel := '公司名稱';
    FieldByName('Phone').DisplayLabel := '電話號碼';
    FieldByName('LastInvoiceDate').DisplayLabel := '購買日期';
  end;
end;

永久欄位物件

直接以 Name 屬性存取,如 Table1CustNo.DisplayLabel := '客戶編號';。

讀寫欄位值

透過 Value 屬性。範例:按鈕點擊時將 Company 欄位值讀入 Edit1:

procedure TForm1.Button1Click(Sender: TObject);
begin
  Edit1.Text := Table1Company.Value; // Table1Company 為 TStringField,Edit1.Text 為 string,型別相符
end;

注意:讀取值時必須指派給相容型別的變數,否則需轉換。

設定顯示格式範例:電話號碼本地化

為 Table1Phone 的 OnGetText 事件撰寫程式碼,將美式格式 808-555-0269 轉為中式 (808) 5550269:

procedure TForm1.Table1PhoneGetText(Sender: TField; var Text: string; DisplayText: Boolean);
begin
  if DisplayText then begin
    Text := Table1Phone.Value;
    Delete(Text, 4, 1);  // 移除第 4 字元 '-'
    Delete(Text, 7, 1);  // 移除第 7 字元 '-'
    Insert('(', Text, 1);
    Insert(')', Text, 5);
  end;
end;

14.4.5 自訂欄位與計算欄位

步驟:

  1. 雙擊 Table1 開啟 Fields Editor,右鍵選 New Field,型別選 Currency,名稱輸入 Balance。
  2. 右鍵選 Add Fields,勾選 OrderNo、CustNo、SaleDate、ShipDate、ItemsTotal、AmountPaid、Balance。
  3. 關閉 Fields Editor,在 Object Inspector 將 Table1Balance 的 Calculated = True。
  4. 在 Table1 的 OnCalcFields 事件撰寫計算邏輯:
procedure TForm1.Table1CalcFields(DataSet: TDataSet);
begin
  Table1Balance.Value := Table1ItemsTotal.Value - Table1AmountPaid.Value;
end;

14.5 查詢資料庫記錄

14.5.1 GotoKey 方法

步驟:確認查找欄位為鍵值或有輔助索引 → SetKey 進入查找模式 → 將查找值指派給欄位的 AsString → 呼叫 GotoKey 並檢查回傳值(True 成功,False 失敗)。

procedure TForm1.Button1Click(Sender: TObject);
begin
  with Table1 do begin
    Label1.Caption := ''; Label2.Caption := '';
    IndexFieldNames := 'CustNo';
    SetKey;
    FieldByName('CustNo').AsString := Edit1.Text;
    if GotoKey then begin
      Label1.Caption := '查找成功';
      Label2.Caption := FieldByName('Phone').AsString;
    end else
      Label1.Caption := '查找失敗';
  end;
end;

14.5.2 FindKey 方法

更簡潔,直接將查找值陣列傳給 FindKey:

procedure TForm1.Button1Click(Sender: TObject);
var SeekValue: string;
begin
  with Table1 do begin
    Label1.Caption := ''; Label2.Caption := '';
    IndexFieldNames := 'CustNo';
    SeekValue := Edit1.Text;
    if FindKey([SeekValue]) then begin
      Label1.Caption := '查找成功';
      Label2.Caption := FieldByName('Phone').AsString;
    end else
      Label1.Caption := '查找失敗';
  end;
end;

差異:FindKey 參數為陣列,支援多欄位同時查找(需先設 IndexFieldNames 為多欄位,逗號分隔)。

14.5.3 GotoNearest / FindNearest 模糊查找

總會傳回最接近的記錄,不會失敗。用法同 GotoKey/FindKey,但查找值可不完整(如 'Dun' 可找到 'Dunteman' 或 'Duncan')。範例:

procedure TForm1.Button1Click(Sender: TObject);
begin
  with Table1 do begin
    IndexFieldNames := 'Company';
    SetKey;
    FieldByName('Company').AsString := Edit1.Text;
    GotoNearest;
    Label3.Caption := FieldByName('Company').AsString;
  end;
end;

14.6 修改資料庫記錄

14.6.1 Edit / Post 方法

修改流程:定位記錄 → Edit 進入編輯模式 → 修改欄位 → Post 寫入資料庫。批次修改範本:

with Table1 do begin
  DisableControls;  // 斷開資料瀏覽元件連結,提升效能
  try
    First;
    while not EOF do begin
      // 讀取欄位值、修改
      Edit;
      FieldByName('TargetField').AsString := NewValue;
      Post;
      Next;
    end;
  finally
    EnableControls; // 即使發生例外也會執行,恢復元件連結
  end;
end;

關鍵點:

  • DisableControls/EnableControls 配對使用,避免每次 Post 都重繪介面。
  • First/Next 確保逐筆處理,避免無限迴圈。
  • 使用 try...finally 保護 EnableControls 必定執行(異常保護),區別於 try...except(異常處理)。

14.6.2 完整範例:地址大小寫轉換

程式碼見原文,展示 ForceCase 程序搭配 try...finally 批次修改 Addr1、Addr2 欄位。

14.7 新增與刪除記錄

14.7.1 逐步新增

with Table1 do begin
  Insert;           // 建立空白記錄
  // 填充各欄位
  Post;             // 寫入磁碟
end;

有索引表會自動依索引順序插入;無索引表則插在當前記錄之後。亦可用 Append 插至尾端(僅適用無索引表)。

14.7.2 InsertRecord 一次新增

InsertRecord(['2000', nil, nil, nil]); // 依欄位順序傳值,nil 表空值

完整範例(原文例 14.7)示範以 FindKey 檢查重複後 InsertRecord,刪除前以 MessageDlg 確認。

14.8 輸入資料有效性驗證

三種驗證層級:

  1. 資料表層級:建表時在 DBD 設定最大/最小值、顯示格式等,由資料庫引擎在寫入前驗證。
  2. 欄位層級:
    • 撰寫欄位的 OnValidate 事件,如驗證 SaleDate 不得晚於今日:
      procedure TForm1.Table1SaleDateValidate(Sender: TField);
      begin
        if Sender.Value > Now then
          raise Exception.Create('不能輸入未來的日期');
      end;
    • 設 Required = True 強制必填,配合 OnValidate 驗證。
  3. 記錄層級:在 TTable.BeforePost 事件對整筆記錄進行驗證。

使用 TDBComboBox / TDBLookupComboBox 限制輸入範圍

  • TDBComboBox:Items 列出允許值(如 Prepaid、Net 30、COD)。
  • TDBLookupComboBox:從另一資料表(如 Employee)取值,設 LookupSource、KeyField、LookupField。

屬性設定詳見表 14.8。

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