创建透明的窗体并移动它上面的子窗体
ByCorbin Dunn
你也许见过带有透明区域的窗体,并想知道在Delphi里面如何实现。很简单,有几种不同的方法能取得下面的效果:
第一种解决的方法是给窗体添加WS_EX_TRANSPARENT风格。这种方法可行,但是达不到期望的全部效果,Microsoft建议对生命短暂的模式窗体使用WS_EX_TRANSPARENT风格。
第二种解决方法是使用Windows 2000新的分层窗口的功能。然而,这样会限制你的应用程序只能运行在Windows2000。
这篇文章选择了第三种方法。您可以调用Windows API的SetWindowRgn来指定窗口的哪些区域是你想要看到的,难点之一是创建这个区域,它包含所有你想看到的所有子窗体。解决的办法是枚举窗体上所有可见的控件,把这些控件占的小区域合并成一个大区域。下面就是实现的代码:
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
// Create a region for each given visible control
RgnCtrl := CreateRectRgn(Left, Top, Left + Width, Top + Height);
// Combine the region with all previous ones, if available
if (RgnCtrl <> 0) and (RgnAll <> 0) then
begin
CombineRgn(RgnAll, RgnAll, RgnCtrl, RGN_OR);
DeleteObject(RgnCtrl);
end
else
RgnAll := RgnCtrl;
// This is the first region being created
end;
end;
end;
// Now, set the RgnAll as what we see for the Window
if RgnAll <> 0 then
begin
(*
From SetWindowRgn in the help file:
"After a successful call to SetWindowRgn,
the operating system owns the region specified
by the region handle hRgn. The operating system
does not make a copy of the region. Thus, you
should not make any further function calls with
this region handle. In particular, do not close
this region handle."
So don't call DeleteObject on RgnAll after using
it for SetWindowRgn (thanks to Richard Albury for
pointing this out!) A previous version of this article
made this mistake.
*)
SetWindowRgn(Handle, RgnAll, True);
end;
end
;
注意我在使用完一个区域后调用了DeleteObject ,不这样做将导致Windows资源泄漏。API CreateRectRgn是创建矩形区域,如果你的形状不同,可以使用CreatePolygonRgn来精确定义窗口或控件的形状。
移动窗体上的控件时你可能会遇到一个问题。如果编程移动控件(如在OnMouseMove事件里面),控件会超出上面创建的区域;此外,移动的时候也可能无法正确绘制控件。一个简单的解决办法是:移动的同时调用SetRegions,更新窗体的可见区域;并调用Control.Repaint,强制重绘控件。代码如下:
procedure
TForm1.GenericMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
begin
// If the control wasn't moved, then exit right away
if (X - LastX = 0) and (Y - LastY = 0) then Exit;
// Move the control
with (Sender as TControl) do
begin
Left := Left + (X - LastX);
Top := Top + (Y - LastY);
end;
SetRegions;
(Sender as TControl).Repaint;
end
;
在你的应用程序中添加透明窗体,现在应该不成问题。
原文来源:http://edn.embarcadero.com/article/26277