[SOLVED] Event TComboBox.OnEditingDone fires to often (Focus problem?) lazarus / 31-LCL ---------------------------------------------------------------------- Hartmut · 2018-07-14 10:38 I have 2 problems, that event TComboBox.OnEditingDone is fired to often: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit Unit1; {$mode objfpc}{$H+}{$apptype console} {neccessary for writeln} interface uses Classes, SysUtils, Forms, Controls, Dialogs, StdCtrls, ComCtrls; type TForm1 = class(TForm)  Button1: TButton;  Button2: TButton;  ComboBox1: TComboBox;  ListBox1: TListBox;  PageControl1: TPageControl;  TabSheet1: TTabSheet;  TabSheet2: TTabSheet;  procedure ComboBox1EditingDone(Sender: TObject);  procedure FormActivate(Sender: TObject); private public end; var Form1: TForm1; implementation {$R *.lfm} procedure ComboBox_add_History(var X: TComboBox; max: integer);   {adds the current value of the ComboBox to the history}   var s: ansistring;     i: integer;   begin   s:=X.Text;             {get aktuellen Wert der ComboBox}   if s='' then exit;    i:=X.Items.IndexOf(s); {sucht 's' in der History, not found => -1}   if i = 0 then exit;    {wenn schon als jüngstes vorhanden}    if i > 0 then          {wenn schon vorhanden, aber nicht als jüngstes: }      begin      X.Items.Delete(i);  {delete current item}      X.Text:=s;          {muß nach Delete() wiederholt werden}      end;    while X.Items.Count >= max do {lösche ggf. ältere Einträge: }      begin      i:=X.Items.Count-1; {oldest item}      X.Items.Delete(i);  {delete oldest item}      end;    X.Items.Insert(0,s);   {neues item am Anfang einfügen}   end; procedure TForm1.ComboBox1EditingDone(Sender: TObject);   const nr: integer = 1;   begin   writeln('OnEditingDone', nr);   inc(nr);   ComboBox_add_History(ComboBox1,12);   ListBox1.SetFocus; // get the focus away from ComboBox1 (does not help)   end; procedure TForm1.FormActivate(Sender: TObject);   begin   ListBox1.SetFocus; // get the focus away from ComboBox1 (does not help)   end; end. Problem #1: a) compile and start the attached project b) click on TabSheet2 c) click on Button 2 d) click on TabSheet1 (result: ComboBox1 becomes blue) e) click on Button 1 Result: event TComboBox.OnEditingDone is fired, although this component was NOT "edited". Looks for me like a focus problem, that the ComboBox became blue in d) and was "quit" in e) Is that correct? To avoid this I used ListBox1 to place the focus there (lines 64 and 69), but this did not help and evoked problem #2. Problem #2:  - compile and start the attached project  - enter something via keybord in ComboBox1 and press ENTER Result: event TComboBox.OnEditingDone is fired twice, although this component was "edited" only once. Why does this happen? I would like to understand this behavior, if possible. What I want is ONE event in case of a) the ComboBox has got another content or b) the same content as last time is selected a 2nd time via Mouse or ENTER. How can this be done? I use Lazarus 1.8.4 on Windows 7 32 bit. Thanks a lot in advance. [EDIT] There is a summary about this Topic in reply #24. ---------------------------------------------------------------------- Handoko · 2018-07-14 11:03 For problem #1: I cannot reproduce what you said. Or maybe I didn't fully understand what you meant. For problem #2: Yes, I get ComboBox1EditingDone fired twice. But your code has problem. Simply remove ListBox1.SetFocus; solve the issue. In the code below, the event only fired once because I use Exit to skip the LisBox1.SetFocus: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.ComboBox1EditingDone(Sender: TObject);   const nr: integer = 1;   begin   writeln('OnEditingDone', nr);   inc(nr);   ComboBox_add_History(ComboBox1,12);   Exit;   ListBox1.SetFocus; // get the focus away from ComboBox1 (does not help)   end; So, I will say it is your fault that cause OnEditingDone to fired 2x. You should not 'steal' focus inside the OnEditingDone event. Tested on Lazarus 1.8.4 Ubuntu 18.04. ---------------------------------------------------------------------- Hartmut · 2018-07-14 11:42 Thank you Handoko for your help. Quote from: Handoko on July 14, 2018, 01:03:27 pmFor problem #1: I cannot reproduce what you said. Or maybe I didn't fully understand what you meant. At which point you cannot follow / what is difficult to understand? Can you click from b) to e) ? Do you get ComboBox1 marked blue in d) ? Is the event fired after e) ? Is it possible that this problem occurs only under Windows? For problem #2: I learned that I may not 'steal' the focus inside an OnEditingDone event. But how can I move the focus away from the ComboBox? When I press ENTER in the ComboBox, the focus "stays" there and comes back in d) After gettinng a (new) value from the ComboBox, I want to show something in the ListBox and want to place the focus there, so that you e.g. can scroll in the ListBox with the arrow keys. How can this be done? ---------------------------------------------------------------------- Handoko · 2018-07-14 12:02 Quote from: Hartmut on July 14, 2018, 01:42:12 pmAt which point you cannot follow / what is difficult to understand? Can you click from b) to e) ? Do you get ComboBox1 marked blue in d) ? Is the event fired after e) ? Is it possible that this problem occurs only under Windows? I don't know. I use Linux and I tested your code on Gtk2 widgetset. As you can see on the image below, nothing is blue. ---------------------------------------------------------------------- Handoko · 2018-07-14 12:12 Quote from: Hartmut on July 14, 2018, 01:42:12 pm... But how can I move the focus away from the ComboBox? When I press ENTER in the ComboBox, the focus "stays" there and comes back in d) After gettinng a (new) value from the ComboBox, I want to show something in the ListBox and want to place the focus there ... Maybe this is what you want: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit Unit1; {$mode objfpc}{$H+}{$apptype console} {neccessary for writeln} interface uses Classes, SysUtils, Forms, Controls, Dialogs, StdCtrls, ComCtrls, ExtCtrls; type  { TForm1 }  TForm1 = class(TForm)  Button1: TButton;  Button2: TButton;  ComboBox1: TComboBox;  ListBox1: TListBox;  PageControl1: TPageControl;  TabSheet1: TTabSheet;  TabSheet2: TTabSheet;  Timer1: TTimer;  procedure ComboBox1EditingDone(Sender: TObject);  procedure FormActivate(Sender: TObject);  procedure Timer1Timer(Sender: TObject); private public end; var Form1: TForm1; implementation {$R *.lfm} procedure ComboBox_add_History(var X: TComboBox; max: integer);   {adds the current value of the ComboBox to the history}   var s: ansistring;       i: integer;   begin   s:=X.Text;           {get aktuellen Wert der ComboBox}   if s='' then exit;    i:=X.Items.IndexOf(s); {sucht 's' in der History, not found => -1}   if i = 0 then exit;    {wenn schon als jüngstes vorhanden}    if i > 0 then          {wenn schon vorhanden, aber nicht als jüngstes: }    begin      X.Items.Delete(i);  {delete current item}      X.Text:=s;        {muß nach Delete() wiederholt werden}      end;    while X.Items.Count >= max do {lösche ggf. ältere Einträge: }      begin    i:=X.Items.Count-1; {oldest item}      X.Items.Delete(i);  {delete oldest item}      end;    X.Items.Insert(0,s);   {neues item am Anfang einfügen}   end; procedure TForm1.ComboBox1EditingDone(Sender: TObject);   const nr: integer = 1;   begin   writeln('OnEditingDone', nr);   inc(nr);   ComboBox_add_History(ComboBox1,12);   Timer1.Enabled := True;   Exit;   ListBox1.SetFocus; // get the focus away from ComboBox1 (does not help)   end; procedure TForm1.FormActivate(Sender: TObject);   begin   Timer1.Interval := 100;   Timer1.Enabled := False;   ListBox1.SetFocus; // get the focus away from ComboBox1 (does not help)   end; procedure TForm1.Timer1Timer(Sender: TObject);begin  ListBox1.SetFocus;  Timer1.Enabled := False;end; end. If I want to 'force' something to always on focus I usually use a Timer. Maybe it is not the best solution but it works. See line #69, #76, #77, #83, #84. ---------------------------------------------------------------------- Hartmut · 2018-07-14 12:55 Quote from: Handoko on July 14, 2018, 02:02:37 pmI use Linux and I tested your code on Gtk2 widgetset. As you can see on the image below, nothing is blue. Seems that in your screenshot the Combobox is "selected" and green (this could be the equivalent to 'blue' on Windows). I guess that if you press a letter key in this situation, it is inserted in the Combobox. If this screenshot is from d) I don't understand, why Combobox is "selected" after clicking on 'TabSheet1'. Don't you get event TComboBox.OnEditingDone fired when you then click on Button 1? This would be a difference between Windows and Linux and maybe could be a bug? ---------------------------------------------------------------------- Hartmut · 2018-07-14 12:56 Quote from: Handoko on July 14, 2018, 02:12:05 pmIf I want to 'force' something to always on focus I usually use a Timer. Thank you very much for that suggestion. It tried it and it solves problem #2 in this demo, but in real live I show data from an sql DB in ListBox1. To read this data can need 10 ms or a couple of seconds. So I would not know how long to set the timer... ---------------------------------------------------------------------- wp · 2018-07-14 13:54 Quote from: Hartmut on July 14, 2018, 12:38:46 pmProblem #1: a) compile and start the attached project b) click on TabSheet2 c) click on Button 2 d) click on TabSheet1 (result: ComboBox1 becomes blue) e) click on Button 1 Result: event TComboBox.OnEditingDone is fired, although this component was NOT "edited". After step d) the Combobox1 is blue, this means that it is in edit mode. When you click on Button1 in step e) the focus moves away from the Combobox, and this terminates the edit mode. The behavior is absolutely correct because edit mode is done - even if nothing was changed. If you want to prevent firing OnEditingDone in this case you must store the value of the combobox before editing starts and exit the OnEditingDone event if the current value is not changed: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i  TForm1 = class(TForm)  ...  private    FOldComboValue: String;  end; procedure TForm1.ComboBox1EditingDone(Sender: TObject);   const nr: integer = 1;begin   if FOldComboValue = Combobox1.Text then exit; // <---- NEW   writeln('OnEditingDone', nr);   inc(nr);   ComboBox_add_History(ComboBox1,12);   ListBox1.SetFocus; // get the focus away from ComboBox1 (does not help)end; procedure TForm1.ComboBox1Enter(Sender: TObject);   // <--- NEWbegin  FOldComboValue := Combobox1.Text;end; ---------------------------------------------------------------------- Handoko · 2018-07-14 14:04 @wp: On Linux Gtk2, it behaves differently. Now matter how often I switched tabs and clicked the buttons, the ComboBox will never automatically get focus nor OnEditingDone event fired. Tested on Linux Gtk2 and WinXP. @Hartmut: I've just found myself a Windows computer to test what you meant in problem 1. I finally understand what you meant now, I can reproduce it. I believe it is a bug because it does not behave like that on Linux Gtk2. Maybe you should submit a bug report on the bugtracker forum: https://bugs.freepascal.org I now testing the code to see if I can find any workaround for it. Quote from: Hartmut link=topic=41882.msg291589#msg291589 It tried it and it solves problem #2 in this demo, but in real live I show data from an sql DB in ListBox1. To read this data can need 10 ms or a couple of seconds. So I would not know how long to set the timer... I use that trick often and so far never have any problem. Although I never use it on database program, but I believe the Interval := 100 should work without any issue too. ---------------------------------------------------------------------- Hartmut · 2018-07-14 14:23 Quote from: wp on July 14, 2018, 03:54:06 pmAfter step d) the Combobox1 is blue, this means that it is in edit mode. When you click on Button1 in step e) the focus moves away from the Combobox, and this terminates the edit mode. The behavior is absolutely correct because edit mode is done - even if nothing was changed. Thank you very much for that explanation. Now I understand the 2nd half of problem #1. What I still not understand is, why Combobox1 gets into edit mode by clicking on TabSheet1 (instead of clicking in the ComboBox). Can this be avoided? QuoteIf you want to prevent firing OnEditingDone in this case you must store the value of the combobox before editing starts and exit the OnEditingDone event if the current value is not changed: Thank you too for this suggestion. But it only works, if the value in the ComboBox is changed. I need that event too, if the same content as last time is selected a 2nd time via Mouse or ENTER. Can this be done? ---------------------------------------------------------------------- Hartmut · 2018-07-14 14:35 Quote from: Handoko on July 14, 2018, 04:04:30 pmOn Linux Gtk2, it behaves differently. Now matter how often I switched tabs and clicked the buttons, the ComboBox will never automatically get focus nor OnEditingDone event fired. Tested on Linux Gtk2 and WinXP. Thanks a lot for testing and reporting this. QuoteI believe it is a bug because it does not behave like that on Linux Gtk2. Maybe you should submit a bug report on the bugtracker forum I will wait if wp disagrees and if not I will submit a bug report. QuoteI now testing the code to see if I can find any workaround for it. This is very friendly of you! QuoteI use that trick often and so far never have any problem. Although I never use it on database program, but I believe the Interval := 100 should work without any issue too. I will try it in my real program. ---------------------------------------------------------------------- wp · 2018-07-14 16:25 Quote from: Hartmut on July 14, 2018, 04:23:48 pmQuoteIf you want to prevent firing OnEditingDone in this case you must store the value of the combobox before editing starts and exit the OnEditingDone event if the current value is not changed: Thank you too for this suggestion. But it only works, if the value in the ComboBox is changed. I need that event too, if the same content as last time is selected a 2nd time via Mouse or ENTER. Can this be done? Now you lost me. Do you want the second OnEditingDone event or not? Or do you want to distinguish between the two cases: (1) EditingDone because of focusing another control, or (2) EditingDone because ENTER was pressed? If your code really depends so much on multiple occurance of events you should evaluate whether you are going the correct way. What exactly do you want to achieve? ---------------------------------------------------------------------- Handoko · 2018-07-14 17:06 After some testings on both Linux and WinXP, I found TComboBox behaves very differently on those widgetsets. The ComboBox will automatically receive focus when switching tab. It won't happen if you just switch the tab. But the ComboBox will be receive focus after you clicked the button inside the tab and then switch to the other tab. Sound very weird, isn't it? Such behavior does not happen on Linux. To prevent this 'weird' behavior on Windows, this is my workaround: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit Unit1; {$mode objfpc}{$H+}{$apptype console} {neccessary for writeln} interface uses Classes, SysUtils, Forms, Controls, Dialogs, StdCtrls, ComCtrls; type  { TForm1 }  TForm1 = class(TForm)  Button1: TButton;  Button2: TButton;  ComboBox1: TComboBox;  ListBox1: TListBox;  PageControl1: TPageControl;  TabSheet1: TTabSheet;  TabSheet2: TTabSheet;  procedure ComboBox1EditingDone(Sender: TObject);  procedure ComboBox1KeyPress(Sender: TObject; var Key: char);  procedure FormActivate(Sender: TObject);  procedure PageControl1Change(Sender: TObject); private public end; var Form1: TForm1;    SkipEvent: Boolean = False; implementation {$R *.lfm} procedure ComboBox_add_History(var X: TComboBox; max: integer);   {adds the current value of the ComboBox to the history}   var s: ansistring;       i: integer;   begin   s:=X.Text;           {get aktuellen Wert der ComboBox}   if s='' then exit;    i:=X.Items.IndexOf(s); {sucht 's' in der History, not found => -1}   if i = 0 then exit;    {wenn schon als jüngstes vorhanden}    if i > 0 then          {wenn schon vorhanden, aber nicht als jüngstes: }    begin      X.Items.Delete(i);  {delete current item}      X.Text:=s;        {muß nach Delete() wiederholt werden}      end;    while X.Items.Count >= max do {lösche ggf. ältere Einträge: }      begin    i:=X.Items.Count-1; {oldest item}      X.Items.Delete(i);  {delete oldest item}      end;    X.Items.Insert(0,s);   {neues item am Anfang einfügen}   end; procedure TForm1.ComboBox1EditingDone(Sender: TObject);   const nr: integer = 1;   begin   if (SkipEvent) then Exit;   writeln('OnEditingDone', nr);   inc(nr);   ComboBox_add_History(ComboBox1,12);   Exit;   ListBox1.SetFocus; // get the focus away from ComboBox1 (does not help)   end; procedure TForm1.ComboBox1KeyPress(Sender: TObject; var Key: char);beginend; procedure TForm1.FormActivate(Sender: TObject);   begin   ListBox1.SetFocus; // get the focus away from ComboBox1 (does not help)   end; procedure TForm1.PageControl1Change(Sender: TObject);begin  SkipEvent := True;  PageControl1.ActivePage.SetFocus;  SkipEvent := False;end; end. I use SkipEvent and PageControl.OnChange event to prevent the auto focus issue. See line #32, #67, #84. I personally think this is a bug. Switching tab in TPageControl should not cause the combobox to receive focus. Quote from: Hartmut on July 14, 2018, 04:23:48 pmWhat I still not understand is, why Combobox1 gets into edit mode by clicking on TabSheet1 (instead of clicking in the ComboBox). TComboBox.OnEditingDone event is fired if the combobox lost focus, this behavior is the same when running on Linux. On Linux: The TComboBox.OnEditingDone won't be fired when you switch focus from the combobox to a non-active tab. The event only be fired if you switch focus from the combobox to an active tab. On Windows (XP): The ComboBox.OnEditingDone always be fired when you switch forus from combobox to either an active or non-active tab. ---------------------------------------------------------------------- Hartmut · 2018-07-14 17:08 Quote from: wp on July 14, 2018, 06:25:29 pmDo you want the second OnEditingDone event or not? Or do you want to distinguish between the two cases: (1) EditingDone because of focusing another control, or (2) EditingDone because ENTER was pressed? No, I don't want do distinguish. Sorry, my English is not so good. I want to do the same actions if: A) someone enters a new value in the ComboBox (and presses Enter or leaves the ComboBox via TAB or selects another Control with the Mouse) or B) if someone selects something from the History of the ComboBox (with the Mouse or by arrow keys and Enter) or C) if the last content of the ComboBox is selected one more time (e.g. by opening the History via Mouse, but selecting the last value again via Mouse click or via Enter). In all those cases the same actions must be executed only once. No actions have to take place, if on a TabSheet is clicked like in d) in my 1st post. Hope this is more understandable. Thank you for your help. ---------------------------------------------------------------------- Hartmut · 2018-07-14 18:27 Quote from: Handoko on July 14, 2018, 07:06:15 pmTo prevent this 'weird' behavior on Windows, this is my workaround: ... I use SkipEvent and PageControl.OnChange event to prevent the auto focus issue. See line #32, #67, #84. This is a great solution. I implemented this in my real program and it works perfect. Problem #1 is solved. Thanks a lot! Problem #2 still exists in my real program, although I deleted the "ListBox1.SetFocus" commands. Now I can reproduce it: Take the attached project from my 1st post. Disable the 2 "ListBox1.SetFocus" commands like: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.ComboBox1EditingDone(Sender: TObject);   const nr: integer = 1;   begin   writeln('OnEditingDone', nr);   inc(nr);   ComboBox_add_History(ComboBox1,12);// ListBox1.SetFocus; // disabled   end; procedure TForm1.FormActivate(Sender: TObject);   begin// ListBox1.SetFocus; // disabled   end;            Then: 1) compile and start the program 2) enter e.g. 3 values into the ComboBox, so that the History contains 3 values 3) open the ComboBox History with the mouse 4) select a value with the arrow keys 5) press ENTER Result: event TComboBox.OnEditingDone is fired twice. For me this looks like a bug, what do others say? Quote from: Handoko on July 14, 2018, 07:06:15 pmI personally think this is a bug. Switching tab in TPageControl should not cause the combobox to receive focus. @wp: Do you also think that this is a bug? ---------------------------------------------------------------------- valdir.marcos · 2018-07-14 18:57 Quote from: Hartmut on July 14, 2018, 08:27:28 pmQuote from: Handoko on July 14, 2018, 07:06:15 pmI personally think this is a bug. Switching tab in TPageControl should not cause the combobox to receive focus.@wp: Do you also think that this is a bug?[Sorry for stealing Handoko's answer.] Yes, it's a bug. Changing TTabSheet in TPageControl should preserve focus inside TPageControl components. Focus would only get outside TPageControl if destine TTabSheet won't have any focusable component. Today, we have to force similar behavior: http://forum.lazarus.freepascal.org/index.php/topic,41874.html ---------------------------------------------------------------------- wp · 2018-07-14 19:03 Very strange: If you move the PageControl to the top of the TabOrder (TabOrder = 0) then changing tabs keeps the focus with the PageControl. The project in the attachment demonstrates the effect of changed TabOrder. ---------------------------------------------------------------------- Hartmut · 2018-07-14 20:14 Quote from: wp on July 14, 2018, 09:03:06 pmVery strange: If you move the PageControl to the top of the TabOrder (TabOrder = 0) then changing tabs keeps the focus with the PageControl. The project in the attachment demonstrates the effect of changed TabOrder. Ok, for me now it's clear that it is a bug, that the ComboBox receives the focus, when switching TabSheets in TPageControl, which occurs only on Windows, not on Linux Gtk2. I will write a bug report for this. What is with the other problem, that this event is fired twice, as I described in reply #14, steps 1..5? Quote1) compile and start the program 2) enter e.g. 3 values into the ComboBox, so that the History contains 3 values 3) open the ComboBox History with the mouse 4) select a value with the arrow keys 5) press ENTER Result: event TComboBox.OnEditingDone is fired twice. If others think, that this is a bug too, I would write 1 bug report for both problems. ---------------------------------------------------------------------- wp · 2018-07-14 20:20 Quote from: Hartmut on July 14, 2018, 10:14:45 pmWhat is with the other problem, that this event is fired twice, as I described in reply #14, steps 1..5? Isn't my demo just covering this case? ---------------------------------------------------------------------- Hartmut · 2018-07-14 20:42 Quote from: wp on July 14, 2018, 10:20:32 pmQuote from: Hartmut on July 14, 2018, 10:14:45 pmWhat is with the other problem, that this event is fired twice, as I described in reply #14, steps 1..5? Isn't my demo just covering this case? I think not, because your demo does not have a history for the combobox. I expanded your demo by an TComboBox.OnEditingDone event and the combobox with a history. See attached project. Quote1) compile and start the program 2) enter e.g. 3 values into the ComboBox, so that the History contains 3 values 3) open the ComboBox History with the mouse 4) select a value with the arrow keys 5) press ENTER Result: event TComboBox.OnEditingDone is fired twice, regardless which TabOrder is 0. ---------------------------------------------------------------------- wp · 2018-07-14 21:36 But this is a completely different story. It does not have to do anything with the PageControl, it is related to the Combobox alone. Look at attached demo which contains only a combobox (plus a memo for registering the OnEditingDone events and a radiogroup for easy changing the Style of the Combobox): It fires the OnEditingDone event twice too if an item is selected from the dropdown with the ENTER key. One OnEditingDone fires when the ENTER key is pressed - I did not yet find the code where this happens. But I think it sits deep inside the heart of the LCL - changing it will break everything... The other OnEditingDone is created in the combobox method CloseUp: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TCustomComboBox.CloseUp;begin  if [csLoading,csDestroying,csDesigning]*ComponentState<>[] then exit;  if (Style in [csSimple, csDropDown, csOwnerDrawEditableFixed, csOwnerDrawEditableVariable]) then    EditingDone;         // <--------- HERE!  if Assigned(FOnCloseUp) then FOnCloseUp(Self);  if FAutoSelect then   begin    SelectAll;    if (SelText = Text) then FAutoSelected := True;   end;//End if FAutoSelectend;From the code it can be seen that the Style csDropDownList does not fire the second onEditingDone which in fact is observed in the demo. This EditingDone cannot be removed because a selection of an item from the dropdown with mouse would not fire the event. So, I am a bit clueless here what to do... [EDIT] Why is it harmful for your code when then OnEditingDone event fires twice? ---------------------------------------------------------------------- Hartmut · 2018-07-15 10:48 Quote from: wp on July 14, 2018, 11:36:28 pmLook at attached demo which contains only a combobox (plus a memo for registering the OnEditingDone events and a radiogroup for easy changing the Style of the Combobox): It fires the OnEditingDone event twice too if an item is selected from the dropdown with the ENTER key. I tried this demo and learned something new about ComboBoxes. And now I understand, why the Event is fired twice. But I think, it's a bug, that 1 exit (via ENTER) fires an event twice. If the OnEditingDone-Event is already fired in procedure TCustomComboBox.CloseUp, then the 2nd event via ENTER in my opinion is a bug. @wp: do you agree? QuoteWhy is it harmful for your code when then OnEditingDone event fires twice? This event reads data from a SQL-DB, which can need some seconds. The demo of wp inspired me to a solution, which works well:  - set a flag in the TComboBox.OnEnter-Event  - excecute the actions in TComboBox.OnEditingDone-Event only, if the flag is set  - at the end of OnEditingDone-Event set the focus to another control, which forces the user to "enter" the ComboBox again, so that a new OnEnter-Event is fired Now the OnEditingDone-Event is always fired twice (because of 'stealing' the focus), but this is now harmless because of the flag. This is my code (project is attached): Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit Unit1; {$mode objfpc}{$H+}{$apptype console} {neccessary for writeln} interface uses Classes, SysUtils, Forms, Controls, Dialogs, StdCtrls, ComCtrls; type  TForm1 = class(TForm)  ComboBox1: TComboBox;  ListBox1: TListBox;  procedure ComboBox1Enter(Sender: TObject);  procedure ComboBox1EditingDone(Sender: TObject); private public end; var Form1: TForm1; implementation {$R *.lfm} const enable_event: boolean = true; procedure TForm1.ComboBox1Enter(Sender: TObject);   begin   writeln('OnEnter');   enable_event:=true; // enable the EditingDone-Event 1x   end; procedure TForm1.ComboBox1EditingDone(Sender: TObject);   const nr: integer = 1;   var ee: boolean;   begin   writeln('OnEditingDone', nr, ' enable=', enable_event);   inc(nr);    ee:=enable_event;    // memorize permission   enable_event:=false; // reset permission   if not ee then exit; // exit if no permission    ListBox1.SetFocus;   // steal the focus from the ComboBox   end; end. ---------------------------------------------------------------------- wp · 2018-07-15 11:16 Quote from: Hartmut on July 15, 2018, 12:48:27 pmBut I think, it's a bug, that 1 exit (via ENTER) fires an event twice. If the OnEditingDone-Event is already fired in procedure TCustomComboBox.CloseUp, then the 2nd event via ENTER in my opinion is a bug. @wp: do you agree?In principle, yes, and if you want you can report it to bugtracker, maybe somebody with good knowledge of the LCL picks it up and fixes it. I won't touch it myself because the OnEditingDone via ENTER originates from deep inside the LCL, the bug may even depend on the widgetset; therefore, I am rather sure that it may introduce a cascade of other bugs if not done correctly. It is much safer to fix - well, maybe, work around - the issue by using the flag that you propose. BTW: What do you think that no OnEditingDone event is created when the combobox style is csDropdownList and an item is picked from the dropdown using a mouse click? On the other hand, the event IS created when the item is selected with the ENTER key. Pretty much inconsistent in my eyes... What does "editing" mean in case a combobox with style csDropDownList? You cannot type anything in here, so no edit state? Then the ENTER key does not make sense either to fire OnEditingDone. But you still can SELECT an item from the combo. Is this editing? And suddenly things get complicated again... And the confusion with OnEditingDone is nothing compared to the OnClick and OnChange events of many LCL controls. The only thing you can be sure of that practically every controls behaves differently. Normally the OnClick fires when the user changes the control by a click, but sometimes also by code. OnChange, sometimes, duplicates OnClick, sometimes not. etc. But we are in good company: Delphi's VCL is not more consistant at all. ---------------------------------------------------------------------- Hartmut · 2018-07-15 12:41 Quote from: wp on July 15, 2018, 01:16:38 pmQuote from: Hartmut on July 15, 2018, 12:48:27 pmBut I think, it's a bug, that 1 exit (via ENTER) fires an event twice. If the OnEditingDone-Event is already fired in procedure TCustomComboBox.CloseUp, then the 2nd event via ENTER in my opinion is a bug. @wp: do you agree?In principle, yes, and if you want you can report it to bugtracker I will create a bug report. QuoteBTW: What do you think that no OnEditingDone event is created when the combobox style is csDropdownList and an item is picked from the dropdown using a mouse click? On the other hand, the event IS created when the item is selected with the ENTER key. Pretty much inconsistent in my eyes... I agree. Maybe the problem is, that Delphi was a template to the LCL and if the original is inconsistent, the copy is difficult to be better. For me (as an "advanced beginner" to the LCL) events are often difficult to handle. Normally I must do a lot of tries to find out, which event is the right one for my purpose and how to handle it. ---------------------------------------------------------------------- Hartmut · 2018-07-15 13:37 This is a summary about this Topic:  - 3 problems with event TComboBox.OnEditingDone firing to often have been discussed  - for every problem a solution was found  - 2 bugs were identified Problem #1 (introduced in the 1st post) was, that if you have a TPageControl with some TabSheets, that by clicking on the TabSheets the focus can be received wrongly by a TComboBox (if the ComboBox has TabOrder=0). If you then click on the next TabSheet, the focus leaves the ComboBox and event TComboBox.OnEditingDone is fired wrongly. This is a bug. I created a bug report (#33991). This bug is not on Linux with Gtk2. A solution came in reply #12 by setting a skip-event-variable in event PageControl1Change. Problem #2 (introduced in the 1st post) was, that event TComboBox.OnEditingDone was always fired twice. The reason was my fault, because I "stealed" the focus from inside the TComboBox.OnEditingDone event at it's end. Therefore the ComboBox was exited twice and the event was fired twice. A solution came in reply #4 by using a timer, if it is neccessary to switch the focus to another control. Another solution came in reply # 21 by using an event-enable-flag, which is set in the TComboBox.OnEnter event. Problem #3 (introduced in reply #14 as a variant of problem #2) was, that event TComboBox.OnEditingDone was fired twice, when you press ENTER in the ComboBox. wp found out in reply #20 why that is the case. This is a bug too. I created a bug report (#33992). A solution came in reply # 21 by using an event-enable-flag, which is set in the TComboBox.OnEnter event. Thanks a lot again to wp and Handoko for their valuable help! I'm happy that all 3 problems found a good solution. ---------------------------------------------------------------------- Ondrej Pokorny · 2018-07-16 05:12 Problem #1 - not a bug, this is "as designed" Problem #2 - not a bug, this is "as designed" Problem #3 - yes, a bug but IMO it's not worth to fix it --- I had the same idea recently - to fire OnEditingDone only if something changed and also refactor the OnEditingDone event in general (see r58337, r58339). Quickly I realized that it is not the way to go and I reverted my changes. I decided so by looking at how OnEditingDone is used in the IDE and the comments in the code about it. Another fact is that you cannot do this generally for every custom control. OnEditingDone is an event that is fired when "editing state" finished. It doesn't mean that something actually has changed. Therefore if you use OnEditingDone you always have to track the value you use from the control (from TEdit is't Text, but from a custom control it can be anything) and execute your action only if the value changed. If you do this (detect change) problem #3 isn't that bad. ---------------------------------------------------------------------- Ondrej Pokorny · 2018-07-16 05:25 Generally speaking OnEditingDone is a "helper" event without much priority that can be fired at various points (whenever the control decides) and doesn't guarantee that something actually changed. So it's not worth to pollute the LCL code with workarounds to fix issue #33992. The user himself is responsible for change detection in OnEditingDone. We should document the meaning of OnEditingDone better in http://lazarus- ccr.sourceforge.net/docs/lcl/controls/tcontrol.oneditingdone.html so that this confusion doesn't happen. ---------------------------------------------------------------------- Hartmut · 2018-07-16 09:54 Quote from: Ondrej Pokorny on July 16, 2018, 07:12:05 amOnEditingDone is an event that is fired when "editing state" finished. It doesn't mean that something actually has changed. Therefore if you use OnEditingDone you always have to track the value you use from the control ... and execute your action only if the value changed. If you do this (detect change) problem #3 isn't that bad. In my case I need the TComboBox.OnEditingDone event also, if nothing was changed. That means, that the same actions have to take place, if someone enters or selects the same value than before e.g. from the ComboBox-History. So this (detect change) is not a solution for my problem #3. But I have a good solution (see reply #21), so my problem #3 is solved. Quote from: Ondrej Pokorny on July 16, 2018, 07:25:08 amGenerally speaking OnEditingDone ... doesn't guarantee that something actually changed. So it's not worth to pollute the LCL code with workarounds to fix issue #33992. I understand that to fix issue #33992 is a difficult decision because of the risk to create new bugs. As wp wrote, this person must have very good knowledge of the LCL.