Forum > Networking and Web Programming

Indy IdAntiFreeze interfering with TreeView events...

(1/1)

mvaldez:
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:


--- Code: ---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.

--- End code ---


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

JuhaManninen:
Hi

You have made a test program reproducing the problem, so it is worth a bug report. You must make a package that includes the project file and also the form .lfm file. Your pascal code can't be run alone.

I recommend you test with latest Lazarus + LCL before reporting. It has many changes since 0.9.28.2. The bug itself sounds very strange. Is it a Indy bug or Treeview bug, don't know.

Juha

marcov:
As far as I know antifreeze always was a hack. If you can eliminate it, that would be a good thing anyway.

mvaldez:


Hi. Thanks both for answering.


juha:
--- Quote ---You have made a test program reproducing the problem, so it is worth a bug report. You must make a package that includes the project file and also the form .lfm file. Your pascal code can't be run alone. I recommend you test with latest Lazarus + LCL before reporting. It has many changes since 0.9.28.2. The bug itself sounds very strange. Is it a Indy bug or Treeview bug, don't know.

--- End quote ---

I'll do it. But first I want to check if I can reproduce it in another computer (with Linux) and in Windows. And I'll post the minimal test with all files with my bug report.

marcov:
--- Quote ---As far as I know antifreeze always was a hack. If you can eliminate it, that would be a good thing anyway.

--- End quote ---

I'm thinking on moving the IdHTTP to a thread but last time I wrote a very simple multi-threaded application (using Indy and critical sections) I had a hard time debugging. So maybe I'll try that as my last option.


Regards and thanks for your comments,

MV

mvaldez:


Hi. I have tested with Lazarus in Windows (Windows XP, 32-bits, win32 widget and gtk2 widget) and something similar happens. With Win32 witget, I still get the OnChanging, OnSelectionChanged and OnChange events but the OnClick events are not received if AntiFreeze is enabled and the control is disabled in the OnChange handler. With GTK2 in Windows it happens exactly as in Linux, the first time I get all events except OnClick, next time only OnClick, then again all except OnClick and so on.

Then I tested in Delphi (Turbo Delphi Explorer, in Windows XP, with Indy 9 not Indy 10) and it behaves just like Lazarus with Win32 widget; if AntiFreeze is enabled and the controls is disabled in the OnChange handler then the OnClick event is never triggered.

I'm guessing, but if the control is being disabled before the OnClick is triggered maybe it makes sense to ignore it as the control has been disabled. How the OnClick is processed before the OnChange is finished, I don't know... maybe it is because when AntiFreeze is active the Indy functions call ProcessMessages several times. Again, this is a guess. And why with GTK the events seems messed up, I don't know either.

In my application that was not a problem in Windows (Lazarus and Delphi) because I only cared about the OnChange event. But in Linux my problem is that one click triggers the OnChange event, but the next doesn't, then the next it does, and the next don't and that is a very annoying experience for the user.

So, I'll try to stop disabling the TreeView and using a global flag so I don't have several events running at the same time. Regarding disabling AntiFreeze, I could do it but then I'll have to move the IdHTTP to its own thread and I think I will end up using a global flag anyway.

Should I file a bug report for this? I mean, maybe I'm just missusing the controls and the AntiFreeze.

Regards,

MV

Navigation

[0] Message Index

Go to full version