Delphi 更改代码中的ItemIndex属性时发生ComboBox OnChange事件
我在Delphi10.1 Berlin上使用FMX 我读到(这是我想要的行为): 以编程方式更改Delphi 更改代码中的ItemIndex属性时发生ComboBox OnChange事件,delphi,events,combobox,firemonkey,Delphi,Events,Combobox,Firemonkey,我在Delphi10.1 Berlin上使用FMX 我读到(这是我想要的行为): 以编程方式更改ItemIndex不会导致触发OnChange事件。它仅在响应用户交互时激发 这仅适用于VCL吗 我这样做是因为,不幸的是,根据我的测试,修改code中的ItemIndex属性会触发OnChange事件 如果这是真的,我如何实现与FireMonkey中VCL相同的行为?处理此问题的正确方法是首先找出调用OnChange处理程序的位置。这是在TCustomComboBox.DoChange()方法中完
ItemIndex
不会导致触发OnChange
事件。它仅在响应用户交互时激发
这仅适用于VCL吗
我这样做是因为,不幸的是,根据我的测试,修改code中的ItemIndex
属性会触发OnChange
事件
如果这是真的,我如何实现与FireMonkey中VCL相同的行为?处理此问题的正确方法是首先找出调用
OnChange
处理程序的位置。这是在TCustomComboBox.DoChange()方法中完成的
因此,您需要做的是:
重写默认的DoChange()
方法以不触发OnChange
事件方法
重写ItemIndex
属性设置程序以使用不同的逻辑,该逻辑不会调用DoChange()
方法
这两种方法都要求您为修改后的组合框创建一个新类
这仅适用于VCL吗
在FMX中,许多事情是以不同的方式处理的
如果这是真的,我如何实现与FireMonkey中VCL相同的行为
一个简单的解决方法是在更改ItemIndex
之前取消OnChange
事件属性,然后恢复事件
要做到这一点,一个简单的例程是这样的(如@Remy所述):
在更改ItemIndex之前将OnChange设置为nil,然后恢复OnChange处理程序。@我认为这是最糟糕的方法。为什么?在将OnChange设置为nil之前,您需要存储它的当前值,以便以后能够还原它,这意味着您需要在代码中引入另一个变量。您可以设置一个变量,该变量是事件查看的,如果设置了该变量,则会立即退出,而不是重置事件本身。但这仍然引入了一个变量。哪一个不是世界末日…@LURD:这会更好:过程SetItemIndex(ix:Integer;cb:TComboBox);var原始:TNotifyEvent;开始原始:=cb.OnChange;cb.OnChange:=零;尝试cb.ItemIndex:=ix;最后cb.OnChange:=原件;结束;结束代码>@kobik,完成。谢谢。如果您重写DoChange()
,您还必须为它引入一个新的属性或参数,以便它在决定何时触发事件(用户操作)和何时不触发事件(编码操作)时查看。您不能重写ItemIndex
设置程序,因为TCustomComboBox.SetItemIndex()
不是virtual
首先,您必须修改FMX.ListBox.pas
并将其包含在项目中。@RemyLebeau如果您是正确的。无法覆盖项索引
设置器,因为它不是虚拟的
。我错过了。因此,有必要在使用不同setter方法的派生类中重新声明Itemindex
属性。或者,只需添加一个被重写的DoChange()
可以查看的新属性。在代码中设置ItemIndex
之前设置该属性,然后将其重置。您不需要重新声明ItemIndex
本身。@RemyLebeau如果引入新属性,那么引入新属性来访问ItemIndex
值而不调用DoChange
方法不是更好吗。您建议的方法将要求每次以编程方式更改ItemIndex
值时调用三次,这将使整个代码变得非常难看。也许会,但重新声明属性也不能保证始终调用新的setter。仅当直接访问新的TDerivedComboBox.ItemIndex
属性时,而不是在访问基类T(自定义)ComboBox.ItemIndex
属性时。至少我的解决方案能正确处理这个问题。此外,基类setter访问派生类中的新setter无法访问的私有成员(FListBox
、FListPicker
、FItemIndex
、和UpdateCurrentItem()
),因此实现新setter实际上不是一个选项。有一刻我希望这是一个FireMonkey bug。。。在从代码调用事件之前设置一个布尔变量,并在执行OnChange命令之前测试它,这是一个坏主意吗?
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;