Delphi:如何在不调用onchange事件的情况下在TEdit/TMaskEdit中设置文本

Pet*_*ner 3 delphi event-handling

我有一个非常大的设置表单,我想填充一个类的数据.所以我做了很多

Edt1.text := ASettings.FirstThing; 
Run Code Online (Sandbox Code Playgroud)

我想避免

Edt1.onchange := nil;
Edt1.text := ASettings.FirstThing; 
Edt1.onchange := edt1Onchange;
Run Code Online (Sandbox Code Playgroud)

如何更改文本框中的文本并回避onchange事件.

jas*_*nny 11

我使用过类似OnChange处理程序的东西,但更常见的是,我使用了一个标志.

updatingFromCode := true;
Edt1.Text := ASettings.FirstThing;
updatingFromCode := false;
Run Code Online (Sandbox Code Playgroud)

然后

procedure TForm1.OnChange(...);
begin
  if updatingFromCode then
    Exit;
  ...
Run Code Online (Sandbox Code Playgroud)


另外,我不是硬编码OnChange实际的OnChange过程,而是存储Edit控件的当前值,然后重置它(如果没有设置它会工作,或者如果另一个地方改变了它,等等)

oldOnChange := Edt1.OnChange;
Edt1.OnChange := nil;
Edt1.Text := ASettings.FirstThing; 
Edt1.OnChange := oldOnChange;
Run Code Online (Sandbox Code Playgroud)

  • 不会.无论文本是由用户更新还是可编程,OnChange事件的发件人将始终是TEdit.VCL从不将Sender参数设置为nil. (3认同)

Del*_*ics 7

您可以考虑使用对象来管理事件的NIL并恢复以前安装的事件处理程序.假设要恢复的事件碰巧是在设计时指定的事件/恰好具有"适合的名称" - 有点危险 - 你应该总是保存/恢复当前分配的处理程序,只是为了安全.

这将提供比SetTextWithoutOnChange()例程更可重用的实用程序:

  TSuspendEvent = class
  private
    fObject: TObject;
    fEvent: String;
    fHandler: TMethod;
  public
    constructor Create(const aObject: TObject; aEvent: String);
    destructor Destroy; override;
  end;

  constructor TSuspendEvent.Create(const aObject: TObject; aEvent: String);
  const
    NILEvent  : TMethod = (Code: NIL; Data: NIL);
  begin
    inherited Create;

    fObject := aObject;
    fEvent  := aEvent;

    fHandler := GetMethodProp(aObject, aEvent);

    SetMethodProp(aObject, aEvent, NILEvent);
  end;


  destructor TSuspendEvent.Destroy;
  begin
    SetMethodProp(fObject, fEvent, fHandler);

    inherited;
  end;
Run Code Online (Sandbox Code Playgroud)

在使用中,这看起来像:

  with TSuspendEvent.Create(Edit1, 'OnChange') do
  try
    Edit1.Text := 'Reset!';
  finally
    Free;
  end;
Run Code Online (Sandbox Code Playgroud)

对于"你不能使用' '人群' - 通过各种方式声明自己一个额外的局部变量,并使用它,如果它将帮助你在晚上更容易入睡.:)

或者,为了使它更方便使用和消除" with ",我会使TSuspendEvent类成为一个接口对象,并将其用于一个函数,该函数产生一个可以允许"生活在范围内"的接口引用,以我的AutoFree()实现为例.实际上,您可以使用AutoFree()来管理它:

  AutoFree(TSuspendEvent.Create(Edit1, 'OnChange'));
  Edit1.Text := 'Reset!';
Run Code Online (Sandbox Code Playgroud)

在超出单个过程范围的时间段内启用事件需要比任何帮助程序实用程序可能以通用方式提供的更多管理,我认为,至少在没有明确恢复事件的特定方法的情况下,而不是自动.

如果您只是将TSuspendEvent包装在它自己的接口生成函数中,遵循与AutoFree()相同的模式,您可以进一步简化为:

  SuspendEvent(Edit1, 'OnChange');
  Edit1.Text := 'Reset!';
Run Code Online (Sandbox Code Playgroud)

作为最后一点,我认为应该很容易看出如何将其简单地扩展到支持在单个调用中挂起对象的多个事件(如果需要),例如:

  SuspendEvent(Edit1, ['OnChange', 'OnEnter']);
Run Code Online (Sandbox Code Playgroud)


Ale*_*exV 6

据我所知,如果你的对象的OnChange被设计为在Text属性被更改时触发,你必须坚持将事件设置为nil temporrly.我自己,我这样做(终于试一试):

Edt1.onchange := nil;
try
    Edt1.text := ASettings.FirstThing;
finally
    Edt1.onchange := edt1Onchange;
end;
Run Code Online (Sandbox Code Playgroud)

你也可以做一些程序来为你处理它:

procedure SetTextWithoutOnChange(anEdit: TEdit; str: String);
var
    anEvent: TNotifyEvent;
begin
    anEvent := anEdit.OnChange;
    anEdit.OnChange := nil;
    try
        anEdit.Text := str;
    finally
        anEdit.OnChange := anEvent;
    end;
end;
Run Code Online (Sandbox Code Playgroud)

  • 添加了 SetTextWithoutOnChange 过程来回答。 (2认同)