gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-02 05:30:37 25 4
gpt4 key购买 nike

我使用Delphi7,带有所有者绘制的PageControl。我无法获得如此简单且漂亮的选项卡外观,正如我在非所有者绘制的 PageControl 上看到的那样。有什么不好的:使用owner-draw时,我无法在“整个”选项卡标题区域上绘制,选项卡标题周围的1-2px小框架是由操作系统绘制的。

1)Delphi不是所有者绘制的,看起来也不错(使用XPMan):

delphi sys

2)Delphi所有者绘制,你看到不是整个选项卡标题都可以着色(使用XPMan):

delphi owner draw

我在这里用蓝色绘制当前选项卡,用白色绘制其他选项卡。仅举个例子。代码:

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;

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

delphi real app

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

我正在寻找一种方法来绘制选项卡标题的整个矩形,而不是减少为 PageControl 所有者绘制事件提供的矩形。我尝试增加所有者绘制事件给出的矩形,但这没有帮助,操作系统无论如何都会在选项卡标题周围重新绘制这个薄的 1-2px 框架。

最佳答案

所有者的选项卡绘制了 native “选项卡控件”(VCL 中的 TPageControl,尽管它的上一代被适本地命名为 TCustomTabControl - 任何人都猜测为什么有创意的命名。 .),预计在处理 WM_DRAWITEM 消息时由其父控件绘制,如 documented here .

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;


以下是上面的内容:
enter image description here

关于delphi - 使所有者绘制的 TPageControl 选项卡看起来更好,就像没有所有者绘制一样,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18282728/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com