Winamp的用戶都知道,Winamp的播放列表或均衡器在被移動(dòng)的時(shí)候,仿佛會(huì)受到一股磁力,每當(dāng)靠近主窗口時(shí)就一下子被“吸附”過去,自動(dòng)沿邊對齊。我想讓我的Winamp插件也具備這種奇妙特性,于是琢磨出了一種“磁化”窗口的方法。該法適用于Delphi的各個(gè)版本。為了演示這種技術(shù),請隨我來制作一個(gè)會(huì)被Winamp“吸引”的樣板程序。
先新建一應(yīng)用程序項(xiàng)目,把主窗口Form1適當(dāng)改小些,并將BorderStyle設(shè)為bsNone。放一個(gè)按鈕元件,雙擊它并在OnClick事件中寫“Close;”。待會(huì)兒就按它來結(jié)束程序?,F(xiàn)在切換到代碼編輯區(qū),定義幾個(gè)全局變量。
var
Form1: TForm1; //“磁性”窗口
LastX, LastY: Integer; //記錄前一次的坐標(biāo)
WinampRect:Trect; //保存Winamp窗口的矩形區(qū)域
hwnd_Winamp:HWND; //Winamp窗口的控制句柄
接著編寫Form1的OnMouseDown和OnMouseMove事件。
procedure TForm1.FormMouseDown(Sender: Tobject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
const
ClassName=‘Winamp v1.x’; //Winamp主窗口的類名
//如果改成ClassName=‘TAppBuilder’,你就會(huì)發(fā)現(xiàn)連Delphi也有引力啦!
begin
//記錄當(dāng)前坐標(biāo)
LastX := X;
LastY := Y;
//查找Winamp
hwnd_Winamp := FindWindow(ClassName,nil);
if hwnd_Winamp>0 then //找到的話,記錄其窗口區(qū)域
GetWindowRect(hwnd_Winamp, WinampRect);
end;
procedure TForm1.FormMouseMove(Sender: Tobject; Shift: TShiftState; X,
Y: Integer);
var
nLeft,nTop:integer; //記錄新位置的臨時(shí)變量
begin
//檢查鼠標(biāo)左鍵是否按下
if HiWord(GetAsyncKeyState(VK_LBUTTON)) > 0 then
begin
//計(jì)算新坐標(biāo)
nleft := Left + X - LastX;
nTop := Top + Y - LastY;
//如果找到Winamp,就修正以上坐標(biāo),產(chǎn)生“磁化”效果
if hwnd_Winamp>0 then
Magnetize(nleft,ntop);
//重設(shè)窗口位置
SetBounds(nLeft,nTop,width,height);
end;
end;
別急著,看Magnetize()過程,先來了解一下修正坐標(biāo)的原理。根據(jù)對Winamp實(shí)現(xiàn)效果的觀察,我斗膽給所謂“磁化”下一個(gè)簡單的定義,就是“在原窗口與目標(biāo)窗口接近到某種預(yù)定程度,通過修正原窗口的坐標(biāo),使兩窗口處于同一平面且具有公共邊的過程”。依此定義,我設(shè)計(jì)了以下的“磁化”步驟。第一步,判斷目標(biāo)窗口(即Winamp)和我們的Form1在水平及垂直方向上的投影線是否重疊?!澳撤较蛲队熬€有重疊”是“需要進(jìn)行坐標(biāo)修正”的必要非充分條件。判斷依據(jù)是兩投影線段最右與最左邊界的差減去它們寬度和的值的正負(fù)。第二步,判斷兩窗口對應(yīng)邊界是否靠得足夠近了??隙ǖ脑捑妥屗鼈兒蠑n。
好了,下面便是“神秘”的Magnetize過程了……
procedure TForm1.Magnetize(var nl,nt:integer);
//內(nèi)嵌兩個(gè)比大小的函數(shù)
function Min(a,b:integer):integer;
begin
if a>b then result:=b else result:=a;
end;
function Max(a,b:integer):integer;
begin
if a end;
var
H_Overlapped,V_Overlapped:boolean; //記錄投影線是否重疊
tw,ww,wh:integer; //臨時(shí)變量
const
MagneticForce:integer=50; //“磁力”的大小。
//準(zhǔn)確的說,就是控制窗口邊緣至多相距多少像素時(shí)需要修正坐標(biāo)
//為了演示,這里用一個(gè)比較夸張的數(shù)字——50。
//一般可以用20左右,那樣比較接近Winamp的效果
begin
//判斷水平方向是否有重疊投影
ww := WinampRect.Right-WinampRect.Left;
tw := Max(WinampRect.Right,nl+Width)-Min(WinampRect.Left,nl);
H_Overlapped := tw<=(Width+ww);
//再判斷垂直方向
wh := WinampRect.Bottom-WinampRect.Top;
tw := Max(WinampRect.Bottom,nt+Height)-Min(WinampRect.Top,nt);
V_Overlapped := tw<=(Height+wh);
//足夠接近的話就調(diào)整坐標(biāo)
if H_Overlapped then
begin
if Abs(WinampRect.Bottom-nt)
else if Abs(nt+Height-WinampRect.Top)
end;
if V_Overlapped then
begin
if Abs(WinampRect.Right-nl)
else if Abs(nl+Width-WinampRect.Left)
end;
end;
怎么樣?運(yùn)行后效果不錯(cuò)吧!