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