如何产生一个只有最大化最小化但是没有关闭按扭的窗体?

  可以什么按钮都没有,也可以使关闭按钮变灰不能用,但是不能只没有关闭按钮,除非自己画标题栏。  
   
  什么按钮都没有的方法:  
  BorderIcons属性中biSystemMenu设为false。  
   
  关闭按钮变灰的方法:  
  执行下面代码  
          HMENU   hMenu   =   NULL;  
   
          hMenu   =   GetSystemMenu(this->Handle,   false);  
          EnableMenuItem(hMenu,   6,   MF_BYPOSITION   |   MF_DISABLED);

收藏内容:

  窗   体   设   计    
   
  11.3   窗   体   特   性  
      我们曾经对窗体的特性、方法等进行过较为详细的讨论。这里,我们再对两个关于窗体类型及边界类型的窗体特性进行介绍。  
      设置窗体类型使用特性FormStyle。该特性允许用户有两种选择:一种是普通的SDI窗体——SDI意思是Single   Document   Interface(单文档接口),另一种是组成MDI应用程序的窗体——MDI的意思是Multiple   Document   Interface(多文档接口)。  
      下面列出了FormStyle特性的可能值:  
  ?fsNorma1:窗体是普通的SDI窗口或对话框。  
  ?fsMDIChild:窗体是MDI子窗口。  
  ?fsMDIForm:窗体是MDI父窗口——也就是   MDI应用程序的框架窗口。  
  ?fsStayOnTop:窗体是SDI窗口,   但它总处于其它所有窗口的前面,   除了那些也被设置为“stay-on-top”(留在最前面)的窗口。  
      设置边框样式使用特性BorderStyle。该特性引用窗体的一个可视化元素TFormBorderStyle,有6个可能值:  
  ?bsSizeable:窗体有标准的粗边框,可以拖动边框来调整窗体的大小。这是缺省的样式。  
  ?bsDialog:窗体有标准的对话框边框,它也是粗的,但不能改变大小。拥有这类边框的窗体也就是对话框。  
  ?bsSingle:窗体有一个细边框而且不能改变大小;它也叫作固定边框。与Windows   3.1不同,Windows   95在细边框与粗边框之间没有显示明显的区别。  
  ?bsToolWindow:窗体采用较细的标题栏(使用较小的字体),而且只有一个最小化Close按钮。这是一种不能改变大小的工具栏的特殊类型。  
  ?bsSizeToolWin:窗体采用较细的标题栏,与上一类型相似,但可以改变大小。  
  ?bsNone:窗体没有边框或任何传统的元素(标题、最大化与最小化按钮、系统菜单)。  
  11.4   固   定   窗   体  
   现在,我们来讨论窗体编程的技巧之一──固定窗口的位置。在Delphi的程序设计中,只需将窗体(Form)的特性BorderStyle取值为 bsSizeable,用户就可随意变更窗体的大小和位置的移动。但在应用程序中使用Windows   API函数同样可以改变窗体的这个特性值,并且还可以实现其它目的。  
      当我们在进行窗体移动和大小变更时,在此动作的前一时刻,Windows系统首先向窗体送出WM_WINDOWPOSCHANGING消息。由此消息产生 的WM_WindowPosChanging事件句柄传递来的TWMWindowPosChanging消息记录型的WindowPos,是包含有变更动 作内容的TWindowPos记录的指针。因此,我们可以根据对其内容的变更,来改变动作内容。  
  type   TWindowPosMsg   =   record    
      Msg:Cardinal;    
      Unusrd:Integer;    
      WindowPos:PwindowPos;//lparam   以下记录的指针    
      Result:Longint;  
  end;  
      该TWindowPos记录包含以下内容:    
  PWindowPos   =   ^TWindowPos;    
  TWindowPos   =   Packed   record;    
      hwnd:HWND;//发生动作窗体的句柄    
      hwndInsertAfter:HWND;//变更Z顺序时最上层的窗体句柄    
      x:Integer;/窗体左端的位置    
   y:Integer;//窗体上端的位置    
      cx:Integer;//窗体的宽    
      cy:Integer;//窗体的高    
      flags:UINT;//变更的内容  
      在flags中,与此话题相关的标志如下:  
  ?SWP_NOMOVE——保持现在位置(无视x成员和y成员)  
  ?SWP_NOOWNERZORDER——不变更主窗体Z顺序的位置  
  ?SWP_NOSIZE——保持现在的大小(无视cx成员和cy成员)  
  ?SWP_NOREDEAW——即使有变更,但不重写画面  
  ?SWP_NOZORDER——保持现在Z顺序(无视hwndInsertAfter成员)  
      据此当我们不想让窗体的大小变更时,只要在TWindowPos记录的flags变量中设置SWP_NOSIZE标志即可。同样不想让窗体移动时,则设置SWP_NOMOVE标志。  
      为了达到以上目的,首先要处理WM_WINDOWPOSCHANGING消息,修改flags变量的内容。作为窗体的处理过程(WMWindowPosChanging)如下:  
  {禁止窗体移动、禁止大小变更处理}  
  porcedure   Tform1.WMWindowPosChanging(var   Msg:TWMWindowPosChanging);    
  begin    
      inherited    
      if   bWinStat   [1]   then    
       Msg.WindowPos^.flags   :=   Msg.WindowPos^.flags   or   SWP_NOMOVE;  
      if   bWinStat   [2]   then    
       Msg.WindowPos^.flags   :=   Msg.WindowPos^.flags   or   SWP_NOSIZE;  
  end;  
      此例中使用bWinStat变量(Boolean类型数组),来禁止窗体的移动和大小的修改。    
  11.5   固定窗体的横宽  
      这里我们继续详细介绍关于在窗体的大小修改中固定横宽的方法。  
  ?当我们修改窗体的大小或按下最大化按扭时,Window系统向应用程序窗体送出WM_GETMINMAXINFO消息。由于这个消息中包含有窗体尺寸的 最大和最小值,如果我们适当利用此消息,则可以指定窗体的大小范围。首先定义WM_GETMINMAXINFO消息的句柄。  
  (1)WM_GETMINMAXINFO消息句柄的说明:  
  type    
      TForm1   =   Class(Tform)    
      procedure   WMGetMinMaxInfo(var   Msg:TWMGetMinMaxInfo);  
       message   WM_GETMINMAXINFO;  
  (2)以TWMGetMinMaxInfo记录为参数:  
  TWMGetMinMaxInfo   =   record    
      Msg:Cardinal;    
      Unused:Integer;    
      MinMaxInfo:PMinMaxInfo;    
      Result:Longint;  
  end   ;  
    TWMGetMinMaxInfo中的MinMaxInfo是具有关于窗体大小信息的TMinMaxInfo记录的指针。  
      该记录在Delphi的Windows.Pas文件中是如下说明的:    
  type  
      {Struct   pointed   to   by   WM_GETMINMAXINFO   Iparam}    
      PMinMaxInfo   =   ^TMinMaxInfo;  
      TMinMaxInfo   =   packed   record   ptReserved:Tpoint;   //预留    
      ptMaxSize:Tpoint;   //最大化时的大小    
      ptMaxPosition:Tpoint   ;   //最大化时的位置    
      ptMinTrackSize:Tpoint   ;   //尺寸变更时最小尺寸    
      ptMaxTrackSize:Tpoint   ;   //尺寸变更时最大尺寸    
  end;  
      当按下最大化按扭时,在ptMaxSize和ptMinSize中指定窗体的大小和位置。当拖动窗体框架时,ptMinTrackSize和ptMaxTrackSize确定其变化的最大和最小尺寸。  
      假如窗体的大小只在从   (100,100)   到   (500,400)   的范围内变化,那么,使用以下处理过程即可完成:    
  //设置窗体大小变化范围    
  procedure   TForm1.WMGetMinMaxInfo(var   Msg:TWMGetMinMaxInfo);    
  begin    
      inherited;    
      Msg.MinMaxInfo^.ptMaxTrackSize:=   Point(500,400);  
      Msg.MinMaxInfo^.ptMinTrackSize:=   Point(100,100);  
  end;  
      首先调用inherited方法,接着对MinMaxInfo构造体设置初始值,即设置ptMaxTrackSize和ptMinTrackSize的值。  
      这里并没有对按下最大化按钮时的大小进行设定,仅仅只是对拖动框架的大小的动作进行了限制。因此当按下最大化按钮时,窗体与平常一样占满全部画面。  
      当我们绝对不想让窗体的尺寸发生变更时,则采用以下处理过程:  
  inherited;    
  Msg.MinMaxInfo^.ptMaxSize:=   Point(300,200);  
  Msg.MinMaxInfo^.ptMaxTrackSize:=   Point(300,200);  
      同样,横宽固定,纵长可自由改变的时候,则采用以下处理过程。  
  inherited;    
      Msg.MinMaxInfo^.ptMaxSize.x=   Width;    
      Msg.MinMaxInfo^.ptMaxTrackSize.x   =   Width;    
      Msg.MinMaxInfo^.ptMinTrackSize.x   =   Width;  
      上面代入的是该事件句柄所属的窗体的横宽,因此其窗体的横宽不能变更。  
      到此从功能上讲,我们已经能够对窗体的尺寸进行控制了。可是,现在你一定会注意到以下的问题:一个是全屏化按钮和图标化按钮的表现方法,另一个是对应尺寸变化的光标形状的变化。  
      关于全屏化按钮和图标化按钮的使用或不使用的控制方法,在Delphi的程序设计中,可通过直接设定窗体(Form)的BorderIcons特性值来控 制。但是光标形状的变换控制稍微有点麻烦。当光标在窗体框架上时,光标显示为尺寸可变更,但是实际上窗体已经被固定。  
 


