【问题标题】:ComboBox OnChange event occurs when changing the ItemIndex property in code在代码中更改 ItemIndex 属性时发生 ComboBox OnChange 事件
【发布时间】:2017-07-31 19:10:54
【问题描述】:

我在 Delphi 10.1 Berlin 上使用 FMX。

我读到了这个(这是我想要的行为):

https://stackoverflow.com/a/42933567/1343976

以编程方式更改 ItemIndex 不会导致触发 OnChange 事件。它仅在响应用户交互时触发。

这仅适用于 VCL 吗?

我要求这样做是因为,不幸的是,根据我可以测试的情况,修改代码中的 ItemIndex 属性触发OnChange 事件。

如果这是真的,我怎样才能在 FireMonkey 中实现与 VCL 相同的行为?

【问题讨论】:

  • 在更改 ItemIndex 之前将 OnChange 设置为 nil,然后恢复 OnChange 处理程序。
  • @LURD 我认为这是您可以使用的更糟糕的方法。为什么?在将 OnChange 设置为 nil 之前,您需要存储其当前值以便以后能够恢复它,这意味着您需要在代码中引入另一个变量。
  • 与其重置事件本身,不如设置事件查看的变量,如果设置了变量,则立即退出。但这仍然引入了一个变量。这不是世界末日...
  • @LURD:这样会更好:procedure SetItemIndex(ix : Integer; cb: TComboBox); var original: TNotifyEvent; begin original := cb.OnChange; cb.OnChange := nil; try cb.ItemIndex := ix; finally cb.OnChange := original; end; end;
  • @kobik,完成。谢谢。

标签: delphi events combobox firemonkey


【解决方案1】:

这仅适用于 VCL 吗?

许多事情在 FMX 中以不同的方式处理。

如果这是真的,我怎样才能在 FireMonkey 中实现与 VCL 相同的行为?

一个简单的解决方法是在更改ItemIndex 之前将OnChange 事件属性设为nil,然后再恢复事件。

执行此操作的简单例程是这样的(如@Remy 所述):

procedure SetItemIndex(ix : Integer; cb: TComboBox);
var
  original : TNotifyEvent;
begin
  original := cb.OnChange;
  cb.OnChange := nil;
  try
    cb.ItemIndex := ix;
  finally
    cb.OnChange := original;
  end;
end;  

【讨论】:

  • 有一刻我希望这是一个 FireMonkey 错误......在从代码调用事件之前设置一个布尔变量并在执行 OnChange 命令之前对其进行测试是不是一个坏主意?
【解决方案2】:

处理此问题的正确方法是首先找出调用OnChange 处理程序的位置。这是在TCustomComboBox.DoChange() 方法中完成的。

所以,你需要做的是:

  1. 覆盖默认的DoChange() 方法以不触发OnChange 事件方法。

  2. 覆盖ItemIndex 属性设置器以使用不会调用DoChange() 方法的不同逻辑。

这两种方法都要求您为修改后的ComboBox 创建一个新类。

【讨论】:

  • 如果您覆盖DoChange(),您还必须引入一个新属性或参数,以便在决定何时触发事件(用户操作)和何时不触发(编码操作)时查看.您不能覆盖ItemIndex 设置器,因为TCustomComboBox.SetItemIndex() 不是virtual,您必须修改FMX.ListBox.pas 并将其包含在您的项目中。
  • @RemyLebeau 你是对的。不可能覆盖ItemIndex setter,因为它不是virtual。我错过了。因此有必要在派生类中重新声明Itemindex 属性,该属性将使用不同的setter 方法。
  • 或者,只需添加一个被覆盖的DoChange() 可以查看的新属性。在代码中设置 ItemIndex 之前设置该属性,然后将其重置。您无需重新声明 ItemIndex 本身。
  • @RemyLebeau 如果引入新属性,最好引入一个新属性来访问ItemIndex 值而不调用DoChange 方法。每次您以编程方式更改 ItemIndex 值时,您建议的方法将需要三个调用,这会使整个代码变得丑陋。
  • 也许会,但重新声明属性并不能保证总是调用新的 setter。仅在直接访问新的TDerivedComboBox.ItemIndex 属性时而不是在访问基类T(Custom)ComboBox.ItemIndex 属性时。至少我的解决方案可以正确处理。此外,基类 setter 访问派生类中的新 setter 无法访问的私有成员(FListBoxFListPickerFItemIndexUpdateCurrentItem()),因此实现新的 setter 确实不是无论如何都是一个选项。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-22
  • 2011-06-01
相关资源
最近更新 更多