TAction.OnUpdate 事件会降低性能吗?

问题描述 投票:0回答:4

在Delphi XE7中,我使用这个技巧根据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;
    

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

但是,在 CodeSite Live Viewer 中,我可以看到

actTestUpdate
事件被连续且频繁地触发,因此语句 actTest.Enabled := ListView1.SelCount > 0;
 经常被执行。

所以我的问题是:这会降低性能吗?如果是的话,还有什么技巧可以达到上述目的吗?

delphi delphi-xe7 tlistview taction
4个回答
9
投票
如果您有(或计划有)许多操作,您可能需要将 Application.ActionUpdateDelay 设置为例如50 毫秒。这可以显着提高性能。

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


5
投票
一般

是的,

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 = 0

SelCount > 0
 之间发出信号的信号,因此无论如何,您都会比严格必要的情况更多地评估该行代码。

假设

MultiSelect

 为 true,您也可以自己计算选择更改,从而无需调用 
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;
或者测试所选项目是否为零:

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;
    

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


0
投票
您可以编写一个触发

OnExecute 操作的事件,并使用其 Action

 指针参数来比较它是由哪个操作触发的。执行所需操作的代码后,您可以调用某种 
UpdateControls()
 过程,该过程可以为您更新按钮的启用/禁用状态。

在这种情况下,

OnExecute

将被调用
仅一次,并且仅在您触发特定操作后并进行适当的控件可见性更新。此外,通过这种方式管理,您可以获得集中的操作管理,而不是每个操作都有 OnExecute
 事件。

© www.soinside.com 2019 - 2024. All rights reserved.