我使用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;
2b)Delphi所有者在真实应用程序中绘制(使用XPMan):
为什么我需要使用自拍?简单。要在选项卡标题上绘制X按钮,使用自定义颜色绘制上线,以从图像列表中绘制图标。
我正在寻找一种方法来绘制标签标题的整个矩形,而不是减少给予PageControl所有者绘制事件的rect。我尝试增加所有者绘制事件给出的矩形,但这没有帮助,操作系统重新绘制了标签标题周围的这个薄的1-2px框架。
答案 0 :(得分:8)
所有者的标签在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;
以上是上述内容:
答案 1 :(得分:1)
据我所知,您只是希望获得应用程序的主题绘画。在Delphi 7中,您需要做的就是添加一个指定使用comctl32版本6的应用程序清单。这样做的简单方法是将TXPManifest组件添加到您的某个表单或数据模块中,或者只是在项目中引用XPMan单元。
由于您希望系统绘制页面控件,因此不得进行任何所有者绘图。