也許你曾經看見過這樣的一些窗體,它的一部分是透明的。那麼我們在Delphi中應該怎麼實現這種效果呢?下面的將說到如何實現這種效果:
一種方法是為你的窗體添加 WS_EX_TRANSPARENT 樣式。雖然它可以動作起來,但是它還不能完全實現我們想要的效果,而且,微軟也建議只為那些運行期比較短的樣式窗體使用 WS_EX_TRANSPARENT 樣式。
第二種方法就是應用WIN2000所支持的層次化窗體特性。不過這將使你的應用程序只局限在WIN2000下使用。
本文所采用的是第三種方法。你可以使用 SetWindowRgn API函數精確的指定你所需要窗體顯示的部分。這其中最困難的就是要創建你所要顯示的那部分窗體的區域。解決問題的辦法就是遍歷窗體上所有可視的控件,然後創建包含所有這些小區域的一個巨大的區域。下面是具體的實現:
procedure TForm1.SetRegions;
var
I: Integer;
RgnAll, RgnCtrl: HRGN;
begin
RgnAll := 0;
for I := 0 to ControlCount - 1 do
begin
with Controls[I] do
begin
if Visible then
begin
// 為所有的可視控件創建一個區域
RgnCtrl := CreateRectRgn(Left, Top, Left + Width, Top + Height);
// 組合上面創建的所有區域
if (RgnCtrl <> 0) and (RgnAll <> 0) then
begin
CombineRgn(RgnAll, RgnAll, RgnCtrl, RGN_OR);
DeleteObject(RgnCtrl);
end
else
RgnAll := RgnCtrl; // 這是第一個創建的區域
end;
end;
end;
// Now, set the RgnAll as what we see for the Window
if RgnAll <> 0 then
begin
(*
下面是SetWindowRgn在幫助文件中的注釋:
”當調用SetWindowRgn成功後,操作系統將擁有區域句柄hRgn所指定的區域。並且操作系統沒有為這個區域考貝副本。因此,你不應再用這個區域句柄調用其它的函數。特別是不要關閉這個句柄。”
因此不要在使用SetWindowRgn後對RgnAll調用DeleteObject(感謝Richard Albury指出這點)該文的以前版本就范了以上錯誤。
*)
SetWindowRgn(Handle, RgnAll, True);
end;
end;
注意,我在使用完這個區域後應該怎樣調用DeleteObject呢。如果不調用,將導致Windows資源的洩漏。我使用API CreateRectRgn,如果你有不同的形狀也可以使用CreatePolygonRgn。
你會碰到的一個問題是如何處理窗體中移動的控件。如果你作用程序移動控件(比如:在OnMouseMove事件當中),那麼控件後面的區域將會露出來。同樣,控件在移動後也許不能正確的重畫。這有一個簡單的方法就是重新調用etRegions函數更新窗體中可見的區域,並且調用控件的Repaint方法使控強制性的重畫。如下:
procedure TForm1.GenericMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
begin
// 如果控件沒有移動,則立刻退出。
if (X - LastX = 0) and (Y - LastY = 0) then Exit;
// 移動控件
with (Sender as TControl) do
begin
Left := Left + (X - LastX);
Top := Top + (Y - LastY);
end;
SetRegions;
(Sender as TControl).Repaint;
end;
現在你將能為你的窗體添加透明的效果了。