Recent

Author Topic: Possible Bug  (Read 501 times)

egsuh

  • Full Member
  • ***
  • Posts: 241
Possible Bug
« on: September 19, 2019, 06:26:49 am »
I think this may be a bug.  In the file attached, there is a form which has two TEdit fields and three Buttons.

If Button3 is pressed, the two TEdit fiels must be filled with random numbers.

Please put cursor within the Edit2, and press Button3. It will do ShowMessage, but two edit fields are not filled with random numbers.

Now, comment out the Showmessage command, put cursor within the Edit2, and press Button3. Then the two edit fields will be filled with random numbers.

I found this while checking the calls to EditingDone event. This event is called when the focus moves away from the control (Edit2 in this case). But when the control is within a frame, not form, this is not called reliably. I'll test this again.


Code: Pascal  [Select]
  1. unit fcontrollink;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, ExtCtrls;
  9.  
  10. type
  11.   TMyClass = class
  12.   public
  13.      Field1,
  14.      Field2 : string;
  15.   end;
  16.  
  17.   { TForm1 }
  18.  
  19.   TForm1 = class(TForm)
  20.     Button1: TButton;
  21.     Button2: TButton;
  22.     Button3: TButton;
  23.     Edit1: TEdit;
  24.     Edit2: TEdit;
  25.     Memo1: TMemo;
  26.     Panel1: TPanel;
  27.     procedure Button1Click(Sender: TObject);
  28.     procedure Button2Click(Sender: TObject);
  29.     procedure Button3Click(Sender: TObject);
  30.     procedure Edit1EditingDone(Sender: TObject);
  31.     procedure Edit2EditingDone(Sender: TObject);
  32.     procedure FormCreate(Sender: TObject);
  33.     procedure FormDestroy(Sender: TObject);
  34.   private
  35.      FMyClass : TMyClass;
  36.  
  37.      function getF1: string;
  38.      function getF2: string;
  39.      procedure setF1(s: string);
  40.      procedure setF2(s: string);
  41.      procedure setMyClass(mc: TMyClass);
  42.  
  43.   public
  44.      property MyClass: TMyClass read FMyClass write setMyClass;
  45.      property F1: string read getF1 write setF1;
  46.      property F2: string read getF2 write setF2;
  47.   end;
  48.  
  49. var
  50.   Form1: TForm1;
  51.  
  52. implementation
  53.  
  54. {$R *.lfm}
  55.  
  56. { TForm1 }
  57.  
  58. procedure TForm1.Button1Click(Sender: TObject);
  59. begin
  60. end;
  61.  
  62. procedure TForm1.Button2Click(Sender: TObject);
  63. begin
  64.    if MyClass <> nil then with memo1.lines do
  65.    begin
  66.       Add('Field1 is ' + MyClass.Field1) ;
  67.       Add('Field2 is ' + MyClass.Field2) ;
  68.    end;
  69. end;
  70.  
  71. procedure TForm1.Edit1EditingDone(Sender: TObject);
  72. begin
  73.    F1 := trim(Edit1.Text);
  74. end;
  75.  
  76. procedure TForm1.Edit2EditingDone(Sender: TObject);
  77. begin
  78.    F2 := trim(Edit2.Text);
  79.    ShowMessage('edit2editingdone called');  // comment out this and press Button3.
  80. end;
  81.  
  82. procedure TForm1.Button3Click(Sender: TObject);
  83. begin
  84.    Randomize;
  85.    F1 := IntToStr(Trunc(Random(1000000)));
  86.    F2 := IntToStr(Trunc(Random(1000000)));
  87. end;
  88.  
  89.  
  90. procedure TForm1.FormCreate(Sender: TObject);
  91. var
  92.    anmc : TMyClass;
  93. begin
  94.    anmc := TMyClass.Create;
  95.  
  96.    anmc.Field1 := 'string field 1';
  97.    anmc.Field2 := 'string field 2';
  98.  
  99.    MyClass := anmc;
  100. end;
  101.  
  102. procedure TForm1.FormDestroy(Sender: TObject);
  103. begin
  104.   MyClass.Free;
  105. end;
  106.  
  107. function TForm1.getF1: string;
  108. begin
  109.    if FMyClass <> nil then Result := FMyClass.Field1 else Result := '';
  110. end;
  111.  
  112. function TForm1.getF2: string;
  113. begin
  114.    if FMyClass <> nil then Result := FMyClass.Field2 else Result := '';
  115. end;
  116.  
  117. procedure TForm1.setF1(s: string);
  118. begin
  119.    if MyClass <> nil then MyClass.Field1:= s;
  120.    Edit1.Text := s;
  121. end;
  122.  
  123. procedure TForm1.setF2(s: string);
  124. begin
  125.    if MyClass <> nil then MyClass.Field2:=  s;
  126.    Edit2.Text := s;
  127. end;
  128.  
  129. procedure TForm1.setMyClass(mc: TMyClass);
  130. begin
  131.    if mc <> nil then begin
  132.      FMyClass := mc;
  133.      Edit1.Enabled := True;
  134.      Edit2.Enabled := True;
  135.      Edit1.Text := FMyClass.Field1;
  136.      Edit2.Text := FMyClass.Field2;
  137.    end
  138.    else begin
  139.       Edit1.Enabled := False;
  140.       Edit2.Enabled := False;
  141.    end;
  142. end;
  143.  
  144. end.
  145.  

