0

我被要求在我们的程序中放置一些东西,以便在某处记录表单上发生的事情......

记录诸如此类的内容...单击了这个或那个按钮、上下文菜单、组件上触发的事件等等..

这主要是因为我们正在处理遗留代码,不幸的是,我们正在尽可能地调整/审查(Delphi XE10)并且我们希望从用户的角度跟踪正在发生的一切(或大部分),以便- 当一些神秘的事情发生时,能够引导用户做了什么 - 当我们不知道事情是如何发生的时候,能够在必要时审查代码 - 最终速度问题

我不是在谈论异常或数据记录......这些都得到了妥善处理。

这只是关于用户界面。

你知道是否有任何图书馆可以做类似的事情吗?如果没有,您将如何尝试实现这一目标?

代码示例很受欢迎(甚至很简单,例如一个/多个带有几个按钮的表单等)

谢谢大家!!!

4

2 回答 2

1

作为轻量级解决方案,您可以使用OutputDebugString(PChar('My logtext'))TFile.AppendAllText('log.txt','My logtext')

如果您想要使用特殊查看器、线程安全等进行花哨的日志记录,您可以包含一些特殊的日志记录框架。在这种情况下,最好在线搜索并自己比较功能,而不是在这里征求意见。

于 2017-07-05T10:40:16.223 回答
0

您可以开发一个非可视组件并将其放在每个表单上,但这必须是一个非常复杂的组件,它要么使用 RTTI,要么查看 Windows 消息以尝试侦听表单中其他可视组件发生的情况。

我看到两种更简单的方法可以至少完成您所要求的部分内容......

1) 拦截对事件处理程序的调用

开发一个组件(比我上面提到的那个简单一些),它连接到您感兴趣的控制类的事件,记录调用,然后将它们转发到原始事件处理程序(如果有的话)。

假设您对TWinControl.OnEnter和感兴趣OnExitTButton.OnClick并且TEdit.OnChange...

TEventLogger = Class(TComponent)
Private
  Procedure Hookup(Const EventName: String; Const Component: TComponent; Const LoggingHandler: TNotifyEvent; Var Handler: TNotifyEvent);
Public
  Procedure Setup(Const Container: TComponent);
  Procedure HandleChange(Sender: TObject);
  Procedure HandleClick(Sender: TObject);
  Procedure HandleEnter(Sender: TObject);
  Procedure HandleExit(Sender: TObject);
End;

Procedure TEventLoggerHookup(Const EventName: String; Const Component: TComponent; Const LoggingHandler: TNotifyEvent; Var Handler: TNotifyEvent);
Begin
  if Assigned(Handler) Then
    Handlers.AddObject(Component.Name + ';' + EventName, Handler);
  Handler := LoggingHandler;
End;

Procedure TEventLogger.Setup(Const Container: TComponent);
Var
  i: Integer;
  c: TComponent;
Begin
  For i:=0 to Container.ComponentCount - 1 Do Begin
    c := Container.Components[i];
    if c Is TWinControl Then Begin
      Hookup('Enter',HandleEnter,TWinControl(c).OnEnter;
      Hookup('Exit',HandleExit,TWinControl(c).OnExit;
    End;
    If c Is TButton Then 
      Hookup('Click',HandleClick,TButton(c).OnClick;
    If c Is TEdit Then 
      Hookup('Change',HandleChange,TEdit(c).OnChange;
  End;
End;

Procedure TEventLogger.Procedure HandleChange(Sender: TObject);
Var
  s: String;
  i: Integer;
  e: TNotifyEvent;
Begin
  With Sender As TComponent Do Begin
    s := Name + ';Change';
    Log(s);
    i:= Handlers.IndexOf(s);
    If i <> -1 Then Begin
      e := Handlers.Objects[i];
      e(Sender);
    End;
  End;
End;

这没有经过测试,但我认为你明白了。要记住的事情:

  • 处理程序很简单TStringList……但您可以使用通用的TDictionary<Key,Value>. 当然,您应该适当地创建和销毁它。
  • 所有列出的事件都是TNotifyEvents。但是您可以轻松地重载 Hookup 过程来处理其他类型的 ov 事件。
  • 当组件已经创建并且属性从 dfm 流入时,必须执行设置。这可能需要您向每个表单添加一些代码。
  • 如果您的应用程序在运行时以动态方式创建控件,或者如果它在运行时与事件处理程序混淆,则此技术可能(并且将会)适得其反。

2)使用继承

为您要记录的每个使用的可视组件派生一类新的可视组件。您需要为每一个定义一个 Log 方法并覆盖您感兴趣的特定“事件”方法。例如:

TLogButton = class(TButton)
private
  procedure Log(Const Event: String);
protected
  procedure Click; override;
end;

TLogButton.Click;
begin
  Log('Click');
  Inherited;
end;

然后,您可以实现 Log 方法,添加您需要的所有信息(表单和组件类和名称,或其他)。如果你想做一些复杂的事情,那么你最好将日志操作委托给一个专门的类。

这也没有经过测试。要记住的事情:

  • 要设置它,您可以使用大量搜索和替换...在 pas 和 dfm 文件中修改TButton... TLogButton(我希望您使用文本 dfm,如果不是,最好将它们转换为文本)。
  • 您必须将新单元添加到包含您感兴趣的控件的所有表单的界面部分
  • 您应该在自定义库中注册新类,以便在 IDE 中使用它们,否则您将无法在设计时打开表单。
  • 您必须为您感兴趣的每个类都这样做......如果应用程序使用许多不同但相似的控件类,这可能会变得混乱。
  • 您必须知道要记录的类的内部结构...并非所有方法都是可覆盖的...许多第三方库没有提供源代码...这可能是地狱。

结论

总的来说......我可能会选择后一种解决方案。在单个控件类上实现基本上更容易,并且您可能已经通过一堆类获得了一些非常有用的用户活动跟踪。前一种解决方案更复杂一些,可能会扩展到涵盖某些情况......但是很难彻底测试,如果您不太了解您的代码库,风险太大。

于 2017-07-06T14:40:13.197 回答