Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ruby-on-rails/62.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi 记录菜单项OnClick事件_Delphi_Logging_Analytics_Delphi 10 Seattle - Fatal编程技术网

Delphi 记录菜单项OnClick事件

Delphi 记录菜单项OnClick事件,delphi,logging,analytics,delphi-10-seattle,Delphi,Logging,Analytics,Delphi 10 Seattle,我有一个项目(Delphi10西雅图,win32),其中有许多菜单和菜单中的许多项。有些菜单项是在设计时创建的,有些是在运行时创建的 我想做的是记录一些关于TMenuItem的信息,比如触发OnClick事件时的名称/标题、时间戳等 我可以简单地在分配给TMenuItem OnClick事件的每个函数的开头添加一个过程调用,但我想知道是否有更优雅的解决方案 同样要注意的是,我试过了,但我发现它没有给我想要的信息或灵活性,而且价格相当昂贵 编辑:我将添加更多信息,详细说明我考虑过的选项(我可能一开

我有一个项目(Delphi10西雅图,win32),其中有许多菜单和菜单中的许多项。有些菜单项是在设计时创建的,有些是在运行时创建的

我想做的是记录一些关于TMenuItem的信息,比如触发OnClick事件时的名称/标题、时间戳等

我可以简单地在分配给TMenuItem OnClick事件的每个函数的开头添加一个过程调用,但我想知道是否有更优雅的解决方案

同样要注意的是,我试过了,但我发现它没有给我想要的信息或灵活性,而且价格相当昂贵

编辑:我将添加更多信息,详细说明我考虑过的选项(我可能一开始就应该这样做)

简单的做法是在我想记录的每个菜单项单击中添加一个函数,这意味着要对许多函数执行此操作,并且必须将其添加到添加的每个新菜单项中

procedure TSomeForm.SomeMenuItem1Click(Sender: TObject);
var
    item : TMenuItem;
begin
    item := Sender as TMenuItem;
    LogMenuItem(item);  // Simple log function added to the start of each menuitem click
end;
我所说的“更优雅的解决方案”是指,在调用分配给OnClick事件的过程之前,是否可以添加一个“钩子”,以便所有TMenuItem OnClick事件触发另一个过程(该过程将进行日志记录)


或者我考虑的另一个选项是创建一个继承自TMenuItem的类,该类将覆盖TMenuItem。但是,如果没有大量的工作来重新设计菜单,我不知道设计时菜单项是如何工作的

使用操作更容易实现这一点。这样做的好处是,您可以选择由菜单以外的UI元素调用的操作,例如工具栏、按钮等


根据您的喜好,使用或。例如,对于操作列表,操作列表对象具有在执行任何操作时激发的事件。您可以侦听该事件,并在其中记录正在执行的操作的详细信息

使用操作更容易实现这一点。这样做的好处是,您可以选择由菜单以外的UI元素调用的操作,例如工具栏、按钮等


根据您的喜好,使用或。例如,对于操作列表,操作列表对象具有在执行任何操作时激发的事件。您可以侦听该事件,并在其中记录正在执行的操作的详细信息

我完全同意操作是一种方法,但为了完整性以及您快速希望使用旧式菜单调试应用程序的情况,这里有一个可以与菜单项一起使用的单元。如果菜单项具有链接到它们的操作,它甚至可以工作,但对于任何其他具有
tractionMainMenuBar
等操作的控件,它都不起作用。所有调试代码都在本单元中,以保持正常代码的整洁。只需将该单元添加到uses子句中,并使用任何适用组件调用
StartMenuLogging
,例如菜单组件、表单组件甚至
应用程序
!树下的任何菜单项都将被钩住。因此,您可以使用生产代码中的这两行调试所有表单中的所有菜单单击。您可以使用
stopmenuloging
停止,但这是可选的警告:此单元未正确测试-我使用了一个我编写的旧调试单元,并为此清理了它,只是对其进行了表面测试

unit LogMenuClicks;


interface

uses
  Classes;

procedure StartMenuLogging(AComponent: TComponent);
procedure StopMenuLogging(AComponent: TComponent);
procedure StopAllMenuLogging;


implementation

uses
  SysUtils,
  Menus;


type
  PLoggedItem = ^TLoggedItem;
  TLoggedItem = record
    Item: TMenuItem;
    OldClickEvent: TNotifyEvent;
  end;

  TLogManager = class(TComponent)
  private
    FList: TList;
    FLog: TFileStream;

    procedure Delete(Index: Integer);
    function FindControl(AItem: TMenuItem): Integer;
    procedure LogClick(Sender: TObject);
  protected
    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;

    procedure AddControl(AItem: TMenuItem);
    procedure RemoveControl(AItem: TMenuItem);
  end;

  var
    LogMan: TLogManager = nil;

{ TLogManager }

constructor TLogManager.Create(AOwner: TComponent);
begin
  inherited;

  FLog := TFileStream.Create(ChangeFileExt(ParamStr(0), '.log'), fmCreate or fmShareDenyWrite);
  FList := TList.Create;
end;

destructor TLogManager.Destroy;
var
  i: Integer;
begin
  i := FList.Count - 1;
  while i >= 0 do
    Delete(i);
  FList.Free;

  FLog.Free;

  inherited;
end;

procedure TLogManager.Notification(AComponent: TComponent; Operation: TOperation);
begin
  if Operation = opRemove then
    RemoveControl(TMenuItem(AComponent));

  inherited;
end;

procedure TLogManager.Delete(Index: Integer);
var
  li: PLoggedItem;
begin
  li := FList[Index];

  with li^ do
  begin
    Item.RemoveFreeNotification(Self);
    Item.OnClick := OldClickEvent;
  end;

  Dispose(li);
  FList.Delete(Index);
end;

function TLogManager.FindControl(AItem: TMenuItem): Integer;
begin
  Result := FList.Count - 1;
  while (Result >= 0) and (PLoggedItem(FList[Result]).Item <> AItem) do
    Dec(Result);
end;

procedure TLogManager.AddControl(AItem: TMenuItem);
var
  li: PLoggedItem;
begin
  if not Assigned(AItem) then
    Exit;

  if FindControl(AItem) >= 0 then
    Exit;

  New(li);
  li.Item := AItem;
  li.OldClickEvent := AItem.OnClick;
  AItem.OnClick := LogClick;
  FList.Add(li);

  AItem.FreeNotification(Self);
end;

procedure TLogManager.RemoveControl(AItem: TMenuItem);
var
  i: Integer;
begin
  if Assigned(AItem) then
  begin
    i := FindControl(AItem);
    if i >= 0 then
      Delete(i);
  end;
end;

procedure TLogManager.LogClick(Sender: TObject);
var
  s: string;
begin
  s := Format('%s: %s' + sLineBreak, [TComponent(Sender).Name, FormatDateTime('', Now)]);
  FLog.WriteBuffer(s[1], Length(s));
  PLoggedItem(FList[FindControl(TMenuItem(Sender))]).OldClickEvent(Sender);
end;


procedure StartMenuLogging(AComponent: TComponent);

  procedure CheckControls(Comp: TComponent);
  var
    i: Integer;
  begin
    if Comp is TMenuItem then
      LogMan.AddControl(TMenuItem(Comp))
    else
      for i := 0 to Comp.ComponentCount - 1 do
        CheckControls(Comp.Components[i]);
  end;

begin
  if not Assigned(LogMan) then
    LogMan := TLogManager.Create(nil);

  CheckControls(AComponent);
end;

procedure StopMenuLogging(AComponent: TComponent);

  procedure CheckControls(Comp: TComponent);
  var
    i: Integer;
  begin
    if Comp is TMenuItem then
      LogMan.RemoveControl(TMenuItem(Comp))
    else
      for i := 0 to Comp.ComponentCount - 1 do
        CheckControls(Comp.Components[i]);
  end;

begin
  if Assigned(LogMan) then
    CheckControls(AComponent);
end;

procedure StopAllMenuLogging;
begin
  LogMan.Free;
end;


initialization

finalization
  if Assigned(LogMan) then
     LogMan.Free;

end.
unitlogmenuclicks;
接口
使用
班级;
程序启动菜单记录(A组件:T组件);
程序停止菜单记录(A组件:T组件);
程序停止记录;
实施
使用
SysUtils,
菜单;
类型
PLoggedItem=^TLoggedItem;
TLoggedItem=记录
项目:项目;
OldClickEvent:TNotifyEvent;
结束;
TLogManager=class(TComponent)
私有的
FList:TList;
FLog:TFileStream;
过程删除(索引:整数);
函数FindControl(AItem:TMenuItem):整数;
程序日志点击(发送方:ToObject);
受保护的
程序通知(A组件:t组件;操作:t操作);推翻
公众的
构造函数创建(AOwner:TComponent);推翻
毁灭者毁灭;推翻
程序控制(AItem:TMenuItem);
程序删除控制(AItem:TMenuItem);
结束;
变量
LogMan:TLogManager=nil;
{TLogManager}
构造函数TLogManager.Create(AOwner:TComponent);
开始
继承;
FLog:=TFileStream.Create(ChangeFileExt(ParamStr(0),'.log')、fmCreate或fmShareDenyWrite);
FList:=TList.Create;
结束;
析构函数TLogManager.Destroy;
变量
i:整数;
开始
i:=FList.Count-1;
而我>=0做
删除(i);
免费飞行;
自由鞭打;
继承;
结束;
过程TLogManager.Notification(组件:TComponent;操作:TOperation);
开始
如果操作=操作,则
移除控制(TMenuItem(组件));
继承;
结束;
过程TLogManager.Delete(索引:整数);
变量
李:普洛格主义;
开始
li:=FList[索引];
和李多
开始
项目。RemoveFreeNotification(自我);
Item.OnClick:=OldClickEvent;
结束;
处置(李);
FList.Delete(索引);
结束;
函数TLogManager.FindControl(AItem:TMenuItem):整数;
开始
结果:=FList.Count-1;
而(Result>=0)和(PLoggedItem(FList[Result])。Item AItem
12月(结果);
结束;
程序TLogManager.AddControl(AItem:TMenuItem);
变量
李:普洛格主义;
开始
如果未分配(AItem),则
出口
如果FindControl(AItem)>=0,则
出口
新(李),;
li.项目:=AItem;
li.OldClickEvent:=AItem.OnClick;
AItem.OnClick:=LogClick;
FList.Add(li);
自由通知(自我);
结束;
程序TLogManager.RemoveControl(AItem:TMenuItem);
变量
i:整数;
开始
如果分配(AItem),则
开始
i:=FindControl(AItem);
如果i>=0,则
删除(i);
结束;
结束;
过程TLogManager.LogClick(发送方:TObject);
变量
s:字符串;
开始
s:=格式(“%s:%s”+sLineBreak[t组件(发件人).Name,FormatDateTime(“”,Now)];
鞭打书写缓冲区(s[1],长度(s));
PLoggedItem(FList[FindContr