12

在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;
    

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

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

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

4

3 回答 3

9

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

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

于 2015-03-01T21:18:06.527 回答
5

一般来说

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

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

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

当您将更新事件中的代码持续时间保持在最低限度时,例如不通过数据库连接检查密码,那么性能将显得正常。如果您有与更新操作相关的冗长操作,请在这些特定情况下使用手动更新。

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

具体来说

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

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

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

但是,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;

或测试所选项目是否为零:

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;
于 2015-03-01T12:58:51.153 回答
0

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

于 2015-03-01T11:17:58.250 回答