把panel的属性dragKind设为dkDock,dragmode设为dmautomatic,就能成为一独立的窗口。
  但当窗口接近另一窗口时,它又会自动靠近,这样的效果怎样实现呢?
  是要设置它的left,top值吗?

解决方案 »

  1.   

    在Dephi7中的form中是可以进行设置的了,你可以参考它所提供的
    源码研究研究,这只是个建议。
      

  2.   

    拦截WM_MOVE消息即可
    type
      TForm1 = class(TForm)
      private
        procedure WMMOVE(var Msg: TMessage); message WM_MOVE;
      end;
    var
      Form1: TForm1;
    implementation
    {$R *.DFM}
    { TForm1 }
    procedure TForm1.WMMOVE(var Msg: TMessage);
    begin
      Inherited;
      if (Left < 10) and (Top < 10) and 
         (Left <> 0) and (Top <> 0) then // 设定移动到左上角 10 点范围内时贴到边上去
      begin
        Left := 0;
        Top := 0;
        Msg.Result := 0;
      end;
    end;
    end.Winamp的用户都知道,Winamp的播放列表或均衡器在被移动的时候,仿佛会受到一股磁力,每当靠近主窗口时就一下子被“吸附”过去,自动沿边对齐。我想让我的Winamp插件也具备这种奇妙特性,于是琢磨出了一种“磁化”窗口的方法。该法适用于Delphi的各个版本。为了演示这种技术,请随我来制作一个会被Winamp“吸引”的样板程序。
      先新建一应用程序项目,把主窗口Form1适当改小些,并将BorderStyle设为bsNone。放一个按钮元件,双击它并在OnClick事件中写“Close;”。待会儿就按它来结束程序。现在切换到代码编辑区,定义几个全局变量。
      var
       Form1: TForm1; //“磁性”窗口
       LastX, LastY: Integer; //记录前一次的坐标
       WinampRect:Trect; //保存Winamp窗口的矩形区域
       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’,你就会发现连Delphi也有引力啦!
      begin
      //记录当前坐标
      LastX := X;
      LastY := Y;
      //查找Winamp
      hwnd_Winamp := FindWindow(ClassName,nil);
      if hwnd_Winamp>0 then //找到的话,记录其窗口区域
      GetWindowRect(hwnd_Winamp, WinampRect);
      end;
      procedure TForm1.FormMouseMove(Sender: Tobject; Shift: TShiftState; X,
       Y: Integer);
      var
       nLeft,nTop:integer; //记录新位置的临时变量
      begin
      //检查鼠标左键是否按下
       if HiWord(GetAsyncKeyState(VK_LBUTTON)) > 0 then
       begin
       //计算新坐标
       nleft := Left + X - LastX;
       nTop := Top + Y - LastY;
       //如果找到Winamp,就修正以上坐标,产生“磁化”效果
       if hwnd_Winamp>0 then
       Magnetize(nleft,ntop);
       //重设窗口位置
       SetBounds(nLeft,nTop,width,height);
       end;
      end;
      别急着,看Magnetize()过程,先来了解一下修正坐标的原理。根据对Winamp实现效果的观察,我斗胆给所谓“磁化”下一个简单的定义,就是“在原窗口与目标窗口接近到某种预定程度,通过修正原窗口的坐标,使两窗口处于同一平面且具有公共边的过程”。依此定义,我设计了以下的“磁化”步骤。第一步,判断目标窗口(即Winamp)和我们的Form1在水平及垂直方向上的投影线是否重叠。“某方向投影线有重叠”是“需要进行坐标修正”的必要非充分条件。判断依据是两投影线段最右与最左边界的差减去它们宽度和的值的正负。第二步,判断两窗口对应边界是否靠得足够近了。肯定的话就让它们合拢。
      好了,下面便是“神秘”的Magnetize过程了……
      procedure TForm1.Magnetize(var nl,nt:integer);
       //内嵌两个比大小的函数
       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; //临时变量
      const
       MagneticForce:integer=50; //“磁力”的大小。
       //准确的说,就是控制窗口边缘至多相距多少像素时需要修正坐标
       //为了演示,这里用一个比较夸张的数字--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);
      //足够接近的话就调整坐标
      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;
      怎么样?运行后效果不错吧!
      我设计的一个卡拉OK插件就应用了这种技术,你可以到http://www.lotof.com/lyrics去下载它作为参考。
      

  3.   

    to wangchinaking(助人为乐是快乐之本) ( ) 
     我这里没有delphi 7.0to debussy(debussy) ( ) 
     我用这段代码作,怎么没反应的?
      

  4.   

    TMagnetic控件,提供Winamp的磁性粘贴(源代码)(1.01)
    http://www.csdn.net/cnshare/soft/6/6270.shtm
      

  5.   

    这是我改了之后的代码,但里面的hwn_winamp老是为0,即找不到。
    procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    const
      ClassName='Winamp v3.0'; //Winamp主窗口的类名
     //如果改成ClassName=‘TAppBuilder’,你就会发现连Delphi也有引力啦!
    begin
    //记录当前坐标
     LastX := X;
     LastY := Y;
    //查找Winamp
     hwnd_Winamp := FindWindow(ClassName,nil);
     if hwnd_Winamp>0 then //找到的话,记录其窗口区域
      GetWindowRect(hwnd_Winamp, WinampRect);
    end;procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    var
    nLeft,nTop:integer; //记录新位置的临时变量
    begin
    //检查鼠标左键是否按下
     if HiWord(GetAsyncKeyState(VK_LBUTTON)) > 0 then
     begin
    //计算新坐标
      nleft := Left + X -LastX;
      nTop := Top + Y - LastY;
    //如果找到Winamp,就修正以上坐标,产生“磁化”效果
      if hwnd_Winamp>0 then
       Magnetize(nleft,ntop);
    //重设窗口位置
      SetBounds(nLeft,nTop,width,height);
     end;
    end;procedure TForm1.Magnetize(var nl,nt:integer);
    //内嵌两个比大小的函数
    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>b then
      result:=a
     else
      result:=b;
    end;
    var
     H_Overlapped,V_Overlapped:boolean; //记录投影线是否重叠
     tw,ww,wh:integer; //临时变量
    const
     MagneticForce:integer=50; //“磁力”的大小。
    //准确的说,就是控制窗口边缘至多相距多少像素时需要修正坐标
    //为了演示,这里用一个比较夸张的数字--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);
     //足够接近的话就调整坐标
     if H_Overlapped then
     begin
      if Abs(WinampRect.Bottom-nt)< MagneticForce then
       nl:=WinampRect.Bottom
      else if Abs(nt+Height-WinampRect.Top)<MagneticForce then
       nl:=WinampRect.Top -Height;
     end;
     if V_Overlapped then
     begin
      if Abs(WinampRect.Right-nl)<MagneticForce then
       nt:=WinampRect.Right
      else if Abs(nl+Width-WinampRect.Left)<MagneticForce then
       nt:=WinampRect.Left-Width;
     end;
    end;
    怎么做?
      

  6.   

    我用TAppBuilder做为classname找到了handle,但我的delphi报错了.....
    你试试吧
      

  7.   

    我改了之后倒没有报错,好想效果不是太好。我想作的是:一个panel1,可以点击它移动放在任何位置,但如果panel1靠近panel2时,它就像磁性窗口一样主动靠向panel2.
    请问这该如何改?