窗体皮肤实现 - 重绘窗体非客户区(二)

第一个实现了基本处理。窗体边框的宽度有些肥大,需要进行瘦身。

实现:

    1、改变外框线宽度 (WM_NCCALCSIZE

    2、改变外框样式 (WM_WINDOWPOSCHANGING

 

通过 WM_NCCALCSIZE 消息可以实现目的。

窗体皮肤实现 - 重绘窗体非客户区(二)

 

procedure WMNCCalcSize(var message: TWMNCCalcSize); message WM_NCCALCSIZE;

procedure TTest.WMNCCalcSize(var message: TWMNCCalcSize);
const
  SIZE_BORDER = 5;
  SIZE_CAPTION = 28;
begin
  // 改变边框尺寸
  with TWMNCCALCSIZE(Message).CalcSize_Params^.rgrc[0] do
  begin
    Inc(Left, SIZE_BORDER);
    Inc(Top, SIZE_CAPTION);
    Dec(Right, SIZE_BORDER);
    Dec(Bottom, SIZE_BORDER);
  end;
  Message.Result := 0;
  Handled := True;
end;

 

窗体的四个角的表现样式可以看出是XP的界面轮廓。倒角的幅度感觉有些大改小些。

窗体皮肤实现 - 重绘窗体非客户区(二)

 

调整外框样式需要在窗体改变尺寸时进行处理,这种方法还可以实现不规则窗体。

WM_WINDOWPOSCHANGING 这个消息可以满足需要。

处理是需要注意的问题:

  1、因为是在调整过程中实际窗体的尺寸是无法通过 GetWindowRect 这个函数获取调整后的状态,因此需要保存有这个消息产生的窗体调整尺寸信息。

  2、这个消息会有很多模式,这个消息的触发来源 SetWindowPos 可以设置很多参数。我们只要处理窗体改变大小的模式,其他需要交由系统默认处理。

 

调用控件默认消息处理

procedure TTest.CallDefaultProc(var message: TMessage);
begin
  ///
  ///  调用控件默认消息处理过错
  ///    为防止出现循环调用,需要使用状态控制(FCallDefaultProc)
  ///
  if FCallDefaultProc then
    FControl.WindowProc(message)
  else
  begin
    FCallDefaultProc := True;
    FControl.WindowProc(message);
    FCallDefaultProc := False;
  end;
end;

记录窗体位置和尺寸,并对窗体进行调整外框样式

procedure TTest.WMWindowPosChanging(var Message: TWMWindowPosChanging);
var
  bChanged: Boolean;
begin
  /// 由外部优先处理消息,完成以下默认的控制
  CallDefaultProc(TMessage(Message));

  Handled := True;
  bChanged := False;

  /// 防止嵌套
  if FChangeSizeCalled then
    Exit;

  /// 调整窗体外框
  ///   如果窗体尺寸有调整时需要重新生成窗体外框区域。
  ///
  if (Message.WindowPos^.flags and SWP_NOSIZE = 0) or
     (Message.WindowPos^.flags and SWP_NOMOVE = 0) then
  begin
    if (Message.WindowPos^.flags and SWP_NOMOVE = 0) then
    begin
      FLeft := Message.WindowPos^.x;
      FTop := Message.WindowPos^.y;
    end;
    if (Message.WindowPos^.flags and SWP_NOSIZE = 0) then
    begin
      bChanged := ((Message.WindowPos^.cx <> FWidth) or (Message.WindowPos^.cy <> FHeight)) and
                 (Message.WindowPos^.flags and SWP_NOSIZE = 0);
      FWidth := Message.WindowPos^.cx;
      FHeight := Message.WindowPos^.cy;
    end;
  end;

  if (Message.WindowPos^.flags and SWP_FRAMECHANGED  <> 0) then
    bChanged := True;

  // 进行调整和重绘处理
  if bChanged then
  begin
    ChangeSize;
    InvalidateNC;
  end;
end;

调整窗体样式 

 1 procedure TTest.ChangeSize;
 2 var
 3   hTmp: HRGN;
 4 begin
 5   /// 调整窗体样式
 6   FChangeSizeCalled := True;
 7   try
 8     hTmp := FRegion;
 9     try
10       /// 创建 倒角为3的矩形区域。
11       ///    在这里可以实现不规则界面的创建,可以通过bmp创建绘制区域
12       ///
13       ///  注:
14       ///    HRGN 句柄是是图形对象,由window管理的资源,不释放会出现内存泄露,
15       ///    后果,你懂得。
16       FRegion := CreateRoundRectRgn(0, 0, FWidth, FHeight, 3, 3);
17       SetWindowRgn(Handle, FRegion, True);
18     finally
19       if hTmp <> 0 then
20         DeleteObject(hTmp); // 释放资源
21    end;
22   finally
23     FChangeSizeCalled := False;
24   end;
25 end;

 

调整后的最终效果,瘦身感觉不错还算精致。

窗体皮肤实现 - 重绘窗体非客户区(二)

 

代码下载: TestCaptionToolbar(v0.2).7z   

    http://pan.baidu.com/s/1jG64aFW

    https://github.com/cmacro/simple

窗体皮肤实现 - 重绘窗体非客户区(二)

上一篇:Webserver管理系列:1、安装Windows Server 2008


下一篇:一、Ubuntu Server上安装Matlab,利用X11和Putty输出窗口到Windows桌面(环境选择)