DelphiX 的 TPictureCollectionItem.StretchDraw 方法允許將圖片以任意寬高繪製到目標表面,支援放大、縮小、非等比縮放、鏡像翻轉 (負尺寸)。這是實現 UI 自適應、縮圖預覽、全螢幕背景拉伸、精靈縮放動畫的基礎工具。
function StretchDraw(
Dest: TDirectDrawSurface; // 目標繪圖表面
const DestRect: TRect; // 目標矩形區域 (決定繪製位置與尺寸)
Pattern: Integer // 圖樣索引 (動畫幀)
): Boolean;
| 參數 | 說明 | 特殊用法 |
|---|---|---|
| Dest | 通常為 DXDraw1.Surface (後台緩衝區) | 也可為 DXDraw1.Primary (直接繪製到前台,不建議) |
| DestRect | 目標繪製區域 (Left, Top, Right, Bottom) | Right-Left = 寬度,Bottom-Top = 高度。負寬/高可鏡像翻轉 |
| Pattern | 動畫幀索引 | 靜態圖片為 0 |
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, DXDraws, StdCtrls, DXClass;
type
TForm1 = class(TForm)
DXDraw1: TDXDraw;
DXImageList1: TDXImageList;
Button1: TButton;
Button2: TButton;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
var
PicItem: TPictureCollectionItem;
procedure TForm1.FormCreate(Sender: TObject);
const
ImgPath1 = 'C:\Temp\DelphiX.bmp';
begin
DXImageList1.DXDraw := DXDraw1;
PicItem := TPictureCollectionItem(DXImageList1.Items.Add);
PicItem.Picture.LoadFromFile(ImgPath1);
Button1.Caption := 'StretchDraw 全螢幕拉伸 (填滿)';
Button2.Caption := 'StretchDraw 置中原始比例 (保持比例)';
end;
// 模式 1:全螢幕拉伸填滿 (可能變形)
procedure TForm1.Button1Click(Sender: TObject);
begin
DXDraw1.Surface.Fill(0); // 黑色背景
// 直接使用 ClientRect 矩形,圖片會被拉伸填滿整個客戶區
PicItem.StretchDraw(DXDraw1.Surface, DXDraw1.Surface.ClientRect, 0);
DXDraw1.Flip;
end;
// 模式 2:置中繪製,保持原始寬高比
procedure TForm1.Button2Click(Sender: TObject);
var
r: TRect;
Scale: Single;
DrawW, DrawH: Integer;
begin
DXDraw1.Surface.Fill(0);
// 計算保持比例的縮放比例
Scale := Min(DXDraw1.Width / PicItem.Width, DXDraw1.Height / PicItem.Height);
DrawW := Round(PicItem.Width * Scale);
DrawH := Round(PicItem.Height * Scale);
// 計算置中矩形
r.Left := (DXDraw1.Width - DrawW) div 2;
r.Top := (DXDraw1.Height - DrawH) div 2;
r.Right := r.Left + DrawW;
r.Bottom := r.Top + DrawH;
// 繪製
PicItem.StretchDraw(DXDraw1.Surface, r, 0);
DXDraw1.Flip;
end;
end.
object Form1: TForm1
Left = 0
Top = 0
Caption = 'DelphiX StretchDraw 縮放繪製示例'
ClientHeight = 300
ClientWidth = 400
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
OnCreate = FormCreate
PixelsPerInch = 96
TextHeight = 13
object DXDraw1: TDXDraw
Left = 0
Top = 0
Width = 400
Height = 250
Align = alClient
AutoInitialize = True
AutoSize = True
Color = clBlack
Display.FixedBitCount = False
Display.FixedRatio = True
Display.FixedSize = True
Options = [doAllowReboot, doWaitVBlank, doCenter, do3D, doDirectX7Mode, doHardware, doSelectDriver]
SurfaceHeight = 250
SurfaceWidth = 400
TabOrder = 0
Traces = <>
end
object Button1: TButton
Left = 10
Top = 260
Width = 180
Height = 30
Caption = 'Button1'
TabOrder = 1
OnClick = Button1Click
end
object Button2: TButton
Left = 210
Top = 260
Width = 180
Height = 30
Caption = 'Button2'
TabOrder = 2
OnClick = Button2Click
end
object DXImageList1: TDXImageList
Left = 40
Top = 40
end
end
procedure StretchDrawKeepAspect(
PicItem: TPictureCollectionItem;
Dest: TDirectDrawSurface;
const TargetRect: TRect; // 目標區域 (如 ClientRect)
Pattern: Integer = 0;
AlignHorizontal: TAlign = alCenter; // alLeft, alCenter, alRight
AlignVertical: TAlign = alCenter // alTop, alCenter, alBottom
);
var
Scale: Single;
DrawW, DrawH, DrawX, DrawY: Integer;
DestW, DestH: Integer;
r: TRect;
begin
DestW := TargetRect.Right - TargetRect.Left;
DestH := TargetRect.Bottom - TargetRect.Top;
// 計算最大等比縮放
Scale := Min(DestW / PicItem.Width, DestH / PicItem.Height);
DrawW := Round(PicItem.Width * Scale);
DrawH := Round(PicItem.Height * Scale);
// 水平對齊
case AlignHorizontal of
alLeft: DrawX := TargetRect.Left;
alCenter: DrawX := TargetRect.Left + (DestW - DrawW) div 2;
alRight: DrawX := TargetRect.Right - DrawW;
else DrawX := TargetRect.Left + (DestW - DrawW) div 2;
end;
// 垂直對齊
case AlignVertical of
alTop: DrawY := TargetRect.Top;
alCenter: DrawY := TargetRect.Top + (DestH - DrawH) div 2;
alBottom: DrawY := TargetRect.Bottom - DrawH;
else DrawY := TargetRect.Top + (DestH - DrawH) div 2;
end;
r := Rect(DrawX, DrawY, DrawX + DrawW, DrawY + DrawH);
PicItem.StretchDraw(Dest, r, Pattern);
end;
// 水平鏡像 (左右翻轉)
r.Left := CenterX + Width div 2;
r.Right := CenterX - Width div 2; // Right < Left 產生負寬度
PicItem.StretchDraw(Surface, r, 0);
// 垂直鏡像 (上下翻轉)
r.Top := CenterY + Height div 2;
r.Bottom := CenterY - Height div 2; // Bottom < Top 產生負高度
PicItem.StretchDraw(Surface, r, 0);
// 同時水平垂直鏡像 = 旋轉 180°
var
ScalePhase: Single = 0;
BaseScale: Single = 1.0;
procedure TForm1.DXTimer1Timer(Sender: TObject; LagCount: Integer);
var
r: TRect;
CurrentScale: Single;
DrawW, DrawH: Integer;
begin
DXDraw1.Surface.Fill(0);
// 正弦波縮放動畫 0.8x ~ 1.2x
ScalePhase := ScalePhase + 0.1 * (LagCount + 1);
CurrentScale := BaseScale + 0.2 * Sin(ScalePhase);
DrawW := Round(PicItem.Width * CurrentScale);
DrawH := Round(PicItem.Height * CurrentScale);
r := Rect(
(DXDraw1.Width - DrawW) div 2,
(DXDraw1.Height - DrawH) div 2,
(DXDraw1.Width + DrawW) div 2,
(DXDraw1.Height + DrawH) div 2
);
PicItem.StretchDraw(DXDraw1.Surface, r, 0);
DXDraw1.Flip;
end;
DelphiX 無內建九宮格,需手動實現:將圖片分為 9 區 (四角不變、邊緣單向拉伸、中心雙向拉伸),分別 StretchDraw 到對應目標區域。適用於對話框邊框、按鈕背景、進度條等 UI 元件。
| 方法 | 縮放 | 旋轉 | 透明度 | 混合模式 | 效能 | 適用場景 |
|---|---|---|---|---|---|---|
| Draw | 否 (原始尺寸) | 否 | 透明色 | 普通 | 最快 | 固定尺寸精靈、UI 圖示 |
| StretchDraw | 是 (任意矩形) | 否 | 透明色 | 普通 | 快 | UI 自適應、縮圖、背景拉伸 |
| DrawRotate | 是 (Width/Height) | 是 (Angle) | 透明色 | 普通 | 中等 | 旋轉精靈、指針、車輛 |
| DrawRotateAdd/Sub/Alpha... | 是 | 是 | Alpha/混合 | 加色/減色/Alpha | 較慢 | 特效、粒子、魔法、UI 高亮 |
Rect() 快速構造TDXTextureImage 的 MipmapdoHardware 和 doDirectX7Mode 啟用,StretchDraw 會使用顯卡雙線性過濾PicItem.SystemMemory := True 可加快 CPU 端像素操作,但 GPU 繪製可能較慢| 問題 | 原因 | 解決 |
|---|---|---|
| 圖片模糊/鋸齒嚴重 | 放大倍數過大或雙線性過濾不佳 | 使用高解析度源圖;檢查 DirectX 設備過濾模式 |
| 透明區域出現邊緣/白邊 | 縮放插值導致透明色邊緣混色 | 預乘 Alpha 處理圖片;使用 32位含 Alpha 通道圖片 |
| 負尺寸不生效/繪製異常 | Rect 定義順序錯誤 | 確保 Left > Right 或 Top > Bottom 產生負寬/高 |
| 縮放比例計算錯誤 | 整數除法截斷 | 使用 Single/Double 計算,最後 Round 到 Integer |
| StretchDraw 無視透明色 | Transparent 屬性未設定 | PicItem.Transparent := True; PicItem.TransparentColor := clFuchsia (或實際透明色) |
StretchDraw 是 DelphiX 實現任意尺寸縮放繪製的核心方法。掌握 TRect 定義目標區域、保持比例計算、負尺寸鏡像翻轉、動畫縮放等技巧,可構建靈活的 UI 自適應系統、精靈縮放動畫、縮圖預覽等功能。關鍵在於理解 DestRect 的幾何含義,配合 Fill 清除背景與 Flip 雙緩衝顯示,即可獲得流暢的縮放視覺效果。