比较难的问题:千千静听的窗体样式如何实现:
    1.磁性窗体;/////这个比较容易
    2.窗体吸附后,拖动主窗体,子窗体随之移动;
    3.改变窗体大小,自动对齐窗体    ***********不要用定时器來实现**********

解决方案 »

  1.   

    嗯,大概知道使用WM_MOVE,WM_MOVING,WM_SIZE...等
      

  2.   

    在form的onmousemove等事件里也能处理一些
      

  3.   

    楼主到底要什么呢?源码还是方法?
    本人思路,用message进行判断后再处理
      

  4.   

    昨晚通過用 DeDe 反編譯 FormMagnet V2.2.2 這個組件,發現它用了鉤子在裡面.老外寫的程序就是不一樣,磁性組件效果最好就是它了,可惜沒有源代碼學習.
    其他的組件如magnetForn,zmagnet,等等都是通過消息實現的,存在很大的缺陷.報告完畢,各位繼續.
      

  5.   

    在JVCL中也有個相同的組件,竟然也是功能一樣,也是一樣使用HOOK實現的.
      

  6.   

    转载
    “磁性”窗口
    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;
      
      

  7.   

    procedure WMWindowPosChanged(var Msg: TWMWindowPosChanged);message WM_WINDOWPOSCHANGED;procedure TForm1.WMWindowPosChanged(var Msg: TWMWindowPosChanged);
    var
      Rect: TRect;
       X, Y, Cx, Cy: Integer;
       uFlag2: UINT;
    begin
      inherited;
      if Form2 <> nil then  //如果子窗体存在
      begin
        GetWindowRect(Form2.Handle, Rect);  //获得子窗体的位置
        with Msg do
        begin
          X := WindowPos^.x + WindowPos^.cx;    //新X坐标
          Y := WindowPos^.y;                   //新Y坐标
          Cx := 112;                            //宽112
          Cy := WindowPos^.cy;                //新高度
        end;
        uFlag2 := uFlag;                //移动必要时
        if (Rect.Top <> Y) or (Rect.Left <> X) then
          uFlag2 := uFlag2 and (not SWP_NOMOVE);
        if (Rect.Bottom - Rect.Top <> Cy) or    //尺寸变更必要时
           (Rect.Right - Rect.Left <> Cx) then
          uFlag2 := uFlag2 and (not SWP_NOSIZE);
        if uFlag <> uFlag2 then                 //都必要时
          SetWindowPos(Form2.Handle, 0, X, Y, Cx, Cy, uFlag2);
      end;
    end;
      

  8.   

    感謝各位了!感謝各位 Copy<--->Paste 的那麼辛苦!謝謝幫忙頂!