7

我正在尝试使用操作来控制控件的可见性。我的代码如下所示:

帕斯卡文件

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ActnList, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    ActionList1: TActionList;
    Action1: TAction;
    CheckBox1: TCheckBox;
    procedure Action1Update(Sender: TObject);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Action1Update(Sender: TObject);
begin
  (Sender as TAction).Visible := CheckBox1.Checked;
end;

end.

表格文件

object Form1: TForm1
  object Button1: TButton
    Left = 8
    Top = 31
    Action = Action1
  end
  object CheckBox1: TCheckBox
    Left = 8
    Top = 8
    Caption = 'CheckBox1'
    Checked = True
    State = cbChecked
  end
  object ActionList1: TActionList
    Left = 128
    Top = 8
    object Action1: TAction
      Caption = 'Action1'
      OnUpdate = Action1Update
    end
  end
end

当表单第一次运行时,按钮是可见的并且复选框被选中。然后我取消选中复选框,按钮消失。当我重新选中复选框时,按钮无法重新出现。

我认为可以在以下本地函数中找到其原因TCustomForm.UpdateActions

procedure TraverseClients(Container: TWinControl);
var
  I: Integer;
  Control: TControl;
begin
  if Container.Showing and not (csDesigning in Container.ComponentState) then
    for I := 0 to Container.ControlCount - 1 do
    begin
      Control := Container.Controls[I];
      if (csActionClient in Control.ControlStyle) and Control.Visible then
          Control.InitiateAction;
      if (Control is TWinControl) and (TWinControl(Control).ControlCount > 0) then
        TraverseClients(TWinControl(Control));
    end;
end;

检查Control.Visible似乎阻止了我的行动有机会再次更新自己。

我是否正确诊断了问题?这是设计使然还是我应该提交 QC 报告?有谁知道解决方法?

4

3 回答 3

8

你的诊断是正确的。自从首次将 Actions 引入 Delphi 以来,它们就一直以这种方式工作。

我希望它是设计使然(可能是为了避免过度更新文本和不可见控件的其他视觉方面的优化),但这并不意味着设计是好的。

我可以想象的任何解决方法都将涉及您的复选框代码直接操作受影响的操作,这不是很优雅,因为它不必知道它可能影响的所有其他内容——这就是OnUpdate事件应该为您做的事情。当复选框被选中时,调用Action1.Update,或者如果这不起作用,则调用Action1.Visible := True

您也可以将您的操作更新代码放入TActionList.OnUpdate事件中。

于 2012-04-12T16:43:04.217 回答
4

是的,正如 Rob 已经说过和解释的那样,您的诊断是正确的。一种解决方法是不使用单个 TAction 的 OnUpdate 事件处理程序,而是使用 TActionList 的 OnUpdate 事件处理程序。

procedure TForm1.ActionList1Update(Action: TBasicAction; var Handled: Boolean);
begin
  Handled := True;
  Action1.Visible := CheckBox1.Checked;
end;

您确实需要至少一个带有链接操作的可见控件才能使其工作,否则也不会调用 ActionList 的 OnUpdate 处理程序。

顺便说一句,当第一次引入 Actions 和 ActionLists 时,Ray Konopka(Raize 组件)写了几篇关于它们实现的文章,并就如何使用它们给出了非常中肯的建议。从那以后,我采用了使用每个单独Action 的OnExecute,但使用ActionList 的OnUpdate 的做法。另外,我在该处理程序中做的第一件事是将 Handled 设置为 True,这样它就不会被不必要地调用,并且只在该处理程序中更改一次 Action 的 Enabled 属性,这样 GUI 就不会因此而闪烁关闭它然后打开。

Ray Konopka 的文章是“有效地使用动作列表”:http : //edn.embarcadero.com/article/27058 Ray 曾经在他自己的网站上发表过三篇文章,但在 embarcadero 上只有一篇,但很可能是“组合”版本(手边没有原件)。

于 2012-04-12T19:06:52.490 回答
2

当相关控件不可见时,不会调用 ActionUpdate 事件。尝试在 Checkbox1 的单击事件上显式调用 ActionUpdate。

于 2012-04-12T16:35:02.723 回答