相對於設計期固定的靜態 DFM,動態 DFM 指執行期生成或存取的 DFM。兩種來源:
Create 動態建立元件並插入生成靜態 DFM 犧牲彈性換取便利;動態插入控制項優勢在於任意時刻、位置、數量、類型,適合介面客製化、狀態保存、對話框保存等場景。缺點為非可視化,可輔以靜態 DFM 可視化設計。
RegisterClass 註冊InsertControl,關閉視窗時必須呼叫 RemoveControl 移除,否則產生異常Delphi 多樣可視元件(文字、編輯、圖像、資料庫、媒體播放、OLE)均佔螢幕區域、具豐富表現力,可作為卡片媒體。卡片要求媒體數量類型不受限、可修改存取,動態 DFM 最適合。若搭配串流存入資料庫 BLOB 欄位,更能融合超文本與關聯資料庫技術。
① 應用程式註冊元件類別
procedure TMainForm.FormCreate(Sender: TObject);
begin
RegisterClass(TLabel); RegisterClass(TEdit); RegisterClass(TMemo);
RegisterClass(TButton); RegisterClass(TPanel); RegisterClass(TPanelP);
RegisterClass(TBitBtn); ...
end;
② 建立與插入物件(點擊表單時依當前工具建立對應控制項)
procedure TMDIChild.FormClick(Sender: TObject);
var Ctrl: TControl; Point: TPoint;
begin
GetCursorPos(Point); Point := BackGround.ScreenToClient(Point);
case CurToolIndex of
1: begin { Label }
Ctrl := TLabel.Create(Self);
TLabel(Ctrl).AutoSize := False;
TLabel(Ctrl).Caption := 'Label'+S;
{ 設定位置、大小、顏色、字型、事件... }
BackGround.InsertControl(Ctrl);
end;
2: begin { Edit }
Ctrl := TEdit.Create(Self);
TEdit(Ctrl).AutoSize := True;
{ 設定位置、高度... }
BackGround.InsertControl(Ctrl);
end;
3: ...;
end;
end;
③ 存取動態 DFM 文件
{ 開啟 }
procedure TMainForm.FileOpen(Sender: TObject);
begin
if OpenDialog.Execute then
begin
DesignWin := TMDIChild.Create(Application);
ReadComponentResFile(OpenDialog.FileName, DesignWin);
DesignWin.Init;
FileName := OpenDialog.FileName;
DesignWin.Caption := FileName;
end;
end;
{ 儲存 }
procedure TMainForm.FileSave(Sender: TObject);
begin
if DesignWin.CurControl <> nil then DesignWin.CurControl.Enabled := True;
WriteComponentResFile(FileName, DesignWin);
DesignWin.Caption := FileName;
end;
{ 關閉時移除動態控制項 }
procedure TMDIChild.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
var I: Integer; Ctrl: TControl; Removed: Boolean;
begin
if Modified then if MessageDlg(...) = mrCancel then CanClose := False;
if CanClose then
begin
repeat
Removed := False; I := 0;
repeat
if BackGround.Controls[I].Name <> '' then
begin BackGround.RemoveControl(BackGround.Controls[I]); Removed := True; end;
Inc(I);
until (I >= BackGround.ControlCount) or Removed;
until not Removed;
SendMessage(ObjectIns.Handle, WM_MDICHILDCLOSED, 0, 0);
end;
end;
DesignWin.Init 將 BackGround 面板中具名控制項加入屬性編輯器列表。儲存用 WriteComponentResFile,關閉時必須逐一 RemoveControl 避免記憶體錯誤。