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

时间:2015-03-01 10:57:29

标签: delphi delphi-xe7 tlistview taction

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

  • 在VCL表格上放置TActionList。
  • 在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;
    

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

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

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

3 个答案:

答案 0 :(得分:7)

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

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

答案 1 :(得分:4)

一般

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

  

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

这可能是免于使用的原因。但你应该意识到单个表达式的评估大多不需要花费那么多时间。此外,要意识到无论动作更新如何,您的应用程序都会在每次鼠标移动时执行(更加繁重)计算和操作。

当您将代码持续时间保持在最新状态时,将事件更新为最小值,例如没有通过数据库连接进行密码检查,然后性能将正常显示。如果您有与更新操作相关的冗长操作,那么请回到这些特定情况下的手动更新。

请注意,不使用Actions的单个OnUpdate事件可以略微提高性能,但ActionList的OnUpdate事件却有Handled参数取消进一步处理,具有集中化和分类的额外好处。

具体地

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

另一种方法是更新ListView的OnSelectItem事件中的操作。该事件将捕获由鼠标和键盘交互引起的所有选择更改,以及设置单个项目 Selected财产:

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

但是,ListView和VCL都没有提供任何信号,只能在SelCount = 0SelCount > 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;

或者测试所选项目为nil:

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

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

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

答案 2 :(得分:0)

Action(更新)事件(主要)在Application.Idle中执行。只要您不在事件处理程序中执行时间关键的事情,就不会出现明显的性能下降。