Thaddy

  • Hero Member
  • *****
  • Posts: 9193
Re: Possible Bug
« Reply #1 on: September 19, 2019, 07:03:04 am »
Code: Pascal  [Select]
  1.    F1 := IntToStr(Trunc(Random(1000000)));
  2.    F2 := IntToStr(Trunc(Random(1000000)));
Why trunc on an integer value? That makes no sense at all...
(Not the cause, but one of the things that are wrong with your code)

What is really wrong is that TMyClass is declared as class and never instantiated. Did you mean record ?
Try that and report back...
« Last Edit: September 19, 2019, 07:07:21 am by Thaddy »
also related to equus asinus.

egsuh

  • Full Member
  • ***
  • Posts: 241
Re: Possible Bug
« Reply #2 on: September 19, 2019, 07:15:38 am »
Sorry. Trunc is not necessary here.  Random returns number between 0 and 1, so I was confused.

TMyClass is instantiated at the FormCreate. 
 MyClass := anmc;  does it.  I did not call FMyClass := TMyClass.Create;  because I wanted to  call setMyClass.

Thaddy

  • Hero Member
  • *****
  • Posts: 9193
Re: Possible Bug
« Reply #3 on: September 19, 2019, 08:48:04 am »
MyClass := anmc;  does it.  I did not call FMyClass := TMyClass.Create;  because I wanted to  call setMyClass.
I told you so. Listening is an art.
also related to equus asinus.

PascalDragon

  • Hero Member
  • *****
  • Posts: 674
  • Compiler Developer
Re: Possible Bug
« Reply #4 on: September 19, 2019, 09:05:48 am »
Code: Pascal  [Select]
  1. procedure TForm1.Button3Click(Sender: TObject);
  2. begin
  3.    Randomize;
  4.    F1 := IntToStr(Trunc(Random(1000000)));
  5.    F2 := IntToStr(Trunc(Random(1000000)));
  6. end;
Aside from that you already found the solution: you should call Randomize only once at program start and not every time you press a button.

egsuh

  • Full Member
  • ***
  • Posts: 241
Re: Possible Bug
« Reply #5 on: September 19, 2019, 09:21:43 am »
Quote
I told you so. Listening is an art.

What do you mean by this?  I instantiated TMyClass.

Code: Pascal  [Select]
  1. anmc := TMyClass.Create;
  2. .....
  3. MyClass := anmc;
  4.  


Quote
you should call Randomize only once at program start and not every time you press a button.
That's not the point.

Bart

  • Hero Member
  • *****
  • Posts: 3541
    • Bart en Mariska's Webstek
