TAction.OnUpdate事件是否会降低性能?

use*_*348 10 delphi taction tlistview delphi-xe7

在Delphi XE7中,我使用此技巧根据是否选择了ListView中的项目来自动启用或禁用工具栏按钮("编辑ListView项目"),以防止用户在没有ListView时单击按钮选择的项目:

  • 将TActionList放在VCL表单上.
  • 在ActionList中创建一个动作actTest.
  • 将TButton放在表单上.
  • 将操作分配actTest给按钮.
  • 在表单上放置一个TListView.
  • 在ListView中创建两个项目.
  • OnUpdate该事件actTest的行动写:

     procedure TForm1.actTestUpdate(Sender: TObject);
     begin
       actTest.Enabled := ListView1.SelCount > 0;
       CodeSite.Send('actTestUpdate'); // gets fired very often!
     end;
    
    Run Code Online (Sandbox Code Playgroud)

现在,您可以看到根据是否选择了ListView中的项目来启用或禁用该按钮,与您是使用鼠标还是使用键盘或以编程方式选择/取消选择项目无关.

但是,在CodeSite Live Viewer中,我可以看到actTestUpdate事件是连续且非常频繁地触发的,因此该语句很快actTest.Enabled := ListView1.SelCount > 0;就被执行了.

所以我的问题是:这会降低性能吗?如果是,是否有另一种技巧可以实现上述目的?

pyx*_*ata 8

如果您有(或计划拥有)许多操作,您可能需要将Application.ActionUpdateDelay设置为例如50毫秒.这可以提高性能显着.

此外,如果您有许多操作,我建议您尝试使用TForm.UpdateActions而不是为每个操作定义TAction.OnUpdate.它将使代码更具可读性.


NGL*_*GLN 5

一般来说

是的,OnUpdate事件处理程序需要时间,就像任何其他例程一样。多个处理程序需要多倍的时间。所有代码的总和将评估导致无事可做的条件。从这个意义上说,您可以得出结论,此更新机制会降低性能。特别是考虑到这些更新事件经常发生:

在应用程序空闲或操作列表更新时发生。

这可能是不使用它的一个原因。但是您应该意识到,对单个表达式的评估通常不会花费太多时间。此外,无论操作更新如何,您的应用程序都会对鼠标的每一次移动执行(更繁重的)计算和操作。

当您将操作更新事件中的代码持续时间保持在最短时,例如不通过数据库连接检查密码,那么性能将看起来正常。如果您有冗长的操作与更新操作相关联,那么在这些特定情况下,请回退到手动更新。

请注意,通过不使用OnUpdateActions的单个事件,而是OnUpdate使用 ActionList的事件,可以稍微提高性能,该事件具有Handled取消进一步处理的参数,具有集中化和分类的额外好处。

具体来说

ListView1.SelCount向控件发送 WinAPI 消息以检索选择计数。这是一个很小的操作,我不会打扰它所需的时间。

另一种方法是更新 ListViewOnSelectItem事件中的操作。该事件将捕获由于鼠标和键盘交互以及设置单个项目的Selected属性而导致的所有选择更改 :

procedure TForm1.ListView1SelectItem(Sender: TObject; Item: TListItem;
  Selected: Boolean);
begin
  actTest.Enabled := ListView1.SelCount > 0;
end;
Run Code Online (Sandbox Code Playgroud)

但是, ListView 和 VCL 不提供任何仅在SelCount = 0和之间发出信号的内容SelCount > 0,因此无论如何您将更加严格地评估该行代码。

假设MultiSelect是真的,您还可以自己计算选择更改以消除调用的需要SelCount

  private
    FListViewSelected: Longbool;

procedure TForm1.ListView1SelectItem(Sender: TObject; Item: TListItem;
  Selected: Boolean);
begin
  if Selected then
    Inc(FListViewSelected)
  else
    Dec(FListViewSelected);
  actTest.Enabled := FListViewSelected;
end;
Run Code Online (Sandbox Code Playgroud)

或测试所选项目为零:

procedure TForm1.ListView1SelectItem(Sender: TObject; Item: TListItem;
  Selected: Boolean);
begin
  actTest.Enabled := ListView1.Selected <> nil;
end;
Run Code Online (Sandbox Code Playgroud)

但话又说回来,真的没有理由不使用该OnUpdate事件:

procedure TForm1.ActionList1Update(Action: TBasicAction; var Handled: Boolean);
begin
  actTest.Enabled := ListView1.Selected <> nil;
  Handled := True;
end;
Run Code Online (Sandbox Code Playgroud)


Uwe*_*abe 0

Action 更新事件(大部分)在 Application.Idle 内执行。只要您不在事件处理程序中执行时间关键的操作,就不会有明显的性能下降。