在 Delphi 開發中,建立非矩形、不規則形狀的視窗(如圓形、多邊形或任意剪影視窗)是常見需求。關鍵在於從圖片中提取透明區域,構建 Windows 區域(HRGN),再套用至視窗。本文提供一個高效的掃描線演算法實作,並示範如何套用至無框視窗。
函式 GraphicToRGN(mGraphic: TGraphic; mTransPoint: TPoint): HRGN 接收圖形物件與一個透明色參考點,回傳對應的非透明區域組合而成的 HRGN。其核心邏輯為:
mTransPoint 取得的像素顏色作為透明色。CreateRectRgn(x1, y, x2, y+1),並以 CombineRgn(..., RGN_OR) 合併至結果區域。CombineRgn 呼叫次數,顯著提升大圖處理速度。function GraphicToRGN(mGraphic: TGraphic; mTransPoint: TPoint): HRGN;
var
I, J: Integer;
vStart: Integer;
vHandle: HRGN;
vTransColor: TColor;
begin
Result := 0;
if not Assigned(mGraphic) then Exit;
Result := CreateRectRgn(0, 0, 0, 0); // 空區域
with TBitmap.Create do
try
Width := mGraphic.Width;
Height := mGraphic.Height;
Canvas.Draw(0, 0, mGraphic);
vTransColor := Canvas.Pixels[mTransPoint.X, mTransPoint.Y];
for I := 0 to Height - 1 do
begin
vStart := -1; // -1 表示尋找段起點
for J := 0 to Width do // 故意多跑一個 Width 以便在行尾關閉段
begin
// 判斷是否為非透明像素且未越界
if (J < Width) and (Canvas.Pixels[J, I] <> vTransColor) then
begin
if vStart < 0 then vStart := J; // 記錄段起點
end
else if vStart >= 0 then // 遇到透明色或行尾,且已有起點 -> 區段結束
begin
vHandle := CreateRectRgn(vStart, I, J, I + 1);
try
CombineRgn(Result, Result, vHandle, RGN_OR);
finally
DeleteObject(vHandle);
end;
vStart := -1; // 重置
end;
end;
end;
finally
Free;
end;
end;
在無框視窗(BorderStyle := bsNone)中,於按鈕點擊事件呼叫:
procedure TForm1.Button1Click(Sender: TObject);
var
vRGN: HRGN;
begin
BorderStyle := bsNone;
Image1.Left := 0;
Image1.Top := 0;
// 以 Image1 左上角 (0,0) 顏色為透明色
vRGN := GraphicToRGN(Image1.Picture.Graphic, Point(0, 0));
try
// 將區域套用至視窗,True 表示重繪
SetWindowRgn(Handle, vRGN, True);
finally
// 套用成功後系統會擁有區域,這裡仍建議釋放以防萬一
DeleteObject(vRGN);
end;
end;
Canvas.Pixels 存取較慢,極大圖建議用 Scanline 屬性直接操作像素記憶體。Alpha = 0 為透明。掌握此技巧,即可在 Delphi 中輕鬆打破矩形視窗限制,創造極具視覺特色的應用程式介面。