Re: Possible Bug
« Reply #6 on: September 19, 2019, 10:03:40 am »
In the scenario described I see TForm1.Edit2EditingDone being executed allways, however if the ShowMessage is called in TForm1.Edit2EditingDone then TForm1.Button3Click is not called when you click on Button3.

Bart

Thaddy

  • Hero Member
  • *****
  • Posts: 9193
Re: Possible Bug
« Reply #7 on: September 19, 2019, 10:11:22 am »
That's not the point.
Well, look again. Bart pointed you to the same issue.
also related to equus asinus.

egsuh

  • Full Member
  • ***
  • Posts: 241
Re: Possible Bug
« Reply #8 on: September 19, 2019, 10:22:51 am »
Quote
ShowMessage is called in TForm1.Edit2EditingDone then TForm1.Button3Click is not called when you click on Button3.

Yes. That's my point.

When I press Button3, Edit2EditingDone should be executed because the focus leaves Edit2, and it must be followed by execution of Button3Click.

But why ShowMessage blocks the execution of Button3Click?

If Showmessage is not called within Edit2EditingDone, Button3Click is executed.   Randomizing again is irrelevant here. 

Bart

  • Hero Member
  • *****
  • Posts: 3541
    • Bart en Mariska's Webstek
Re: Possible Bug
« Reply #9 on: September 19, 2019, 10:17:16 pm »
The behaviour is the same as in Delphi (7).
If I put a ShowMessage inside an OnExit event, then the OnClickEvent of the button is not fired.
In fact this happens if you show a modal form in the OnExit handler.

It seems that showing a modal form  blockt/clears the event queue.

Bart

egsuh

  • Full Member
  • ***
  • Posts: 241
Re: Possible Bug
« Reply #10 on: September 20, 2019, 05:49:56 am »
@Bart

Yes, you are right. I tested it with Delphi DX 10.1 Berlin.  (Why do I not use Delphi? This is free starter version^^).

But this behavior is related with TButton. I tested with following codes.

Code: Pascal  [Select]
  1. procedure TForm1.Edit1Exit(Sender: TObject);
  2. begin
  3.    ShowMessage(Edit1.Text);
  4. end;
  5.  
  6. procedure TForm1.Button2Click(Sender: TObject);
  7. begin
  8.    Edit1.Text := 'Text from button 2';
  9. end;
  10.  
  11. procedure TForm1.Edit2Enter(Sender: TObject);
  12. begin
  13.    Edit1.Text := Edit2.Text;
  14. end;
  15.  
  16. procedure TForm1.TreeView1Change(Sender: TObject; Node: TTreeNode);
  17. begin
  18.   Edit1.Text := node.text;
  19. end;
  20.  
  21. procedure TForm1.ListView1SelectItem(Sender: TObject; Item: TListItem;
  22.   Selected: Boolean);
  23. begin
  24.   if Selected then Edit1.Text := item.Caption;
  25. end;
  26.  

Followings occur when I press each control while Edit1 is focused. 

1.  When I press Button2,  Edit1.Text is showmessaged, and when I close, there are no change in the Edit1.  And if I press Button2 again, the content of Edit1 is changed (this is very natural becuase Edit1Exit is not called).

2.  When I enter Edit2, everything goes as expected.

3.  When I select any tree node, everything goes as expected.

4.  When I select any listview item, Edit1.Text is modified first, and then the modified message is shown (i.e.  selected node.text).   But, in Delphi, everything goes as expected here too.


My conclusions are :

1.  TButton's behavior is a bug both in Delphi and Lazarus.
2.  The order in which  events occur when a listview item is selected in Lazarus is wrong. This is a bug (or many bugs).  There is a logical order of events happening. In our case, the focus must 1) move away from TEdit,  2) Enter TListView, and then 3) listview item is selected. A person cannot enter a new room before leaving current room.

3.  Aside from that,  TTreeview should use treenode about to lose focus (or selection) as parameter of  OnChanging event handler.