2010-01-06 77 views

回答

11

我已经使用了类似更改OnChange处理程序的内容,但更常见的是,我使用了一个标志。

updatingFromCode := true; 
Edt1.Text := ASettings.FirstThing; 
updatingFromCode := false; 

然后

procedure TForm1.OnChange(...); 
begin 
    if updatingFromCode then 
    Exit; 
    ... 


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

oldOnChange := Edt1.OnChange; 
Edt1.OnChange := nil; 
Edt1.Text := ASettings.FirstThing; 
Edt1.OnChange := oldOnChange; 
+1

你不能也使用发件人参数吗?据推测,他希望OnChange能够在有人将文本输入框中时触发,而不是在从单独的过程中填充文本时(如自动填充类型)。在这种情况下,我是否认为你可以拥有TForm1.OnChange(发件人:TObject),然后做“如果发件人为TEdit”(做其他)(什么都不做)“?那么你没有所有额外的东西在代码中设置和取消设置变量 – 2010-05-13 00:18:10

+2

编号OnChange事件的发送者将永远是TEdit,无论用户是更新文本还是可编程地发送.VCL从未将发送者参数设置为零 – 2010-06-23 21:03:46

5

据我所知,如果您的对象的OnChange设计为在Text属性更改时触发,则必须坚持将事件临时设置为零。我自己,我做这种方式(在一个try最后):

Edt1.onchange := nil; 
try 
    Edt1.text := ASettings.FirstThing; 
finally 
    Edt1.onchange := edt1Onchange; 
end; 

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

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; 
+1

已添加SetTextWithoutOnChange procdeure to answer。 – AlexV 2010-01-06 18:37:31

+0

+1 for exception block – TridenT 2013-08-31 19:38:09

6

你可能会考虑使用一个对象来管理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; 

在使用,这看起来是这样的:

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

对于“你不要使用''人群' - 通过一切手段宣布自己一个额外的本地变量,并使用它,如果它可以帮助你在夜间更容易入睡。:)

或者,使其更方便地使用和消除“”,我会做TSuspendEvent类的接口对象,敷在产生一个接口引用它的功能及其使用的是可以允许“住在范围”,as exemplified by my AutoFree() implementation. In fact, you could use AutoFree() as-is已经管理这个:

AutoFree(TSuspendEvent.Create(Edit1, 'OnChange')); 
    Edit1.Text := 'Reset!'; 

Dsabling事件一个超出单一程序的范围,期限,需要更多的管理比任何帮助工具,很可能是能够我认为这是以一种通用的方式提供的,至少不是没有特定的手段显式存储事件,而不是自动。

如果你只是包裹TSuspendEvent里面它自己的界面产生功能,千篇一律的AutoFree(),你可以进一步简化这:

SuspendEvent(Edit1, 'OnChange'); 
    Edit1.Text := 'Reset!'; 

最后一点,我认为这应该很容易看出,如果需要,可以简单地扩展以支持在单个调用中暂停对象上的多个事件,例如:

SuspendEvent(Edit1, ['OnChange', 'OnEnter']); 
+0

哇,这似乎很多工作,尽管可能值得。我会记住这一点,并可能在某一天实施它,谢谢! – 2010-06-24 13:25:58

+0

这不是很多工作,真的大约需要3分钟,而“AutoFree”大约需要10分钟),结果是在您使用结果的项目的整个生命周期内将继续累计节约成本(代码完全是generi c - 小'g')。 – Deltics 2010-06-24 21:09:22

1

我知道这是一个古老的问题,但我想我会添加我的解决方案,而不涉及前面的答案中列出的任何复杂的过程,以防它出现在另一个搜索中。

问题是onChange事件本身。我根本不使用它来处理文本字段。

删除所有OnChange并使用OnExit代替并将其绑定到OnKeyUp。

所有的编辑都有一个共同的祖先TCustomEdit。

我一般使用称为CustomEditKeyUp一种方法和指向一个表上的所有编辑这个单一的方法(TEDIT,TLabeledEdit等等)

type THack = class(TCustomEdit); 

procedure TForm1.CustomeEditKeyUP(Sender: TObject; var Key: Word; 
    Shift: TShiftState); 
begin 
    if (Key=VK_RETURN) and (Sender is TCustomEdit) then 
    {This is just to isolate the one occasion when they press the 
    enter but don't exit immediately} 
    if Assigned(THack(Sender).OnExit) then THack(Sender).OnExit(Sender); 
end; 

出于某种原因,所述的OnExit处于TCustomEdit私人所以黑客是需要的。如果您知道编辑内容来自OnExit公开的其他路线,则投射方式不同,而且Hack不是必需的。

然后为每个编辑的控制,如果你想以编程方式更改值没有它发射使用特定的OnExit

procedure TForm1.MyEditExit(Sender: TObject); 
begin 
    if MyEdit.Modified then 
    begin 
    {Do Something here} 
    MyEdit.Modified := false; 
    end; 
end; 

“的OnExit”

.... 
MyEdit.Text :='I've changed it' 
MyEdit.Modified := false; 
.... 

对我来说,最大的好处就是,当我解析输入为一个有效的数字,我只需要这样做一次编辑完成后,而不是每个退格,删除插入等所有包围的尝试,除了各种格式函数错误,因为他们不明白空间等。对于数据库e tc,通话次数会大大减少。

这是我的两个通便。

相关问题