Docking windows (overview of From.ScreenSnap included)
Здравейте :) Днес ще Ви покажа как можете да накарате вашия прозорец да се прикача към краищата на работната площ, когато достигне дадено разстояние. Наблюдавах тази функция на доста популярния Winamp и реших, че ще е полезно да го разработя, за да го ползвам в някои мои програмки.
Известно време след написването на тази статия се появи Delphi 7 и вниманието ми веднага се насочи към новата възможност за snap на TForm. Погледнах кода на Borland - 10 реда. По това време моят код беше към 100 реда и естествено веднага се зарибих да оправя нещата. Резултата не закъсня :)
TfmMain = class(TForm)
...
private
pMoved: TPoint;
protected
procedure WMSysCommand(var
Msg: TWMSysCommand); message WM_SYSCOMMAND;
procedure WMMoving(var
Msg: TWMMoving); message WM_MOVING;
end;
var
fmMain: TfmMain;
implementation
procedure TfmMain.WMSysCommand(var
Msg: TWMSysCommand);
const
SC_DRAGMOVE = $F012;
begin
if (Msg.CmdType = SC_MOVE) or
(Msg.CmdType = SC_DRAGMOVE) then
begin //a
new move was started
pMoved.X := 0;
pMoved.Y := 0;
end;
inherited;
end;
procedure TfmMain.WMMoving(var Msg: TWMMoving);
procedure BorderDock(const
ABorder: Integer; var APosition, AChangedPosition:
Integer);
begin
if Abs(ABorder - APosition)
< iDockDistance then
begin //the
position has to change
if Abs(AChangedPosition)
> iDockDistance then
begin //we
need undocking
APosition := APosition + AChangedPosition;
//realize position
AChangedPosition := 0; //nil
the moved variable
end
else
begin //we need to dock the window
AChangedPosition
:= AChangedPosition + APosition - ABorder; //add new change
to the old
APosition := ABorder;
//set new position
end;
end;
end;
begin
if bHasToDock then
begin
with Screen.WorkAreaRect
do
begin //do
dock for all four borders
BorderDock(Left, Msg.DragRect^.Left, pMoved.X);
BorderDock(Top, Msg.DragRect^.Top, pMoved.Y);
BorderDock(Right - Width, Msg.DragRect^.Left,
pMoved.X);
BorderDock(Bottom - Height, Msg.DragRect^.Top,
pMoved.Y);
end;
//realize drag rectangle dimensions
Msg.DragRect^.Right := Msg.DragRect^.Left + Width;
Msg.DragRect^.Bottom := Msg.DragRect^.Top + Height;
end;
inherited;
end;
Моя код отново е по-дълъг, но това се дължи на факта, че използвам друг подход: прихващам съобщението WM_MOVING, което налага и съхранението на промяната в координатите. Забелязах, че при Borland не се използва такава глобална промелива, което е добре (това е така заради закачането към WM_WINDOWPOSCHANGING). Лошото на техния код е, че ако е изключен "Show window contents while dragging" (в Windows), няма да се прикача рамката за индикация на движението (която се използва), тъй като реалното преместване на прозореца става след одобряване на промяната на позицията. Затова и съм избрал WM_MOVING. Той винаги работи :)
Докато разглеждах кода на Forms.pas видях, че има и друг проблем:
HandleEdge(x, Monitor.WorkareaRect.Left, Monitor.WorkareaRect.Left);
HandleEdge(y, Monitor.WorkareaRect.Top, Monitor.WorkareaRect.Top);
Като се вземе предвид, че последните два парамеръра се вадят един от друг, то винаги резултата ще бъде равен на нула. Пример: ако TaskBar (или някоя друга лента) е прикачен вляво или горе. Е, това си е направо бъг. Може би са се объркали с добавянето на третите параметри в тези два случая. Ако се изпуснат ще се използва стойността, която е точно колкото трябва SnapDistance = 0 (за ляв и горен ръб на формата).
ПП В случай, че Ви трябва само главната форма да може да се прикача може да ползвате кода, отделен в собствен модул. Ето ви сорса на моето предложение DockManU.pas , а информация за употребата му ще намерите вътре.
ПП2 Можете да си свалите и компонента TADocker (прикачане на формата,
на която е поставен) от страницата с компоненти на моя сайт. Адреса е :
http://www.kamburov.net/comps.html
Ако по някаква случайност съм изпуснал нещо или сте намерили грешка, Ви моля да отделите една минутка и да драснете някой ред. Надявам се да ползвате моя код, защото смятам, че е добре написан и че съм обърнал внимание на детайлите. Няма смисъл да се създава едно и също нещо два пъти...
Copyright © 2002-2003 Wise Guy
wise_guybg at yahoo.com
Created: 18.08.2002
Last revised: 31.01.2006