Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi 更改代码中的ItemIndex属性时发生ComboBox OnChange事件_Delphi_Events_Combobox_Firemonkey - Fatal编程技术网

Delphi 更改代码中的ItemIndex属性时发生ComboBox OnChange事件

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()方法中完

我在Delphi10.1 Berlin上使用FMX

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

以编程方式更改
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;