2012年8月31日星期五

转: 窗体间相互连动

窗体间相互连动

设其中一个为主窗体,另一个为子窗体。    在Delphi程序设计中,窗体(Form)的Position特性取值为poDesigned,则窗体的显示位置和大小以特性Left、Top、 Width、Height的取值为依据来决定。这样在创建子窗体时,以获得主窗体的显示位置和大小(主窗体的Left、Top、Width、Height 的特性值)为基准,然后确定子窗体的位置和大小即可。    
        窗体的初始显示位置,可用CreateParams方法进行设置,之后用重载子窗体(Form1)的CreateParams方法,来改变子窗体的显示位 置和大小。主窗体和子窗体之间是怎样互相引用的呢?首先设置窗体(Form1)的单元文件名为unit1.pas,子窗体(Form2)的单元文件名为 unit2.pas。通常要引用某窗体单元文件的特性和内容时,应该在interface的uses处插入其窗体(Form)的单元名(unit)。本实 例中根据主窗体动态生成子窗体,因此在主窗体(Form1)的interface的uses处插入子窗体的单元名(unit2)。这样主窗体即可引用子窗 体的各种特性值。另一方面要实现子窗体引用主窗体的各种特性值又怎么办呢?由于Pascal语言不允许相互循环引用,即A到B,并且B到A。这时,必须在 imptementation的uses处插入主窗体的单位名(unit1),这样即可对主窗体(Form1)的特性值进行引用。    
        引用方法如下:    
   implementation    
   {$R    *.DFM}      
   uses Unit1;//主窗体单元名    
   {生成窗体时参考数的初始化}    
   procedure    TForm2.CreateParams(var    Params:    TCreateParams);    
   begin    
        inherited    CreateParams(Params);    
        //当没有窗体题目时,添加细框    
     if    BorderStyle    =    bsNone    then      
         Params.Style    :=    Params.Style    or    WS_THICKFRAME;      
        //根据主窗体的显示位置和大小决定子窗体的显示位置和大小      
         with    Form1    do      
         begin      
          Params.X    :=    Left    +    Width;      
          Params.Y    :=    Top;      
          Params.Height    :=    Height;      
          Params.Width    :=    100;      
         end;    
   end;    
        这样即完成了对应主窗体的子窗体在其右侧显示的程序设计。现在当我们移动主窗体时,子窗体并不随之移动,自然,移动子窗体时,主窗体也不会移动。虽然通常的Windows的应用程序则到此为止,但是我们的主题是要讨论连动,下面我们继续介绍这一问题。    
        首先要搞清楚,怎样把握自身窗体的移动和大小变化。在窗体的移动和大小变化时Windows系统要送出WINDOWSPOSCHANGED消息,为了捕捉此消息,对以下方法(Method)进行说明:    
   type      
        Tform1    =    class(Tform)      
    protected      
    procedure    WMWindowPosChanged(vax    Msg:TWMWindowPosChanged);    
        message    WM_WINDOWPOSCHANGED;    
        WM_WINDOWPOSCHANGED消息是在窗体的位置和大小变化后送出的。上面是对WM_WONDOWPOSCHANGED消息句柄的说明,接着是TWMWindowsPosChanged消息记录型和TWindowPos记录内容的定义。    
   type      
        TWMWindowPosMsg    =    record      
        Msg:Cardind;      
        Unused:Integer;      
        WindowPos:PwindowPos;      
        Resukt:Longint;      
   end;      
   PwindowPos    =    ∧TWindowPos;    
   TwindowPos    =    packed    record      
        hwnd:HWND;    //自身的窗体句柄      
        hwndInsertAfeer:HWND;//变更Z的顺序时,最上层窗体句柄      
        x:Integer//新窗体左端的位置      
        y:Integer//新窗体上端的位置      
        cx:Integer//新窗体上端的宽    
        cy:Integer//新窗体上端的高      
        flags:UINT//变更内容(移动、大小    、Z顺序等)      
   end;    
        下面具体介绍此方法的使用,首先要确认子窗体是否存在,而后确认自身的显示位置,一旦发生变更就使用WindowSAPI的SetWindowPos,以变更子窗体的显示位置和大小。要注意的是只是主窗体发生变更时才使用。    
        这样即可使子窗体随主窗体的变更而变更。接着我们还希望主窗体随子窗体的变更而变更。以下先是主窗体变更使子窗体变更的处理过程。    
   const      
        uFlag    =    SWP_NOACTIVATE    or    SWP_NOZORDER    or    SWP_NOMOVE    orSWP_NOSIZE;      
         //大小变更、位置移动结束通知      
        porcedure    TForm1.WMWindowPosChanged(var    Msg:TWMWindowPosChanged);      
         var    Rect:TRect;    
          x,y,cx,cy:Integer;    
          uFlag2:UINT;    
        begin      
        inherited;    
         if    Form2    <>    nil    then      
          //如果子窗体存在      
          begin      
           GetWindowRoct(Form2.Handle,Rect);    //获取子窗体的位置      
            With    Msg    do      
            begin      
         x:=    WindowPos^.x    +    WindowPos^.cx;    //新x坐标      
         y:=    Window^.y;    //新y坐标    
             cx:=    100;    //宽固定在100      
             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      
           //对子窗体(Form)进行变更      
            setWindowPos(Form2.Handle,0,x,y,cx,cy,uFlag2);    
         以上处理是从主窗体的新位置来计算子窗体的新位置,然后与现

没有评论: