Avatar of ConceptSysInc
ConceptSysInc asked on

Revealing the current application/object event

I'm creating an application that generates a "treeView" index based on field values in an ADO table. When form is created, certain user-based object events are fired, such as the treeView's "onChange".

How can I test if the current event is fired because of user-action, or if it's fired by the form being created? I looked up "tBasicAction" in the Help, but it didn't clear up the matter, and I can't find how to reveal a current event or the event-source. (The event-model is not that defined).

Thank you, in advance
Delphi

Avatar of undefined
Last Comment
modulo

8/22/2022 - Mon
shaneholmes

"How can I test if the current event is fired because of user-action, or if it's fired by the form being created?"

UMMMMM, there would be no No user action until after form is created....

Shane
kretzschmar

?? usual i have a global var

var treefilling : boolean;

then i have a loadtree-proc

procedure TFormX.LoadTree;
begin
  TreeFilling := True;
  //fillingAction
  TreeFilling := False;
end;

and in any event, which may triggered by filling the tree i have

procedure TFormX.TreeviewXChange(sender : TObject; Node : TTreeNode);
begin
  if not TreeFilling then
  begin
     //useraction
  end;
end;

meikl ;-)
shaneholmes



 Ahhhhhh, not on form creation, he wanted it on Tree creation.... <Smile>

Shane

Your help has saved me hundreds of hours of internet surfing.
fblack61
ASKER
ConceptSysInc

Let me clarify: for example, there is code in the "onChange" that issues a SQL query for records that fall under the selected treeNode (based associated treeNode data). However, when the form is created, the "onChange" event fires, and surely references to specific objects are null-and-void.

What's needed is a CASE or IF statement that tests the event - ie, if the formis being created, then <do this>; if the user selects a treeNode, then <do that>. The problem for me is capturing and interpreting the event and/or message generated in any event.

Kretz, you method will work but it doesn't reveal anything about the Delphi's event-model (but if there is no true answer, then I'll slide the points to you)
kretzschmar

well,

do you have predefined nodes?
if so, the first change-event comes,
if the tree gets the focus, because its the activecontrol

is it such construction you could solve it this way

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ComCtrls;

type
  TForm1 = class(TForm)
    TreeView1: TTreeView;
    procedure TreeView1Change(Sender: TObject; Node: TTreeNode);
  private
    isNotFirst : Boolean; //defaults to False
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}



procedure TForm1.TreeView1Change(Sender: TObject; Node: TTreeNode);
begin
  if isNotFirst then
    showmessage('Change fired for Node '+Node.Text)
  else
    isNotFirst := True;
end;

end.

meikl ;-)
kretzschmar

btw. at which time you have a properly filled data-entry
(just asking because this event is just fired after the form is created, not during creating of the form)

meikl ;-)
Get an unlimited membership to EE for less than $4 a week.
Unlimited question asking, solutions, articles and more.
ASKER
ConceptSysInc

Meikl,

the tree is NOT pre-defined; it is populated from a queried SQLserver-based dataset. Referencing changes in the nodes is no problem for me to code - it's knowing what events and messages are being generated that's the problem. (PARADOX was great for situations like this because you always knew what was going on behind the application).

If this is too "internal", then do you know of any DELPHI sites (or even books) that go into the ying-and-yang of database processing and development with Delphi?
kretzschmar

well, next question,

do u use the standard-treeview or any other third-party tree?
(i know, that the virtualStringTree fires this onChange-event also by adding Nodes, whereas the standard-treeview does not do this)

meikl ;-)
ASKER
ConceptSysInc

sorry, no third-party components...

Call me crazy but I figured anything with tObject inheritance should have methods that reveal the object's events. (I was reading about the tBasicAction class but there isn't aren't any good examples or explanations on it's use).
Experts Exchange has (a) saved my job multiple times, (b) saved me hours, days, and even weeks of work, and often (c) makes me look like a superhero! This place is MAGIC!
Walt Forbes
kretzschmar

courious,
just asking myself why you have porblems,
there should be no one

can you show, how you do fill your tree?

meikl ;-)
kretzschmar

an older sample,
(Node-amount and Tree-Depth and ID/ParentID order doesn't matter)


unit loadtree_u;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, DB, Mask, DBCtrls, ADODB, ComCtrls;

type
  TForm1 = class(TForm)
    ADOConnection1: TADOConnection;
    ADOQuery1: TADOQuery;
    TreeView1: TTreeView;
    ADOTable1: TADOTable;  //Here are done the Changes
    ADOTable1Id: TAutoIncField;
    ADOTable1Id_Parent: TIntegerField;
    ADOTable1Description: TWideStringField;
    ADOTable1Value: TIntegerField;
    Label1: TLabel;
    DBEdit1: TDBEdit;
    DataSource1: TDataSource;
    Label2: TLabel;
    DBEdit2: TDBEdit;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure TreeView1Change(Sender: TObject; Node: TTreeNode);
    procedure TreeView1Deletion(Sender: TObject; Node: TTreeNode);
  private
    Procedure Load_Tree;  //Load the Tree, also use for Refresh_Tree
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

Type
  PDataCacheRecord = ^TDataCacheRecord;
  TDataCacheRecord = Record
                       ID  : Integer;
                       PID : Integer;
                       Text: String[50];
                     end;

function FindParent(ATreeView : TTreeView; ID : Integer) : TTreeNode;
var i : integer;
begin
  result := nil;
  i := 0;
  while (i < ATreeView.Items.Count) and
        (assigned(ATreeView.Items[i].Data)) and
        (PDataCacheRecord(ATreeView.Items[i].Data)^.ID <> ID) do
    inc(i);
  if i < ATreeView.Items.Count then
    result := ATreeView.Items[i];
end;


Procedure TForm1.Load_Tree;
var
  ANode : TTreeNode;
  RecordCache : PDataCacheRecord;
  RecordCacheList : TList;
  I, PreviousCount : Integer;
begin
  TreeView1.Items.Clear;
  ADOQuery1.Close;
  ADOQuery1.SQL.Text := 'Select ID, ID_Parent, Description from Tree_Table Order by Id_Parent';
  RecordCacheList := TList.Create;
  try
    ADOQuery1.Open;
    //Cache Data
    while not ADOQuery1.Eof do
    begin
      RecordCache := New(PDataCacheRecord);
      RecordCache^.ID := ADOQuery1.FieldByName('ID').AsInteger;
      RecordCache^.PID := ADOQuery1.FieldByName('ID_Parent').AsInteger;
      RecordCache^.Text := ADOQuery1.FieldByName('Description').AsString;
      RecordCacheList.Add(RecordCache);
      ADOQuery1.Next;
    end;
    ADOQuery1.Close;
    //Adding Roots
    PreviousCount := RecordCacheList.Count;
    i := 0;
    While i < RecordCacheList.Count do
    begin
      If PDataCacheRecord(RecordCacheList.Items[i])^.PID = 0 then //RootEntry
      begin
        ANode := TreeView1.Items.AddChild(NIL,PDataCacheRecord(RecordCacheList.Items[i])^.Text);
        ANode.Data := RecordCacheList.Items[i];
        RecordCacheList.Delete(i);
      end
      else inc(i);
    end;
    //Adding Childs
    //Loop until there is nothing or it is never reduced -> inkonsistence
    While (RecordCacheList.Count > 0) and (PreviousCount <> RecordCacheList.Count) do
    begin
      i := 0;
      PreviousCount := RecordCacheList.Count;
      while i < RecordCacheList.Count do
      begin
        ANode := FindParent(TreeView1,PDataCacheRecord(RecordCacheList.Items[i])^.PID);
        if Anode <> NIL then
        begin
          ANode := TreeView1.Items.AddChild(ANode,PDataCacheRecord(RecordCacheList.Items[i])^.Text);
          ANode.Data := RecordCacheList.Items[i];
          RecordCacheList.Delete(i);
        end
        else inc(i);
      end;
    end;
    if RecordCacheList.Count > 0 then
      raise exception.Create('Data-Inkonsistence Detected!');
  finally
    RecordCacheList.Free;
  end;
end;

//Load
procedure TForm1.Button1Click(Sender: TObject);
begin
  ADOTable1.Close;
  Load_Tree;
  ADOTable1.Open;
  TreeView1.Selected := TreeView1.TopItem;
end;

//Navigate
procedure TForm1.TreeView1Change(Sender: TObject; Node: TTreeNode);
begin
  if ADOTable1.Active then
    ADOTable1.Locate('ID',PDataCacheRecord(Node.Data)^.ID,[]);
end;

//avoid memoryLeak
procedure TForm1.TreeView1Deletion(Sender: TObject; Node: TTreeNode);
begin
  If assigned(Node.Data) then
    Dispose(PDataCacheRecord(Node.Data));
end;

end.

meikl ;-)
ASKER
ConceptSysInc

I fill it the same as you did, pretty much: query the database; while-not-EOF through the recordSet, doing an "... items.add" to the tree.

the problem is that the "onChange" event keeps firing, invoking the code, prior to the tree being populated and the form displayed
Get an unlimited membership to EE for less than $4 a week.
Unlimited question asking, solutions, articles and more.
ASKER
ConceptSysInc

For now, I have a quick-fix -

the best I can come up with is using the treeView's "selText" property: the SelText property is only valid when the combo box has focus; when the combo box does not have focus, reading SelText always yields an empty string and setting it inserts the text at the cursor rather than replacing the selected text. So if I use an "IF"-statement at a critical point in the "onChange" procedure, I can know if the node was [actually] selected, or if the event was called by something... non-user related.
kretzschmar

well, thats a workaround :-)
(you see in my sample above,
that i determine this on the adotable.active-property)

just to say,
that the treeview doesn't care about properly filled data,
-> means you have to care about this

meikl ;-)
ASKER
ConceptSysInc

this question can be closed since I was NOT able to find a more suitable solution than the one I  am already using
Experts Exchange is like having an extremely knowledgeable team sitting and waiting for your call. Couldn't do my job half as well as I do without it!
James Murphy
kretzschmar

i'm unsure to agree with this
ASKER
ConceptSysInc

the thrust of the question was how to "branch" the processing during the initial creation of the form - while your suggested solution and source code show how to populate the tree: that's a "no-brainer", and I already have that coded!

after more trial-and-error, I found the solution to the question/issue is to test whether the tree contains any objects or "nodes"; ie, this is done by an IF-statement that asks whether "... the treeview.componentCount equals zero" - if it's zero, then break; otherwise, you've started the form-creation process, and the inherited objects exists

I just figured that since I came up with this solution on my own, there was no need to keep this question OPEN
shaneholmes

Lets see the solution posted here....

listening...

Shane
Get an unlimited membership to EE for less than $4 a week.
Unlimited question asking, solutions, articles and more.
ASKER CERTIFIED SOLUTION
modulo

Log in or sign up to see answer
Become an EE member today7-DAY FREE TRIAL
Members can start a 7-Day Free trial then enjoy unlimited access to the platform
Sign up - Free for 7 days
or
Learn why we charge membership fees
We get it - no one likes a content blocker. Take one extra minute and find out why we block content.
See how we're fighting big data
Not exactly the question you had in mind?
Sign up for an EE membership and get your own personalized solution. With an EE membership, you can ask unlimited troubleshooting, research, or opinion questions.
ask a question