Delphi 如何知道我引用的组件是否正确?

Delphi 如何知道我引用的组件是否正确?,delphi,custom-component,Delphi,Custom Component,概述 我重写了一些从TXPStyleMenuItem继承的过程,这样我就可以在使用TActionMainMenuBar时更改菜单的外观 例如: TMyXPStyleMenuItem = class(TXPStyleMenuItem) protected procedure DrawBackground(var PaintRect: TRect); override; end; 我已经创建了自己的组件,它是从TActionMainMenuBar派生的,并且在GetContro

概述

我重写了一些从TXPStyleMenuItem继承的过程,这样我就可以在使用TActionMainMenuBar时更改菜单的外观

例如:

  TMyXPStyleMenuItem = class(TXPStyleMenuItem)
  protected
    procedure DrawBackground(var PaintRect: TRect); override;
  end;
我已经创建了自己的组件,它是从TActionMainMenuBar派生的,并且在GetControlClass方法中,我将
var-ControlClass:tcCustomActionControlClass
设置为TMyXPStyleMenuItem

到目前为止,我所做的工作做得很好,尽管显然比上面的例子更完整——为了这个问题的目的,我尽量使它简短

样式器组件

我创建了一个非可视化的样式器组件,它基本上只不过是一堆已发布的属性,这个样式器组件可以分配给我的一些控件,在本例中是我的下一个TActionMainMenuBar

当我的控件指定了样式器组件时,它会读取属性的值,然后根据这些值进行绘制。如果没有指定样式器组件,那么我只需使用默认值来决定控件的绘制方式

一个简单的例子来自我的一个自定义TEDIT,我可以根据指定的样式器值更改颜色:

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;
差点就赢了

我得到的最接近的是菜单组件的单元,我在实现部分上方创建了一个全局变量:

var
  FStyler: TMyStyler;

implementation
然后在高架牵引地面程序中,我做了以下操作:

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变量

我认为我可以做的另一件事是用重载指令标记过程,这样可以添加额外的参数,但我仍然不知道是否引用了正确的菜单组件


由于我基本上仍在熟悉组件编写等,如果我忽略了一些完全显而易见的东西,请原谅我。如果它很简单,那么我完全错过了它-如果我诚实的话,这让我现在有点困惑

使用
菜单
属性(在类的父级
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;

我在使用jachguate的答案时遇到了问题,
GetStyler
方法中的以下行从未被触发:

function TMyXPStyleMenuItem.GetMenuStyler: TMyStyler;
begin
  if Menu is TMyActionMainMenuBar then //< never hit
    Result := TMyActionMainMenuBar(Menu).Styler
  else
    Result := nil;
end;

它的关键是
菜单。RootMenu
,它告诉我们已经使用了自定义菜单栏。

+1很高兴看到您自己做进一步的调查,给出了答案并提出了解决方案。@Marjannema感谢您的评论,老实说,我不太经常能解决很多问题,如果可以的话,我会回答更多。如果没有jachguate的回答,我甚至不会注意到
菜单
属性,这最终让我找到了上面的解决方案。关键是你在学习,你愿意深入挖掘,我只是想在此向你致意。许多人会简单地带着“它(仍然)不起作用”回来。。。
function TMyXPStyleMenuItem.GetMenuStyler: TMyStyler;
begin
  if Menu is TMyActionMainMenuBar then //< never hit
    Result := TMyActionMainMenuBar(Menu).Styler
  else
    Result := nil;
end;
function TMyXPStyleMenuItem.GetStyler: TMyStyler;
begin
  if Menu.RootMenu is TMyActionMainMenuBar then
    Result := TMyActionMainMenuBar(Menu.RootMenu).Styler
  else
    Result := nil;
end;