概述
我正在重写从TXPStyleMenuItem继承的一些过程,这样我可以更改使用TActionMainMenuBar时菜单的显示方式。
示例:
TMyXPStyleMenuItem = class(TXPStyleMenuItem)
protected
procedure DrawBackground(var PaintRect: TRect); override;
end;
我创建了自己的组件,它是从TActionMainMenuBar派生的,而在GetControlClass方法中,我已将var ControlClass: TCustomActionControlClass
设置为TMyXPStyleMenuItem。
到目前为止我的工作效果很好,但显然比上面的例子更完整 - 为了问题的目的,我尽可能简短而简单。
Styler组件
我创建了一个非可视样式组件,它基本上只是一堆已发布的属性,这个样式组件可以分配给我的一些控件,在这种情况下我的下载TActionMainMenuBar。
当我的控件分配了样式器组件时,它会读取属性的值,然后根据值进行绘制。如果未分配样式器组件,那么我只需使用默认值来决定控件的绘制方式。
一个快速示例来自我的一个自定义TEdits,我可以根据指定的样式器值更改颜色:
TMyEdit = class(TCustomEdit)
private
FStyler: TMyStyler;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
end;
if Assigned(FStyler) then
begin
Color := FStyler.Color;
end;
问题
我面临的问题是TMyXPStyleMenuItem = class(TXPStyleMenuItem)
中的覆盖程序。
我需要读取我的样式组件的值,但因为TMyXPStyleMenuItem实际上不是我的菜单组件的一部分,所以我无法知道FStyler
来自哪里,例如我分配给TActionMainMenuBar的哪个实例?
通常,FStyler的设置类似于我的菜单类:
private
FStyler: TMyStyler;
procedure SetStyler(const Value: TMyStyler);
published
property Styler: TMyStyler read FStyler write SetStyler;
..
procedure TMyMenu.SetStyler(const Value: TMyStyler);
begin
if Value <> FStyler then
begin
FStyler := Value;
end;
end;
但TMyXPStyleMenuItem
的那些程序不知道上述情况。
我不能在重载过程中包含一个新参数,因为它不会起作用,因为声明与基类不同,例如:
procedure DrawBackground(var PaintRect: TRect; AStyler: TMyStyler); override;
几乎拥有它
我最接近的是在菜单组件的单元中,我在实现部分上方创建了一个全局变量:
var
FStyler: TMyStyler;
implementation
然后在过度的DrawBackground程序中我这样做了:
procedure TMyXPStyleMenuItem.DrawBackground(var PaintRect: TRect);
procedure _DrawBackground(AStyler: TMyStyler);
begin
// handle all the painting from here
// using the values from AStyler.
end;
begin
if Assigned(FStyler) then
_DrawBackground(FStyler);
end;
正如我以为我有它工作,我很快发现它不是。只要我有一个二级菜单或另一个表单上的菜单,就会混淆应该使用哪个样式器值绘制哪个菜单。这是因为理论上我的菜单组件的任何实例都将使用全局FStyler变量。
我认为我能做的另一件事是用过载指令标记过程,这会让我添加额外的参数,但是我仍然不知道我是否引用了正确的菜单组件。
由于我基本上仍然熟悉组件编写等,如果我忽略了一些完全明显的东西,请原谅我。如果它很简单,那么我完全错过了 - 如果我诚实的话,这让我感到非常困惑!
答案 0 :(得分:5)
使用Menu
属性(在TCustomMenuItem
中声明,这是您班级的祖父)来访问菜单样式器,如下所示:
procedure TMyXPStyleMenuItem.DrawBackground(var PaintRect: TRect);
var
Styler: TMyStyler;
begin
if Menu is TMyActionMainMenuBar then
Styler := TMyActionMainMenuBar(Menu).Styler
else
Styler := nil;
if Assigned(Styler) then
DrawStyledBackground
else
DrawDefaultBackground;
end;
您可以重构代码以添加GetMenuStyler方法:
function TMyXPStyleMenuItem.GetMenuStyler: TMyStyler;
begin
if Menu is TMyActionMainMenuBar then
Result := TMyActionMainMenuBar(Menu).Styler
else
Result := nil;
end;
procedure TMyXPStyleMenuItem.DrawBackground(var PaintRect: TRect);
var
Styler: TMyStyler;
begin
Styler := GetMenuStyler;
if Assigned(Styler) then
DrawStyledBackground
else
DrawDefaultBackground;
end;
procedure TMyXPStyleMenuItem.OtherDrawMethod(var PaintRect: TRect);
var
Styler: TMyStyler;
begin
Styler := GetMenuStyler;
if Assigned(Styler) then
...;
end;
答案 1 :(得分:3)
我使用jachguate的答案遇到问题,GetStyler
方法中的以下行从未被触发:
function TMyXPStyleMenuItem.GetMenuStyler: TMyStyler;
begin
if Menu is TMyActionMainMenuBar then //< never hit
Result := TMyActionMainMenuBar(Menu).Styler
else
Result := nil;
end;
这显然导致其余代码出现问题,因为我从未找到自定义派生菜单。
我按照jachguate的回答中指出的Menu
属性进行了一些测试和调试,以确定类名是否为TMyActionMainMenuBar
,但它不是 - 它是{{1相反。
所以我需要找出如何让课程成为TXPStylePopupMenu
。
我通过尝试一些不同的东西找到了解决方案,这是我发现的:
TMyActionMainMenuBar
它的关键是function TMyXPStyleMenuItem.GetStyler: TMyStyler;
begin
if Menu.RootMenu is TMyActionMainMenuBar then
Result := TMyActionMainMenuBar(Menu.RootMenu).Styler
else
Result := nil;
end;
,它告诉我们使用了自定义菜单栏。