使所有者绘制的TPageControl选项卡看起来更好,就像没有所有者绘制一样

Pro*_*020 2 delphi delphi-7 tpagecontrol

我使用Delphi7,PageControl和owner-draw.正如我在非所有者绘制的PageControls上看到的那样,我无法获得如此简单明了的标签.有什么不好的:当使用所有者绘制时,我无法在"整个"标签标题区域上绘制,选项卡标题周围的小1-2px框架由OS绘制.

1)Delphi不是自主绘图,看起来也可以(XPMan使用):

德尔福系统

2)Delphi owner-draw,你看不是整个标签头都可以着色(XPMan使用):

德尔福老板画

我在这里用蓝色绘制当前标签,用白色绘制其他标签.只是例子.码:

procedure TForm1.PageControl1DrawTab(Control: TCustomTabControl;
  TabIndex: Integer; const Rect: TRect; Active: Boolean);
var
  c: TCanvas;
begin
  c:= (Control as TPageControl).Canvas;
  if Active then
    c.Brush.Color:= clBlue
  else
    c.Brush.Color:= clWhite;
  c.FillRect(Rect);    
end;
Run Code Online (Sandbox Code Playgroud)

2b)Delphi所有者在真实应用程序中绘制(使用XPMan):

德尔福真正的应用程序

为什么我需要使用所有者抽奖?简单.要在选项卡标题上绘制X按钮,使用自定义颜色绘制上线,以从图像列表中绘制图标.

我正在寻找一种方法来绘制标签标题的整个矩形,而不是减少给予PageControl所有者绘制事件的rect.我试图增加由所有者绘制事件给出的矩形,但这没有帮助,操作系统重新绘制了标签标题周围的这个薄的1-2px框架.

Ser*_*yuz 8

所有者的标签绘制了原生的"标签控件"(TPageControl在VCL中,虽然它的上升位置被恰当地命名TCustomTabControl- 任何人猜测为什么创意命名...),在处理WM_DRAWITEM消息时应该由其父控件绘制,如此处所述.

VCL通过将消息变为CN_DRAWITEM消息并将其发送给控件本身来承担父母的负担.在这个过程中,VCL没有进一步干预.它只是调用OnDrawTab消息处理程序,如果它由用户代码分配,并传递适当的参数.

因此,不是VCL在选项卡周围绘制边框,而是操作系统本身.另外,显然,它不会在处理WM_DRAWITEM消息期间执行此操作,而是在绘制过程中稍后执行此操作.您可以通过在WM_DRAWITEM页面控件的父级上放置一个空处理程序来验证这一点.结果是,无论我们在事件处理程序中绘制什么,它都会在以后通过操作系统获得边界.

我们可能尝试的是尝试阻止操作系统绘制的内容生效,毕竟我们有设备上下文(如Canvas.Handle).不幸的是,这条路线也是死路一条,因为VCL在事件处理程序返回后恢复设备上下文的状态.

那么,唯一的方法是完全放弃处理OnDrawTab事件,并根据CN_DRAWITEM消息采取行动.下面的示例代码使用内插器类,但您可以按照自己喜欢的方式对控件进行子类化.确保OwnerDrawn已设置.

type
  TPageControl = class(comctrls.TPageControl)
  protected
    procedure CNDrawitem(var Message: TWMDrawItem); message CN_DRAWITEM;
  end;

  TForm1 = class(TForm)
    ..

..

procedure TPageControl.CNDrawitem(var Message: TWMDrawItem);
var
  Color: TColor;
  Rect: TRect;
  Rgn: HRGN;
begin
  Color := 0;  
  // draw in different colors so we see where we've drawn
  case Message.DrawItemStruct.itemID of
    0: Color := $D0C0BF;
    1: Color := $D0C0DF;
    2: Color := $D0C0FF;
  end;
  SetDCBrushColor(Message.DrawItemStruct.hDC, Color);

  // we don't want to get clipped in the passed rectangle
  SelectClipRgn(Message.DrawItemStruct.hDC, 0);

  // magic numbers corresponding to where the OS draw the borders
  Rect := Message.DrawItemStruct.rcItem;
  if Bool(Message.DrawItemStruct.itemState and ODS_SELECTED) then begin
    Inc(Rect.Left, 2);
//    Inc(Rect.Top, 1);
    Dec(Rect.Right, 2);
    Dec(Rect.Bottom, 3);
  end else begin
    Dec(Rect.Left, 2);
    Dec(Rect.Top, 2);
    Inc(Rect.Right, 2);
    Inc(Rect.Bottom);
  end;
  FillRect(Message.DrawItemStruct.hDC, Rect,
      GetStockObject(DC_BRUSH));

  // just some indication for the active tab
  SetROP2(Message.DrawItemStruct.hDC, R2_NOTXORPEN);
  if Bool(Message.DrawItemStruct.itemState and ODS_SELECTED) then
    Ellipse(Message.DrawItemStruct.hDC, Rect.Left + 4, Rect.Top + 4,
      Rect.Left + 12, Rect.Top + 12);

  // we want to clip the DC so that the borders to be drawn are out of region
  Rgn := CreateRectRgn(0, 0, 0, 0);
  SelectClipRgn(Message.DrawItemStruct.hDC, Rgn);
  DeleteObject(Rgn);

  Message.Result := 1;
  inherited;
end;
Run Code Online (Sandbox Code Playgroud)


以下是上述内容:
在此输入图像描述

  • 太好了!虽然,问题是,如果这样的黑客绘图甚至有意义.您可以隐藏选项卡和页面切换使用,例如放置在页面控件顶部的图像. (2认同)