如何使用操作来确定控件的可见性?

时间:2012-04-12 16:24:50

标签: delphi

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

Pascal文件

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的检查似乎阻止我的行动再次有机会自我更新。

我是否正确诊断了该问题?这是设计还是我应该提交质量控制报告?有没有人知道一种解决方法?

3 个答案:

答案 0 :(得分:8)

您的诊断是正确的。自从他们第一次被引入德尔福以来,行动一直是这样的。

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

我能想象的任何解决方法都会让你的复选框代码直接操纵受影响的操作,这不是很优雅,因为它不应该知道它可能影响的所有其他内容 - 这就是OnUpdate事件应该为你做。选中此复选框后,请致电Action1.Update,如果这不起作用,则Action1.Visible := True

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

答案 1 :(得分:4)

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

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

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

顺便说一下,当动作和动作列表首次推出时,Ray Konopka(Raize组件)写了几篇关于它们实现的文章,并就如何使用它们给出了非常合理的建议。从那以后,我采用了使用每个Action的OnExecute的做法,但是要使用ActionList的OnUpdate。此外,我在该处理程序中做的第一件事是将Handled设置为True,因此不会超过必要的调用,并且只在该处理程序中更改一次Action的Enabled属性,因此GUI不会因此而闪烁把它关掉再打开。

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

答案 2 :(得分:2)

当相关控件不可见时,不会调用ActionUpdate事件。尝试在Checkbox点击事件上显式调用Action Update。