Delphi TButton.OnClick 事件看似簡單,實則涉及方法指標、Click 方法、設計時元件關聯三層機制。理解其差異,能避免「刪除元件後殘留方法」、「動態建立按鈕事件不生效」、「跨表單呼叫 Click 失效」等常見坑。
| 方式 | 程式碼 | 機制 | 需元件存在 | 需方法存在 |
|---|---|---|---|---|
| 使用者點擊 | (自動) | Windows BN_CLICKED → TButton.Click → OnClick 事件 | 是 | 是 |
| 程式呼叫 Click 方法 | Button1.Click; | 直接呼叫 TButton.Click 方法,內部觸發 OnClick | 是 | 是 |
| 程式呼叫事件處理函數 | Button1Click(Form1); | 直接呼叫表單方法,繞過 Button 物件 | 否 | 是 |
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;
type
TForm1 = class(TForm)
Panel1: TPanel;
Button1: TButton;
procedure Button1Click(Sender: TObject);
procedure Panel1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage('Button1Click 執行了');
end;
procedure TForm1.Panel1Click(Sender: TObject);
begin
// 方式 1:直接呼叫表單方法 (Sender 傳 Form1)
// 特點:不需要 Button1 物件存在,只要方法編譯進去即可執行
Form1.Button1Click(Form1);
// 方式 2:呼叫 Button1 物件的 Click 方法
// 特點:需要 Button1 物件存在 (設計時放置或執行時建立)
// 若設計時刪除 Button1,此行編譯錯誤:Undeclared identifier 'Button1'
Form1.Button1.Click;
{
關鍵差異總結:
- Button1Click(Form1) 是呼叫 TForm1 的方法,屬於表單類別成員
- Button1.Click 是呼叫 TButton 實例的方法,屬於控制項實例成員
- 設計時刪除 Button1,Button1 欄位聲明消失,Button1.Click 自然無法編譯
- 但 Button1Click 方法仍保留在 TForm1 中 (除非手動刪除)
}
end;
end.
OnClick,IDE 自動:
procedure Button1Click(Sender: TObject);OnClick = Button1Click 關聯TReader 將事件屬性指派給 Button1.OnClick := Button1Click (方法指標)procedure TForm1.CreateDynamicButton;
var
Btn: TButton;
begin
Btn := TButton.Create(Self);
Btn.Parent := Self;
Btn.SetBounds(10, 10, 100, 30);
Btn.Caption := '動態按鈕';
// 正確綁定:指派方法指標 (需方法簽名相符)
Btn.OnClick := Button1Click; // 共用現有方法
// 或指派匿名方法 (Delphi 10.4+)
// Btn.OnClick := procedure(Sender: TObject) begin ShowMessage('動態!'); end;
end;
| 現象 | 原因 | 解決 |
|---|---|---|
| 呼叫 Button1.Click 無反應 | Button1 未建立或 Parent 錯誤導致不可見 | 檢查 Button1.Assigned、Visible、Enabled、Parent |
| 動態建立按鈕點擊無反應 | 未指派 OnClick、或指派錯誤方法指標 | Btn.OnClick := 正確方法指標 |
| 跨表單呼叫 Button1Click 失效 | Sender 參數期望 TObject,傳入錯誤類型 | 傳入 Self 或 Sender 來源物件 |
| 刪除按鈕後編譯錯誤 | 殘留程式碼呼叫 Button1.Click | 搜尋並移除所有 Button1.Click 呼叫 |
| OnClick 觸發兩次 | 同時指派 OnClick 又呼叫 Click、或父控制項也處理點擊 | 檢查事件鏈、避免重複觸發 |
procedure TControl.Click;
begin
if Assigned(FOnClick) then
FOnClick(Self); // 呼叫事件處理函數,Sender = Self (按鈕自身)
// 另有繼承鏈處理...
end;
Button1Click(Sender) 是表單方法,Button1.Click 是控制項實例方法。前者不依賴控制項實例存在,後者強依賴。設計時刪除控制項只移除欄位與 .dfm 關聯,**不自動清理事件方法原始碼**,這是 IDE 保守策略 (避免誤刪業務邏輯)。動態建立控制項時,務必手動指派 OnClick := 方法指標。掌握這三層關係,按鈕事件處理將不再有陰影。