• Delphi磁性窗口


    昨天要用到磁性窗口,就是两个窗口离得近到一个距离就吸附到一起.拖动主窗口,吸附窗体一块运动.

    到网上搜了一下,基本没见到可以使用的.有个东东,还是收费的.没办法自己写了一个.

    用法很简单,把你的窗口都改成从这个继承即可生效.例如

    type
      TForm3 = class(TCustomMagnetForm)
      private
        { Private declarations }

      public
        { Public declarations }
      end;

    var
      Form3: TForm3;

    不多说了,上代码

    { ******************************************************* }
    { }
    { 磁性吸附窗口 }
    { }
    { 版权所有 (C) 2011 wr960204武稀松 }
    { }
    { ******************************************************* }

    unit MagnetForm;

    interface

    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, Generics.Collections;

    type
      TCustomMagnetForm = class(TForm)
      private type
        TMagnetFormList = TList<TCustomMagnetForm>;
        class var
        // 吸附距离
          FMagnetBuffer: Integer;

      var
        // 吸附子窗口容器
        FMagnetClientList: TMagnetFormList;
        // 相对主窗口的位置
        FMagnetPosOffset: TPoint;
        // 可否随主窗口移动
        FEnableMagnetMoveClient: Boolean;
        // 移除子窗口
        procedure RemoveMagnetForm(AForm: TCustomMagnetForm);
        // 添加子窗口
        procedure AddMagnetForm(AForm: TCustomMagnetForm; Value: TPoint);
        // 处理子窗口吸附
        function ProcessClient(var ServerBound, ClientBound: TRect): Boolean;
        // 处理主窗口吸附
        function ProcessServer(var ServerBound, ClientBound: TRect;
          AClient: TCustomMagnetForm): Boolean;
        // 主窗口移动
        procedure ProcessServerMove();

      protected
        procedure WMWindowPosChanging(var Message: TWMWindowPosChanging);
          message WM_WINDOWPOSCHANGING;
        procedure WMMoving(var Message: TWMMoving); message WM_MOVING;
        procedure WMMove(var Message: TWMMove); message WM_MOVE;
        procedure DoClose(var Action: TCloseAction); override;
        procedure WMSysCommand(var Message: TWMSysCommand); message WM_SYSCOMMAND;

      public
        constructor Create(AOwner: TComponent); override;
        destructor Destroy; override;
        class property MagnetBuffer: Integer read FMagnetBuffer write FMagnetBuffer;
      end;

    implementation

    { TCustomMagnetForm }

    constructor TCustomMagnetForm.Create(AOwner: TComponent);
    begin
      inherited Create(AOwner);
      FMagnetClientList := TMagnetFormList.Create;
    end;

    destructor TCustomMagnetForm.Destroy;
    begin
      if Self <> Application.MainForm then
        RemoveMagnetForm(Self);
      FMagnetClientList.Free;
      inherited Destroy;
    end;

    procedure TCustomMagnetForm.DoClose(var Action: TCloseAction);
    begin
      inherited DoClose(Action);
      if Self <> Application.MainForm then
        RemoveMagnetForm(Self);
    end;

    function TCustomMagnetForm.ProcessClient(var ServerBound,
      ClientBound: TRect): Boolean;
    var
      lspace, rspace, tspace, bspace: Integer;
    begin
      Result := False;
      lspace := ABS(ClientBound.Right - ServerBound.Left);
      rspace := ABS(ClientBound.Left - ServerBound.Right);
      tspace := ABS(ClientBound.Bottom - ServerBound.Top);
      bspace := ABS(ClientBound.Top - ServerBound.Bottom);

      FMagnetPosOffset := Point(ClientBound.Left - ServerBound.Left,
        ClientBound.Top - ServerBound.Top);

      if (ClientBound.Bottom > ServerBound.Top) and
        (ClientBound.Top < ServerBound.Bottom) then
      begin
        if lspace < rspace then
        begin
          if lspace < FMagnetBuffer then
          begin
            AddMagnetForm(Self, Point(ClientBound.Left - ServerBound.Left,
              ClientBound.Top - ServerBound.Top));
            OffsetRect(ClientBound, (ServerBound.Left - ClientBound.Right), 0);
            Result := True;
          end;
        end
        else
        begin
          if rspace < FMagnetBuffer then
          begin
            AddMagnetForm(Self, Point(ClientBound.Left - ServerBound.Left,
              ClientBound.Top - ServerBound.Top));
            OffsetRect(ClientBound, (ServerBound.Right - ClientBound.Left), 0);
            Result := True;
          end;
        end;
      end;
      if (ClientBound.Right > ServerBound.Left) and
        (ClientBound.Left < ServerBound.Right) then
      begin
        if tspace < bspace then
        begin
          if tspace < FMagnetBuffer then
          begin
            AddMagnetForm(Self, Point(ClientBound.Left - ServerBound.Left,
              ClientBound.Top - ServerBound.Top));
            OffsetRect(ClientBound, 0, ServerBound.Top - ClientBound.Bottom);
            Result := True;
          end;
        end
        else
        begin
          if bspace < FMagnetBuffer then
          begin
            AddMagnetForm(Self, Point(ClientBound.Left - ServerBound.Left,
              ClientBound.Top - ServerBound.Top));
            OffsetRect(ClientBound, 0, ServerBound.Bottom - ClientBound.Top);
            Result := True;
          end;
        end;
      end;
    end;

    function TCustomMagnetForm.ProcessServer(var ServerBound, ClientBound: TRect;
      AClient: TCustomMagnetForm): Boolean;
    var
      lspace, rspace, tspace, bspace: Integer;
    begin
      Result := False;
      lspace := ABS(ClientBound.Right - ServerBound.Left);
      rspace := ABS(ClientBound.Left - ServerBound.Right);
      tspace := ABS(ClientBound.Bottom - ServerBound.Top);
      bspace := ABS(ClientBound.Top - ServerBound.Bottom);

      FMagnetPosOffset := Point(ClientBound.Left - ServerBound.Left,
        ClientBound.Top - ServerBound.Top);

      if (ClientBound.Bottom > ServerBound.Top) and
        (ClientBound.Top < ServerBound.Bottom) then
      begin
        if lspace < rspace then
        begin
          if lspace < FMagnetBuffer then
          begin
            AddMagnetForm(AClient, Point(ClientBound.Left - ServerBound.Left,
              ClientBound.Top - ServerBound.Top));
            OffsetRect(ServerBound, -(ServerBound.Left - ClientBound.Right), 0);
            Result := True;
          end;
        end
        else
        begin
          if rspace < FMagnetBuffer then
          begin
            AddMagnetForm(AClient, Point(ClientBound.Left - ServerBound.Left,
              ClientBound.Top - ServerBound.Top));
            OffsetRect(ServerBound, -(ServerBound.Right - ClientBound.Left), 0);
            Result := True;
          end;
        end;
      end;
      if (ClientBound.Right > ServerBound.Left) and
        (ClientBound.Left < ServerBound.Right) then
      begin
        if tspace < bspace then
        begin
          if tspace < FMagnetBuffer then
          begin
            AddMagnetForm(AClient, Point(ClientBound.Left - ServerBound.Left,
              ClientBound.Top - ServerBound.Top));
            OffsetRect(ServerBound, 0, -(ServerBound.Top - ClientBound.Bottom));
            Result := True;
          end;
        end
        else
        begin
          if bspace < FMagnetBuffer then
          begin
            AddMagnetForm(AClient, Point(ClientBound.Left - ServerBound.Left,
              ClientBound.Top - ServerBound.Top));
            OffsetRect(ServerBound, 0, -(ServerBound.Bottom - ClientBound.Top));
            Result := True;
          end;
        end;
      end;
    end;

    procedure TCustomMagnetForm.ProcessServerMove;
    var
      i: Integer;
      p: TPoint;
    begin
      Inherited;
      if Self = Application.MainForm then
      begin
        if FMagnetClientList <> nil then
          for i := 0 to FMagnetClientList.Count - 1 do
          begin
            if FMagnetClientList[i].FEnableMagnetMoveClient then
            begin
              p := FMagnetClientList[i].FMagnetPosOffset;
              FMagnetClientList[i].SetBounds(Left + p.X, Top + p.Y,
                FMagnetClientList[i].Width, FMagnetClientList[i].Height);
            end;
          end;
      end;
    end;

    procedure TCustomMagnetForm.AddMagnetForm(AForm: TCustomMagnetForm;
      Value: TPoint);
    var
      Index: Integer;
    begin
      if (Application.MainForm <> nil) and
        (Application.MainForm is TCustomMagnetForm) then
        with TCustomMagnetForm(Application.MainForm) do
          if FMagnetClientList <> nil then
          begin
            AForm.FMagnetPosOffset := Value;
            Index := FMagnetClientList.IndexOf(AForm);
            if Index < 0 then
            begin
              Index := FMagnetClientList.Add(AForm);
            end;
          end;
    end;

    procedure TCustomMagnetForm.RemoveMagnetForm(AForm: TCustomMagnetForm);
    begin
      AForm.FEnableMagnetMoveClient := False;
      if (Application.MainForm <> nil) and
        (Application.MainForm is TCustomMagnetForm) then
        with TCustomMagnetForm(Application.MainForm) do
          if FMagnetClientList <> nil then
          begin
            if FMagnetClientList.IndexOf(AForm) >= 0 then
            begin
              FMagnetClientList.Remove(AForm);
            end;
          end;
    end;

    procedure TCustomMagnetForm.WMMove(var Message: TWMMove);
    begin
      ProcessServerMove;
    end;

    procedure TCustomMagnetForm.WMMoving(var Message: TWMMoving);
    begin
      ProcessServerMove;
    end;

    procedure TCustomMagnetForm.WMSysCommand(var Message: TWMSysCommand);
      procedure SetAllClientEnableMove();
      var
        i: Integer;
      begin
        Inherited;
        if Self = Application.MainForm then
        begin
          if FMagnetClientList <> nil then
            for i := 0 to FMagnetClientList.Count - 1 do
            begin
              FMagnetClientList[i].FEnableMagnetMoveClient := True;
            end;
        end;
      end;

    begin
      Inherited;
      if (Message.CmdType and SC_MOVE) = SC_MOVE then
      begin
        SetAllClientEnableMove();
      end;
    end;

    procedure TCustomMagnetForm.WMWindowPosChanging(var Message
      : TWMWindowPosChanging);
    var
      ServerBound, ClientBound: TRect;
      lspace, rspace, tspace, bspace: Integer;
      MainForm: TCustomMagnetForm;
      oBound: TRect;
      i: Integer;
    begin
      inherited;

      if (Message.WindowPos^.flags and SWP_NOMOVE) = SWP_NOMOVE then
      begin
        Exit;
      end;

      if (Application.MainForm = nil) or
        (not(Application.MainForm is TCustomMagnetForm)) then
        Exit;

      if (Application.MainForm = Self) then
      begin
        ServerBound := Rect(Message.WindowPos^.X, Message.WindowPos^.Y,
          Message.WindowPos^.X + Message.WindowPos^.cx, Message.WindowPos^.Y +
          Message.WindowPos^.cy);
        for i := 0 to Screen.FormCount - 1 do
        begin
          if (Screen.Forms[i] <> Self) and (Screen.Forms[i] is TCustomMagnetForm)
            and ((FMagnetClientList.IndexOf(TCustomMagnetForm(Screen.Forms[i])) < 0)
            or (not TCustomMagnetForm(Screen.Forms[i])
            .FEnableMagnetMoveClient)) then
          begin
            ClientBound := Screen.Forms[i].BoundsRect;
            TCustomMagnetForm(Screen.Forms[i]).FEnableMagnetMoveClient := False;
            if ProcessServer(ServerBound, ClientBound,
              TCustomMagnetForm(Screen.Forms[i])) then
            begin
              Message.WindowPos^.X := ServerBound.Left;
              Message.WindowPos^.Y := ServerBound.Top;
              Message.WindowPos^.cx := ServerBound.Right - ServerBound.Left;
              Message.WindowPos^.cy := ServerBound.Bottom - ServerBound.Top;

              break;
            end;
          end;
        end;
      end
      else
      begin

        MainForm := TCustomMagnetForm(Application.MainForm);
        MainForm.RemoveMagnetForm(Self);
        ServerBound := Application.MainForm.BoundsRect;
        ClientBound := Rect(Message.WindowPos^.X, Message.WindowPos^.Y,
          Message.WindowPos^.X + Message.WindowPos^.cx, Message.WindowPos^.Y +
          Message.WindowPos^.cy);
        ProcessClient(ServerBound, ClientBound);
        Message.WindowPos^.X := ClientBound.Left;
        Message.WindowPos^.Y := ClientBound.Top;
        Message.WindowPos^.cx := ClientBound.Right - ClientBound.Left;
        Message.WindowPos^.cy := ClientBound.Bottom - ClientBound.Top;
        FEnableMagnetMoveClient := True;
      end;
    end;

    initialization

    TCustomMagnetForm.FMagnetBuffer := 10;

    finalization

    end.

  • 相关阅读:
    ArcGIS JS API多线程克里金插值
    PostGIS计算矢量切片(一)--渲染数据
    Arcpy多线程热力图
    Puppeteer之大屏批量截图
    Echarts 南海诸岛简图显示位置调整
    Echarts地图使用经验-地图变形和添加数据
    springboot的拦截器Interceptor的性质
    Centos7 网络报错Job for iptables.service failed because the control process exited with error code.
    记录一次Service被注入mapper实例的错误
    java中通过Adb判断PC是否连接了移动设备
  • 原文地址:https://www.cnblogs.com/ljl_falcon/p/2420969.html
Copyright © 2020-2023  润新知