Recent

Author Topic: TComboBox and OnChange event  (Read 6978 times)

VTwin

  • Hero Member
  • *****
  • Posts: 1227
  • Former Turbo Pascal 3 user
TComboBox and OnChange event
« on: February 07, 2015, 05:35:08 pm »
I have a dialog box in which a TComboBox.ItemIndex must change. Setting this in code, however, triggers an OnChange event which is not supposed to happen. The OnChange event when triggered by the user makes other changes that I don't want to happen when I'm setting it in code.

I tried this:

Code: [Select]
procedure TVComboBoxHelper.SetInt(const i: integer);
var
  handler: TNotifyEvent;
begin
    handler := OnChange;
    OnChange := nil;
    ItemIndex := i;
    OnChange := handler;
 end;
end;

but the event still fires. I'm on Carbon (see below). This seems to be a bug. Does anyone have and experience with this, maybe a workaround?

By the way, if I don't revert OnChange from nil, the change event is not called, but of course then the ComboBox doesn't respond to the user.

Cheers,
VTwin
« Last Edit: February 07, 2015, 05:37:57 pm by VTwin »
“Talk is cheap. Show me the code.” -Linus Torvalds

Free Pascal Compiler 3.2.2
macOS 15.3.2: Lazarus 3.8 (64 bit Cocoa M1)
Ubuntu 18.04.3: Lazarus 3.8 (64 bit on VBox)
Windows 7 Pro SP1: Lazarus 3.8 (64 bit on VBox)

balazsszekely

  • Guest
Re: TComboBox and OnChange event
« Reply #1 on: February 07, 2015, 05:48:17 pm »
Try this:

Code: [Select]
var
  Skip: Boolean;

procedure TVComboBoxHelper.SetInt(const i: integer);
begin
  Skip := True;
  ItemIndex := i;
  Skip := False;
end;

procedure TForm1.YourComboChange(Sender: TObject);
begin
  if Skip then
    Exit;
  //...
end; 

VTwin

  • Hero Member
  • *****
  • Posts: 1227
  • Former Turbo Pascal 3 user
Re: TComboBox and OnChange event
« Reply #2 on: February 07, 2015, 06:05:03 pm »
Thanks GetMem,

I've been trying something like that, before I tried setting the event to nil, but it doesn't seem to work.

Code: [Select]
  ...
  fSetting := true;
  cbx.SetInt(1);
  fSetting := false;
  ...

procedure TDlg.cbxChange(Sender: TObject);
begin
  if fSetting then exit;
  ...
end;

I think the event may be posted in a queue and does not happen until leaving the function, but that's beyond my expertise. I was looking to see if another event could restore the flag, but I'm not sure what that would be.

VTwin
“Talk is cheap. Show me the code.” -Linus Torvalds

Free Pascal Compiler 3.2.2
macOS 15.3.2: Lazarus 3.8 (64 bit Cocoa M1)
Ubuntu 18.04.3: Lazarus 3.8 (64 bit on VBox)
Windows 7 Pro SP1: Lazarus 3.8 (64 bit on VBox)

balazsszekely

  • Guest
Re: TComboBox and OnChange event
« Reply #3 on: February 07, 2015, 06:14:35 pm »
TComboBox is buggy on carbon! For example, let's say you have a combo with 3 items. The first one is selected, so ItemIndex is 0.
Now, if you select the second one:
Code: [Select]
procedure TForm1.ComboBox1Change(Sender: TObject);
begin
  ShowMessage(IntTostr(ComboBox1.ItemIndex));
end; 

On Windows and Linux ShowMessage will display 1, which is correct. On carbon you will see 0. If you start a timer on ComboChange, and after 500 ms. display the ItemIndex again, the result will be 1. At least that was the situation a few years ago, I did not test it with the most recent version of lazarus.
« Last Edit: February 07, 2015, 06:16:19 pm by GetMem »

Bart

  • Hero Member
  • *****
  • Posts: 5563
    • Bart en Mariska's Webstek
Re: TComboBox and OnChange event
« Reply #4 on: February 07, 2015, 06:15:48 pm »
Setting ItemIndex by code should not lead to the OnChange event being fired.
(It does not in Delphi and it does not in Lazarus on Windows).

Please test with trunk and if the issue is still present then file a bugreport.
Make sure to attach a minimal testcase (sources only) demonstrating the issue.

Bart

VTwin

  • Hero Member
  • *****
  • Posts: 1227
  • Former Turbo Pascal 3 user
Re: TComboBox and OnChange event
« Reply #5 on: February 07, 2015, 06:19:34 pm »
Thanks,

Must be a Carbon issue. This works:

Code: [Select]
...
  fSetting := true;
  cbx.SetInt(1);
  ...

procedure TDlg.cbxChange(Sender: TObject);
begin
  if fSetting then exit;
  ...
end;

procedure TGradientDlg.FormPaint(Sender: TObject);
begin
  fSetting := false;
end;

I guess I'll bracket it with IFDEFS for now and file a bug report.

VTwin
“Talk is cheap. Show me the code.” -Linus Torvalds

Free Pascal Compiler 3.2.2
macOS 15.3.2: Lazarus 3.8 (64 bit Cocoa M1)
Ubuntu 18.04.3: Lazarus 3.8 (64 bit on VBox)
Windows 7 Pro SP1: Lazarus 3.8 (64 bit on VBox)

VTwin

  • Hero Member
  • *****
  • Posts: 1227
  • Former Turbo Pascal 3 user
Re: TComboBox and OnChange event
« Reply #6 on: February 07, 2015, 06:50:12 pm »
Bug report filed.
“Talk is cheap. Show me the code.” -Linus Torvalds

Free Pascal Compiler 3.2.2
macOS 15.3.2: Lazarus 3.8 (64 bit Cocoa M1)
Ubuntu 18.04.3: Lazarus 3.8 (64 bit on VBox)
Windows 7 Pro SP1: Lazarus 3.8 (64 bit on VBox)

VTwin

  • Hero Member
  • *****
  • Posts: 1227
  • Former Turbo Pascal 3 user
Re: TComboBox and OnChange event
« Reply #7 on: February 09, 2015, 06:08:31 pm »
Just to follow up, this caused me a lot of hours because of the side effects. The ComboBox event fires even if the Form is not visible. Anyway here is my workaround:

Code: [Select]
function TPrefsDlg.Disabled(page: integer): boolean;
begin
  {$IFDEF DARWIN}
  result := gDisabled or not Visible or (page <> PageControl1.PageIndex);
  {$ELSE}
  result := false;
  {$ENDIF}
end;

procedure TPrefsDlg.cbxDDataTypeChange(Sender: TObject);
begin
  if Disabled(gDataPage) then exit;
  DoDataTypeChange(cbxDDataType.Text);
end;
 

In my case the ComboBoxes are on hidden Page of a PageControl, and gDisabled is set in the Form Show and Hide handlers.

Cheers,
VTwin
« Last Edit: February 09, 2015, 06:18:02 pm by VTwin »
“Talk is cheap. Show me the code.” -Linus Torvalds

Free Pascal Compiler 3.2.2
macOS 15.3.2: Lazarus 3.8 (64 bit Cocoa M1)
Ubuntu 18.04.3: Lazarus 3.8 (64 bit on VBox)
Windows 7 Pro SP1: Lazarus 3.8 (64 bit on VBox)

 

TinyPortal © 2005-2018