前面做的工作就是想在标题区域增加快速工具条。前续的基础工作完成,想要在标题区域增加特殊区域都非常方便。只要在绘制时控制自定义区域需要占用标题区域多少空间,然后直接在所占位置绘制。做这个事情前,稍微把代码规整了下。所以界面皮肤处理放到一个单元中。

 

窗体皮肤实现 - 在标题栏上增加快速工具条(四)

 

主要处理步骤

  1、划出一个新区域(整个工具条作为一个区域)

  2、处理区域检测(HitTest)

  3、如果是新区域,把相应消息传给这个区域处理。

  4、响应鼠标点击,执行Action

 

通过上述步骤就能扩展出所想要的标题区快速工具条的。

 

标题按钮区域是作为一个整体处理,这样比较容易控制和扩展。只要当检测区域是标题工具区时,消息交由工具条实现。

 1   HTCUSTOM = 100; //HTHELP + 1;       /// 自定义区域ID
 2   HTCAPTIONTOOLBAR = HTCUSTOM + 1;    /// 标题工具区域ID
 3 
 4 
 5 ///
 6 /// 检测区域时增加自定义区域的检测
 7 function TskForm.HitTest(P: TPoint):integer;
 8 begin
 9     ... ... (代码略)  
10     ///
11     ///  标题工具区域
12     ///    需要前面扣除窗体图标区域
13     if (Result = HTNOWHERE) and (FToolbar.Visible) then
14     begin
15       r.Left := rCaptionRect.Left + 2 + GetSystemMetrics(SM_CXSMICON) + SPALCE_CAPTIONAREA;
16       R.Top := rCaptionRect.Top + (rCaptionRect.Height - FToolbar.Border.Height) div 2;
17       R.Right := R.Left + FToolbar.Border.Width;
18       R.Bottom := R.Top + FToolbar.Border.Height;
19 
20       if FToolbar.FOffset.X = -1 then
21         FToolbar.FOffset := r.TopLeft;
22 
23       if PtInRect(r, p) then
24         Result := HTCAPTIONTOOLBAR;
25     end;
26   end;
27 end;

这样做的好处就是,简化自定义皮肤TskForm内部的处理。模块化比较清晰,简化实现逻辑。

 

标题工具条实现过程

   1、准备绘制的区域

   2、确定绘制区域大小

   3、实现绘制

   4、响应消息

 

确定绘制区域大小

  考虑到按钮是动态增加上去,需要根据实际标题区域的按钮数量来确定实际大小。所有的Action存放在记录中,这样每次只要循环Action数组就可以获得相应宽度。

区域的宽度包括:两条分割线 + 下拉配置菜单 + Button * Count

 1 /// 用于保存Action的信息
 2 TcpToolButton = record
 3   Action: TBasicAction;
 4   Enabled: boolean;
 5   Visible: Boolean;
 6   ImageIndex: Integer;        // 考虑到标题功能图标和实际工具栏功能使用不同图标情况,分开图标索引
 7   Width: Word;                // 实际占用宽度,考虑后续加不同的按钮样式使用
 8   Fade: Word;                 // 褪色量 0 - 255
 9   SaveEvent: TNotifyEvent;    // 原始的Action OnChange事件
10 end;
11 
12 ///
13 /// 计算实际占用尺寸
14 function TcpToolbar.CalcSize: TRect;
15 const
16   SIZE_SPLITER = 10;
17   SIZE_POPMENU = 10;
18   SIZE_BUTTON  = 20;
19 var
20   w, h: Integer;
21   I: Integer;
22 begin
23   ///
24   ///  占用宽度
25   ///     如果考虑比较复杂的按钮样式和显示标题等功能,那么需要计算每个按钮实际占用宽度才能获得。
26 
27   w := SIZE_SPLITER * 2 + SIZE_POPMENU;
28   for I := 0 to FCount - 1 do
29     w := w + FItems[i].Width;
30   h := SIZE_BUTTON;
31   Result := Rect(0, 0, w, h);
32 end;

 

占用区域大小的问题解决,绘制问题主要考虑在什么位置绘制,怎么获得Action的图标和实际的状态。

以正常情况考虑绘制区域:从原点(0,0)开始绘制,这样比较符合一般的习惯。只要在绘制前对画布重新设置原点,就能实现。

 1 ///
 2 /// 绘制工具条
 3 if FToolbar.Visible and (rCaptionRect.Right > rCaptionRect.Left) then
 4 begin
 5   /// 防止出现绘制出多余区域,当区域不够时需要进行剪切。
 6   ///  如: 窗体缩小时
 7   CurrentIdx := 0;
 8   bClipRegion := rCaptionRect.Width < FToolbar.Border.Width;
 9   if bClipRegion then
10   begin
11     ClipRegion := CreateRectRgnIndirect(rCaptionRect);
12     CurrentIdx := SelectClipRgn(DC, ClipRegion);
13     DeleteObject(ClipRegion);
14   end;
15 
16   /// 设置原点偏移量
17   iLeftOff := rCaptionRect.Left;
18   iTopOff := rCaptionRect.Top + (rCaptionRect.Height - FToolbar.Border.Height) div 2;
19   MoveWindowOrg(DC, iLeftOff, iTopOff);
20   FToolbar.Paint(DC);
21   MoveWindowOrg(DC, -iLeftOff, -iTopOff);
22 
23   if bClipRegion then
24     SelectClipRgn(DC, CurrentIdx);
25 
26   /// 扣除工具条区域
27   rCaptionRect.Left := rCaptionRect.Left + FToolbar.Border.Width + SPALCE_CAPTIONAREA;
28 end;

 

获取Action的图标

  直接从ImageList中获取。考虑标题区域是纯色,能让标题工具条显的更美观(个人审美),能让工具条支持2中不同的图标。画了一组纯白的图标用于标题区域的显示。

窗体皮肤实现 - 在标题栏上增加快速工具条(四)

 1 // 创建Bmp,支持透明
 2 // cIcon := TBitmap.Create;
 3 // cIcon.PixelFormat := pf32bit;  // 支持透明
 4 // cIcon.alphaFormat := afIgnored;
 5 
 6 function TcpToolbar.LoadActionIcon(Idx: Integer; AImg: TBitmap):Boolean;
 7 var
 8   bHasImg: Boolean;
 9 begin
10   /// 获取Action的图标
11   AImg.Canvas.Brush.Color := clBlack;
12   AImg.Canvas.FillRect(Rect(0,0, AImg.Width, AImg.Height));
13   bHasImg := False;
14   if (FImages <> nil) and (FItems[Idx].ImageIndex >= 0) then
15     bHasImg := FImages.GetBitmap(FItems[Idx].ImageIndex, AImg);
16   if not bHasImg and (FItems[Idx].Action is TCustomAction) then
17     with TCustomAction(FItems[Idx].Action) do
18       if (Images <> nil) and (ImageIndex >= 0) then
19         bHasImg := Images.GetBitmap(ImageIndex, AImg);
20   Result := bHasImg;
21 end;
获取Action的图标

相关文章:

  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-10-04
  • 2022-12-23
猜你喜欢
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-07-31
  • 2021-12-07
相关资源
相似解决方案