This is my problem:
I am migrating a Delphi application to Lazarus. The application has a TreeView with a tree of product categories. Each time the user selects a category, (in the OnChange event) my application connects to the server via HTTP and downloads the product records from that category to show them in a ListView. Because internet connections can be slow, I disable the TreeView before the application will do the actual HTTP POST to the server and enable it after it is finished with the server response.
However, now (in Lazarus) when the user selects a category the OnChange event triggers (as expected), it send the POST and then the next time the user tries to select another category the OnChange event is not triggered. After some wolf fencing I found the problem was the IdHTTP.Post call, but only if IdAntiFreeze is active and if the TreeView is disabled and enabled.
I created a minimal test application with a TreeView (which do the HTTP POST in the OnChange handler), a Memo (to display some TreeView events), an edit field (to set a test URL), a button to add nodes to the TreeView, a button to clear the Memo and a checkbox to enable/disable the AntiFreeze. I attached a screenshot marking with colors the events from three clicks.
What I see is that if AntiFreeze is disabled, the TreeView event handlers are triggered as OnChanging, OnSelectionChanged, OnChange and OnClick.
But if AntiFreeze is enabled, the TreeView event handlers are called as OnChanging, OnSelectionChanged and OnChange, and the next time the user selects another node only the OnClick handler is called, and the next time only the first three.
So, the conditions for this to happen are: the OnChange event disables the TreeView control, it does a POST and AntiFreeze is active. If the TreeView is not disabled and enabled, or if it does a HTTP GET (not a POST) or if AntiFreeze is disabled, this does not happen.
So far in my application the only workaround is to disable the AntiFreeze or not to enable/disable the TreeView and use a global flag to ignore the user selection if a POST request is already running. Maybe if I disable the AntiFreeze then disabling/enabling the TreeView won't be necessary. Or maybe I should use the running flag plus a TAction (I really should explore those).
Why is this happening? Is a problem with the threading of the AntiFreeze? With TTreeView? With the GTK2 control? With my application?
My minimal test app is:
unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs,
StdCtrls, ExtCtrls, ComCtrls, IdHTTP, IdAntiFreezeBase, IdAntiFreeze;
type
{ TForm1 }
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
CheckBox1: TCheckBox;
Edit1: TEdit;
Memo1: TMemo;
TreeView1: TTreeView;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure CheckBox1Change(Sender: TObject);
procedure TreeView1Change(Sender: TObject; Node: TTreeNode);
procedure TreeView1Changing(Sender: TObject; Node: TTreeNode;
var AllowChange: Boolean);
procedure TreeView1Click(Sender: TObject);
procedure TreeView1SelectionChanged(Sender: TObject);
private
{ private declarations }
public
{ public declarations }
end;
var
Form1: TForm1;
HTTPClient: TIdHTTP;
Antifreeze : TIdAntiFreeze;
implementation
uses lconvencoding, IdMultipartFormData;
{ TForm1 }
procedure TForm1.Button2Click(Sender: TObject);
begin
Memo1.Lines.Clear;
end;
procedure TForm1.CheckBox1Change(Sender: TObject);
begin
Antifreeze.Active := CheckBox1.Checked;
end;
procedure TForm1.TreeView1Change(Sender: TObject; Node: TTreeNode);
var
PostData : TIdMultiPartFormDataStream;
Response : string;
begin
TreeView1.Enabled:=FALSE;
Memo1.Lines.Append('CHANGE');
Memo1.Lines.Append('**************************');
PostData := TIdMultiPartFormDataStream.Create;
PostData.AddFormField ('Test', 'Test');
TRY
TRY
Response := HTTPClient.Post (Edit1.Text, PostData);
EXCEPT
Response := '';
END;
FINALLY
PostData.Free;
END;
TreeView1.Enabled:=TRUE;
Form1.FocusControl(TreeView1);
end;
procedure TForm1.TreeView1Changing(Sender: TObject; Node: TTreeNode;
var AllowChange: Boolean);
begin
Memo1.Lines.Append('CHANGING');
end;
procedure TForm1.TreeView1Click(Sender: TObject);
begin
Memo1.Lines.Append('CLICK');
end;
procedure TForm1.TreeView1SelectionChanged(Sender: TObject);
begin
Memo1.Lines.Append('SELECTIONCHANGED');
end;
procedure TForm1.Button1Click(Sender: TObject);
var Node : TTreeNode;
begin
TreeView1.Items.Add (NIL,'test1');
end;
initialization
{$I unit1.lrs}
HTTPClient := TIdHTTP.Create (Application);
Antifreeze := TIdAntiFreeze.Create (Application);
Antifreeze.Active := FALSE;
end.
BTW, I am using Lazarus 0.9.28.2-8ubuntu1 r22277 FPC 2.4.0 x86_64-linux-gtk 2 (beta) (in Ubuntu 10.04, 64-bits).
Any ideas, comments or suggestions are welcome.
Regards,
MV