Delphi 的 FireDAC 元件簡化了資料函式庫應用程式的開發流程。透過 FireDAC,開發者可以輕鬆地執行 SQL 查詢、管理資料函式庫連線以及處理資料集。本文除了資料函式庫操作,也涵蓋 UI 設計,包含使用 TListView 元件展示資料、客製化列表專案的外觀、以及處理使用者互動事件。這使得開發者能夠快速建立功能完善、使用者友善的資料函式庫應用程式。文章也示範瞭如何透過介面設計模式來分離資料存取邏輯和 UI 邏輯,提升程式碼的可維護性和擴充性。
使用 FireDAC 存取資料函式庫
在 Delphi 中使用 FireDAC 進行資料函式庫操作是一種相對簡單直接的方式。首先,我們需要設定查詢編輯器中的 SQL 陳述式,以取得 ToDos 資料表中的最大 Id 值。
建立取得最大 Id 值的 SQL 查詢
SELECT MAX(Id) AS MaxId FROM ToDos
在查詢編輯器中執行此查詢,可以檢查 SQL 陳述式是否有錯誤。雖然此時資料函式庫中尚無記錄,但仍可藉此檢查語法正確性。
內容解密:
SELECT MAX(Id) AS MaxId FROM ToDos:這條 SQL 陳述式用於取得ToDos資料表中最大的Id值,並將結果命名為MaxId。- 使用
MAX聚合函式來計算Id的最大值。 - 如果資料表為空,
MAX(Id)將傳回NULL,因此需要特別處理這種情況。
實作 GetNewId 方法
function TDMToDo.GetNewId: Integer;
begin
FdqToDoMaxId.Open;
try
var Fld := FdqToDoMaxId.FieldByName('MaxId');
if Fld.IsNull then
Result := 1
else
Result := Fld.AsInteger + 1;
finally
FdqToDoMaxId.Close;
end;
end;
內容解密:
- 開啟
FdqToDoMaxId查詢並嘗試取得MaxId欄位的值。 - 使用區域性變數
Fld簡化程式碼並提高可讀性。 - 如果
MaxId為NULL,表示資料表為空,因此傳回 1;否則,傳回目前最大值加 1。 - 確保在
finally區塊中關閉查詢,以釋放資源。
新增 Todo 專案
設定插入查詢的 SQL 陳述式
INSERT INTO ToDos (Id, Title, Category) VALUES (:Id, :Title, :Category)
在查詢編輯器中設定引數的資料型別和方向:
Id:ftInteger,ptInputTitle:ftString,ptInputCategory:ftString,ptInput
實作 ToDoCreate 方法
function TDMToDo.ToDoCreate(AValue: TToDo): Integer;
begin
var Id := GetNewId;
FdqToDoInsert.ParamByName('Id').AsInteger := Id;
FdqToDoInsert.ParamByName('Title').AsString := AValue.Title;
FdqToDoInsert.ParamByName('Category').AsString := AValue.Category;
try
FdqToDoInsert.ExecSQL;
Result := Id;
except
Result := -1;
end;
end;
內容解密:
- 首先呼叫
GetNewId以取得新的Id值。 - 將
AValue的屬性指定給對應的引數。 - 執行插入查詢,如果成功則傳回新的
Id,否則傳回 -1。
讀取 Todo 專案
設定查詢的 SQL 陳述式
SELECT Title, Category FROM ToDos WHERE Id = :Id
設定 Id 引數的資料型別為 ftInteger 和方向為 ptInput。
實作 ToDoRead 方法
function TDMToDo.ToDoRead(Id: Integer; out AValue: TToDo): Boolean;
begin
FdqToDoSelect.ParamByName('Id').AsInteger := Id;
FdqToDoSelect.Open;
try
if FdqToDoSelect.RecordCount > 0 then
begin
Result := True;
AValue.Id := Id;
AValue.Title := FdqToDoSelect.FieldByName('Title').AsString;
AValue.Category := FdqToDoSelect.FieldByName('Category').AsString;
end
else
Result := False;
finally
FdqToDoSelect.Close;
end;
end;
內容解密:
- 設定
Id引數並開啟查詢。 - 如果找到記錄,則將其屬性指定給
AValue,並傳回True;否則傳回False。
更新 Todo 專案
設定更新查詢的 SQL 陳述式
UPDATE ToDos SET Title = :Title, Category = :Category WHERE Id = :Id
設定引數的資料型別和方向,與插入查詢類別似。
實作 ToDoUpdate 方法
function TDMToDo.ToDoUpdate(AValue: TToDo): Boolean;
begin
FdqToDoUpdate.ParamByName('Id').AsInteger := AValue.Id;
FdqToDoUpdate.ParamByName('Title').AsString := AValue.Title;
FdqToDoUpdate.ParamByName('Category').AsString := AValue.Category;
try
FdqToDoUpdate.ExecSQL;
Result := True;
except
Result := False;
end;
end;
內容解密:
- 將
AValue的屬性指定給對應的引數。 - 執行更新查詢,如果成功則傳回
True,否則傳回False。
刪除 Todo 專案
設定刪除查詢的 SQL 陳述式
DELETE FROM ToDos WHERE Id = :Id
設定 Id 引數的資料型別為 ftInteger 和方向為 ptInput。
實作 ToDoDelete 方法
function TDMToDo.ToDoDelete(Id: Integer): Boolean;
begin
FdqToDoDelete.ParamByName('Id').AsInteger := Id;
try
FdqToDoDelete.ExecSQL;
Result := True;
except
Result := False;
end;
end;
內容解密:
- 設定
Id引數並執行刪除查詢。 - 如果成功則傳回
True,否則傳回False。
取得所有 Todo 專案列表
設定查詢的 SQL 陳述式
SELECT * FROM ToDos ORDER BY Id DESC
實作 ToDoList 方法
procedure TDMToDo.ToDoList(AList: TToDos);
var
Item: TToDo;
begin
if AList <> nil then
begin
AList.Clear;
FdqToDoSelectAll.Open;
try
while not FdqToDoSelectAll.Eof do
begin
Item.Id := FdqToDoSelectAll.FieldByName('Id').AsInteger;
Item.Title := FdqToDoSelectAll.FieldByName('Title').AsString;
Item.Category := FdqToDoSelectAll.FieldByName('Category').AsString;
AList.Add(Item);
FdqToDoSelectAll.Next;
end;
finally
FdqToDoSelectAll.Close;
end;
end;
end;
內容解密:
- 首先檢查
AList是否為nil,然後清除列表。 - 開啟查詢並逐一讀取記錄,將每筆記錄的屬性指定給
Item並新增到列表中。 - 確保在
finally區塊中關閉查詢,以釋放資源。
至此,我們完成了資料存取層的構建。下一步是建立使用者介面(UI),以便利用資料存取層提供的服務。
實作資料驅動的使用者介面
資料存取邏輯實作與介面實作
在完成資料存取邏輯後,我們透過 IToDoData 介面提供資料存取功能。這樣可以確保 UI 邏輯只能透過此介面存取資料,實作真正的外掛架構。以下程式碼展示如何在主表單單元中實作 GetToDoData 方法以傳回資料存取介面的參考:
uses uDMToDo;
function TFormToDo.GetToDoData: IToDoData;
begin
if DMToDo = nil then
DMToDo := TDMToDo.Create(Application);
Result := DMToDo;
end;
內容解密:
GetToDoData方法確保DMToDo例項在需要時被建立,並傳回IToDoData介面的實作。- 這種設計允許在未來更改底層資料庫存取邏輯或資料函式庫平台,只要新的類別實作了
IToDoData介面即可。
使用者介面設計
- 在表單上放置
TTabControl元件,並將其對齊設為Client,然後重新命名為TbctrlMain。 - 右鍵點選
TbctrlMain,新增兩個分頁,分別用於顯示所有待辦事項和編輯選定的待辦事項。 - 在每個分頁上放置一個
TToolBar元件。 - 將
TbctrlMain的TabPosition屬性設為None以隱藏分頁標籤。 - 將兩個分頁分別重新命名為
TbiList和TbiEdit。
切換分頁與事件處理
- 在表單上放置
TActionList元件,雙擊它並新增兩個ChangeTabActions元件,分別命名為CtaList和CtaEdit,並將它們的Tab屬性連線到對應的分頁。 - 雙擊表單的
OnCreate和OnDestroy事件。在這裡,我們將建立和釋放一個全域的待辦事項列表。
procedure TFormToDo.FormCreate(Sender: TObject);
begin
FToDos := TToDos.Create;
TbctrlMain.ActiveTab := TbiList;
RefreshList;
end;
procedure TFormToDo.FormDestroy(Sender: TObject);
begin
FToDos.Free;
end;
內容解密:
- 在
FormCreate事件中,建立待辦事項列表並顯示第一個分頁,接著呼叫RefreshList方法來更新列表。 - 在
FormDestroy事件中,釋放待辦事項列表。
使用 TListView 顯示資料
- 在第一個分頁上放置一個
TListView元件,重新命名為LstvwToDos,並將其對齊設為Client。 - 調整
LstvwToDos的ItemAppearance屬性為DynamicAppearance以自訂列表專案的外觀。 - 在 Object Inspector 中新增自訂元素,如標題、類別和附件。
// 示例程式碼:設定 TListView 的動態外觀
// 將 Appearance 設定為 DynamicAppearance 後,可以透過程式碼或設計模式調整專案外觀
內容解密:
- 使用
DynamicAppearance可以靈活地定義列表專案的外觀和佈局。 - 自訂元素名稱如
Title、Category和More可在程式碼中使用。
自訂列表專案外觀
- 將列表專案的高度設為 64,並進入設計模式以調整各元素的位置和大小。
- 自訂各元素的字型樣式,如將標題設為粗體,類別設為斜體。
// 示例程式碼:自訂 TListView 專案外觀
// 在設計模式下調整元素佈局和樣式
內容解密:
- 在設計模式下,可以直觀地調整列表專案的佈局和樣式,以滿足應用程式的需求。
在 Delphi 中建立待辦事項應用程式:資料驅動的使用者介面實作
在開發行動應用程式時,建立一個資料驅動的使用者介面(UI)是非常重要的。本篇文章將介紹如何在 Delphi 中實作一個待辦事項應用程式的 UI,並將其與資料函式庫進行繫結。
重新整理列表方法實作
首先,我們需要實作 RefreshList 方法,該方法負責從資料函式庫中讀取資料並將其顯示在列表檢視中。
procedure TFormToDo.RefreshList;
begin
GetToDoData.ToDoList(FToDos);
LstvwToDos.BeginUpdate;
try
LstvwToDos.Items.Clear;
for var Todo in FToDos do
begin
var Item := LstvwToDos.Items.Add;
Item.Tag := Todo.Id;
Item.Objects.FindObjectT<TListItemText>('Title').Text := Todo.Title;
Item.Objects.FindObjectT<TListItemText>('Category').Text := Todo.Category;
end;
finally
LstvwToDos.EndUpdate;
end;
end;
內容解密:
GetToDoData.ToDoList(FToDos);:呼叫GetToDoData物件的ToDoList方法,將待辦事項列表讀取到FToDos變數中。LstvwToDos.BeginUpdate;和LstvwToDos.EndUpdate;:這兩個方法用於暫停和還原列表檢視的更新,以提高效能。for var Todo in FToDos do:遍歷FToDos列表中的每個待辦事項物件。Item.Objects.FindObjectT<TListItemText>('Title').Text := Todo.Title;:將待辦事項的標題和類別顯示在列表檢視中。
新增、刪除和編輯待辦事項
接下來,我們將介紹如何新增、刪除和編輯待辦事項。
新增待辦事項
- 在工具欄上放置一個
TSpeedButton元件,並將其StyleLookup屬性設定為Addtoolbutton。 - 在動作列表中新增一個動作,並將其連線到新增按鈕。
procedure TFormToDo.ActAddExecute(Sender: TObject);
begin
FCurrentId := -1;
EdtTitle.Text := '';
EdtCategory.Text := '';
CtaEdit.ExecuteTarget(self);
end;
內容解密:
FCurrentId := -1;:將FCurrentId設定為 -1,表示正在新增一個新的待辦事項。EdtTitle.Text := '';和EdtCategory.Text := '';:清空標題和類別編輯框。CtaEdit.ExecuteTarget(self);:切換到編輯標籤頁。
儲存待辦事項
儲存待辦事項的邏輯取決於目前的操作是新增還是更新。
procedure TFormToDo.ActSaveExecute(Sender: TObject);
var
Todo: TToDo;
begin
Todo.Title := EdtTitle.Text;
Todo.Category := EdtCategory.Text;
if FCurrentId < 0 then
GetToDoData.ToDoCreate(Todo)
else
begin
Todo.Id := FCurrentId;
GetToDoData.ToDoUpdate(Todo);
end;
RefreshList;
CtaList.ExecuteTarget(self);
end;
內容解密:
if FCurrentId < 0 then:如果是新增操作,則呼叫ToDoCreate方法建立新的待辦事項。else:如果是更新操作,則呼叫ToDoUpdate方法更新現有的待辦事項。RefreshList;:重新整理列表檢視。CtaList.ExecuteTarget(self);:切換回列表標籤頁。
刪除待辦事項
刪除待辦事項的邏輯如下:
procedure TFormToDo.ActDeleteExecute(Sender: TObject);
begin
if FCurrentId > 0 then
begin
GetToDoData.ToDoDelete(FCurrentId);
RefreshList;
end;
if TbctrlMain.ActiveTab <> TbiList then
CtaList.ExecuteTarget(self);
end;
內容解密:
if FCurrentId > 0 then:只有當FCurrentId大於 0 時,才執行刪除操作。GetToDoData.ToDoDelete(FCurrentId);:呼叫ToDoDelete方法刪除指定的待辦事項。RefreshList;:重新整理列表檢視。