为解决此问题生成适当的窗体,而后用WinSignt32(Delphi中含有)或Spy++等Windows监视系统对向该窗体传送的消息进行监视。当 鼠标器在该窗体上移动时,Windows监视系统向窗体传送WM_MOUSEMOVE消息的同时,还传送WM_NCHITTEST消息。当移动和敲击鼠标 时,系统对窗体传送WM_NCHITTEST消息,询问现在鼠标光标在窗体的什么位置,如果传回光标在窗体的框架上或窗体内,系统则相应自动改变光标的形 状。  
      因此,我们先定义WM_NCHITTEST消息句柄,从该句柄传回值。就是说即使光标在框架上,传回值也不在框架上,给Windows系统一个小骗局。该消息句柄说明如下:  
  interface    
  type  
      Tform1   =   class(Tform)    
      private    
       bWinStat:array   [1..4]   of   Boolean;    
       procedure   WMNCHitTest(var   Msg:TWMNCHitTest);  
        message   WM_NCHITTEST;  
      该消息句柄的处理过程:  
  //尺寸变更的光标形状不显示    
  porcedure   Tform1.WMNCHitTest(var   Msg:TWMNChitTest);  
  begin    
      inherited    
       //当移动禁止时,则使其上端、左端尺寸不变更    
    if   bWinStat   [1]   and  
       (Msg.Result   in   [   HTTOP,HTLEFT,HTTOPLEFT,HTTOPRIGHT;HTBOTTOMLEFT])    
       then   Msg.Result:=   Windows.HTNOWHERE;  
       //整体窗体尺寸变更禁止时  
    if   bWinStat   [2]    
  ?and   (Msg.Result   in   {   HTLEFT,HTRIGHT,HTTOP,  
        HTBOTTOM,HTTOPLEFT,HTTOPRIGHT,HTBOTTOMLEFT,HTBOTTOPMRIGHT])  
       then   Msg.Result:=   Windows.HTNOWHERE;  
      //横宽方向尺寸变更禁止时    
    if   bWinStat   [3]   and (Msg.ResultIn{    
     HTLEFT,HTRIGHT,HTTOPLEFT,HTBOTTOM,HTTOPLEFT,HTBOTTOPMRIGHT])    
       then Msg.Result:=   Windows.HTNOWHERE;  
  end;  
      单纯就窗体的框架而言,可分为上下左右4条边和4个角共8个模式。当移动禁止时,上端、左端的位置尺寸不得变更。  
  11.6   无标题栏窗口  
      现在,我们来讨论窗体编程的另一种技巧──建立无标题栏窗口。  
      为了使标题栏不显示,我们可以在窗体BorderStyle特性中选取bsNone值即可。但选取bsNone值后,窗体周围什么也没有。当我们只想去掉标题栏时又怎么办呢?  
      实际上窗体的位置、大小、显示风格等均由Windows   API的CreateWindowEx函数所指定,这个API的参数是在Delphi的CreateParams过程中被初始化的。Delphi是依据以 下的TCreateParams记录的值生成窗体的。TCreateParams记录包含窗体的位置、大小以及其他各种特性,在Delphi的 Control.Pas单元中记录的定义为:    
  TCreateParams   =   record    
      Caption:   PChar;   //标题    
      Style:   DWORD;   //窗体的显示风格    
      ExStyle:   DWORD;   //窗体的扩展显示风格    
      X,   Y:   Integer;   //显示位置    
      Width,   Height:   Integer;   //窗体的大小    
      WndParent:   HWnd;   //父窗体    
      Param:   Pointer;   //指向窗口生成参数(WM_CREATE消息的   //LParam)的指针    
      WindowClass:   TWndClass;   //窗体的类别    
      WinClassName:   array[0..63]   of   Char;   //类别名    
  end;  
      该记录中包含窗体的位置、大小和窗体显示风格的标志。因此,一般通过其值的改变来控制生成窗体的位置、大小和窗体显示风格。由于我们要设置窗体初始的风 格,所以在Params.Style变量中设定窗体的风格。又因为该变量是取标志形式,所以使用and或or布尔运算来演算,从而完成各个位的on或 off。  
      例如,当BorderStyle特性为bsNone时,再给窗体加上可变更大小的粗框架,则对CreateParams方法进行重载。处理过程如下即可:  
  Procedure   TForm1.CreateParams(var   Params:TCreateParams);  
  begin  
      inherited   CreateParams(Params);  
      if   BorderStyle   =   bsNone   then  
       with   Params   do   Style:=   Style   or   WS_THICKFRAME;  
  end;  
      需要注意,一般情况下的继承关系,单纯使用inherited,则派生类的方法即可被调出执行;但继承使用了CreateParams方法时,必须明确按inheritedCreateParams(Params)编制程序。  
      关于窗体风格标志值用以下定量来指定,这里列举的只是具有代表性的一部分。详情请参考Windows   API的CreateWindow的help。  
  WS_BORDER边框  
  WS_CAPTION标题栏    
  WS_CHILD子窗体    
  WS_HSCROLL水平滚动条    
  WS_MAXIMIZE全屏化窗体    
  WS_MAXIMIZEBOX全屏按钮    
  WS_MINIMIIE图标化窗体    
  WS_MINIMIZEBOX图标化按钮    
  WS_SYSMENU系统菜单    
  WS_THICKFRAME可变更窗体大小的粗边框  
  WS_VISIBLE初始为可视的窗体  
      到此,没有标题栏的,大小可以变更的窗体已完成。  
    此窗体由于没有标题栏所以关闭、全屏化等按钮的操作均不可能,并且想通过拉拖标题栏移动窗体也不可能,下面我们先讨论关于移动的问题。  
      关于WM_NCHITTEST消息前面已经作了解说。当拖拉标题栏移动窗体时,窗体伴随鼠标器的移动,系统向窗体传送WM_NCHITTEST消息,当确认光标在标题栏上,并同时检测出鼠标器左按钮被按下时,移动成开始状态。  
      只要光标在窗体,则使窗体的移动成为可能。为此,WMNCHitTest处理过程如下。  
  porcedure   TForm1.WMNCHitTest(var   Msg:TWMNCHitTest);  
  begin   inherited;   //当标题栏非显示时,光标在窗体领域即可移动    
      if   (BorderStyle   =   brNone)   and    
      (Msg.Result   =   HTCLIENT)   then    
       Msg.Result:=   HTCAPTION;  
  end;  
      当鼠标光标在窗体领域内时,并且无标题栏,WM_NCHITTEST消息传回值为HTCLIENT时,将传回值作为HTCAPTION处理,系统则判断鼠标光标在标题栏上,这样就完成了窗体领域可移动的处理。这里再次给Windows系统一个骗局。  
      另外,讨论一下标题栏的消除和追加的方法。从而解决关闭、全屏化、图标化的问题。首先想到的方法是在窗体(Form)被单击或双击后,改变 BorderStyle特性的值。就是说对Form的OnClick事件进行定义,创建子程序将bsNone变为bsSizeable。  
      可是我们测试一下,它并不动作。实际上这是因为在前面为了处理移动,在WMNCHitTest过程中,将窗体领域的返回值变更成了标题栏的返回值,因此系统只判断鼠标光标在标题栏上单击。  
      要想移动和单击同时起作用需要下一点功夫。当用WinSight32来确认显示正常的窗体返回给系统的消息时,与通常窗体领域返回WM_LBUTTONDOWN消息相对,在标题上单击时返回WM_NCLBUTTONDOWN消息。  
      这里不使用窗体(Form)的OnClik事件,而是通过WM_NCLBUTTONDOWN消息的处理来得到希望的动作。如下编程即可   :  
  interface    
 


type  
      TForm1   =   Class(TForm);  
      :  
      protected   WMNCLButtonDown(var   Msg:TWMNCLButtonDown);  
       message   WM_NCLBUTTONDOWN;    
   implemention   //鼠标单击窗体追加标题栏    
      porcedure   TForm1.WMNCLButtonDown(var   Msg:TWMNCLButtonDown);   
      begin  
       if   BorderStyle   =   bsNone   then  
      borderStyle   =   bsSizeble;  
      end;  
      当然,如果在窗体上配置其他可视构件,从而可以简单地通过对构件的单击来完成以上动作。  
  11.7   窗体间相互连动  
      下面我们来讨论两个窗体的设计技巧。设其中一个为主窗体,另一个为子窗体。   在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);  
       以上处理是从主窗体的新位置来计算子窗体的新位置,然后与现在的子窗体的位置信息进行比较,如果不同则变更子窗体。单纯用Wondow   API的SetWindowPos对位置进行变更时,Z顺序和活动窗口(Active   Window)发生转换,因此指定SWP_NOACTIVATE标志和SWP_NOZORDER标志,阻止其转换。  
    从子窗体来变更主窗体的过程大致与上相同。不同之处在于主窗体一定存在,而不需要对其进行检验。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值