C++ Builder (與 Delphi 相同) 的主視窗最小化時沒有動畫效果,根源在於 VCL 架構設計:任務列按鈕代表的是隱藏的 TApplication 視窗 (0×0 像素),而非 MainForm。本文深度剖析 VCL 原始碼機制,並提供修改 VCL 源碼與專案啟動碼的完整解決方案。
TApplication 視窗:隱藏於螢幕中心,大小 0×0,擁有任務列按鈕。MainForm (如 TForm1):非 TApplication 子視窗,無 WS_EX_APPWINDOW 風格,不在任務列顯示按鈕。Application.Minimize 隱藏 TApplication 視窗,同時 Hide MainForm。procedure TApplication.Minimize;
begin
if not IsIconic(FHandle) then begin
NormalizeTopMosts;
SetActiveWindow(FHandle);
ShowWinNoAnimate(FHandle, SW_MINIMIZE); // 關鍵:無動畫最小化
if Assigned(FOnMinimize) then FOnMinimize(Self);
end;
end;
procedure ShowWinNoAnimate(Handle: HWnd; CmdShow: Integer);
var Animation: Boolean;
begin
Animation := GetAnimation;
if Animation then SetAnimation(False); // 暫時關閉系統動畫
ShowWindow(Handle, CmdShow);
if Animation then SetAnimation(True); // 恢復動畫
end;
procedure SetAnimation(Value: Boolean);
var Info: TAnimationInfo;
begin
Info.cbSize := SizeOf(TAnimationInfo);
BOOL(Info.iMinAnimate) := Value;
SystemParametersInfo(SPI_SETANIMATION, SizeOf(Info), @Info, 0);
end;
procedure TCustomForm.WMSysCommand(var Message: TWMSysCommand);
begin
if (Message.CmdType and $FFF0 = SC_MINIMIZE) and (Application.MainForm = Self) then
Application.Minimize // 最小化 Application 視窗,隱藏 Form
else
inherited;
end;
核心思路:賦予 MainForm WS_EX_APPWINDOW 風格,隱藏 Application 視窗,並修改 VCL 讓 MainForm 自行處理最小化。
$(BCB)\Source\Vcl\Forms.pas 複製到專案目錄。Forms 單元,加入本地 Forms.pas。TCustomForm.WMSysCommand:procedure TCustomForm.WMSysCommand(var Message: TWMSysCommand);
begin
{ 註釋掉原有邏輯
if (Message.CmdType and $FFF0 = SC_MINIMIZE) and
(Application.MainForm = Self) then
Application.Minimize
else }
inherited; // 直接讓預設視窗程序處理 SC_MINIMIZE
end;
program Project1;
uses
Windows, // 新增
Unit1 in 'Unit1.pas' {Form1},
Forms in 'Forms.pas'; // 本地修改版
{$R *.RES}
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
// 賦予 WS_EX_APPWINDOW,隱藏 Application 視窗
SetWindowLong(Form1.Handle, GWL_EXSTYLE,
GetWindowLong(Form1.Handle, GWL_EXSTYLE) or WS_EX_APPWINDOW);
Form1.Show; // 顯示 Form1
ShowWindow(Application.Handle, SW_HIDE); // 隱藏 Application 視窗
Application.Run;
end.
MainForm 最小化/還原擁有系統原生動畫,任務列按鈕直接對應 MainForm。Application 視窗隱藏後,Application.MessageBox、Application.Handle 相關功能可能異常。FormResize 或自訂 Minimize 方法中,使用 AnimateWindow API 或計時器漸變 AlphaBlend 實現自訂動畫,不修改 VCL。OnMinimize 執行自訂動畫邏輯。// 在 FormCloseQuery 或自訂 Minimize 方法中
if (CanClose) {
AnimateWindow(Handle, 300, AW_BLEND | AW_HIDE); // 300ms 淡出
// 或滑動動畫
// AnimateWindow(Handle, 300, AW_SLIDE | AW_HOR_NEGATIVE | AW_HIDE);
}
建議採用「自繪動畫」或「接受預設」方案,避免修改 VCL 核心帶來的潛在風險。若專案極度依賴原生任務列動畫體驗,可參考本文方案並在完整測試後謹慎採用。