1. Technology

Passing a Simple Type Variable (Integer) for a Pointer Parameter.

IterateSubtree for VirtualTreeView - Counting Using the Data: Pointer Parameter

By

The TVirtualTreeview component by Mike Lischke is a custom-Delphi-control master piece.

If you ever needed a tree like user interface in your Delphi applications I would strongly suggest that you try the Virtual TreeView. Delphi IDE uses it. Have I mentioned that it is free.

Anyway, the rest of this article is not (only) about the Virtual TreeView but about something that can be named: "preserve the value of a value type pointer parameter in Delphi callbacks for simple types". What a stupid title :)

Before I continue I need to freshen up your memory on some fundamental Delphi topics:

On Value Parameters

The Understanding and Using Functions and Procedures along with The Many Faces of Delphi Routines: Functions and Procedures describe what functions and procedures in Delphi programming are, and provide a material for beginners to understand various parameter passing options.

Let's consider the next function declaration:

 function DoIt(var x : integer; y : integer) ;
 
Note the different declaration between the X and Y parameters. They are both integers but X is a variable parameter while y is a value parameter.

A value parameter acts like a local variable that gets initialized to the value passed in the procedure or function call. If you pass a variable as a value parameter, the procedure or function creates a copy of it; changes made to the copy have no effect on the original variable and are lost when function exits.

On Procedural Pointers

Consider the next function declaration:
 procedure IterateSubtree(Callback: TCallback; Data: Pointer) ;
"Data" is a value parameter (a Pointer type). TCallBack is a procedural type defined as:
 type
 TCallback = procedure(Data: Pointer; var Abort: Boolean) ;
 
In order to call the IterateSubtree procedure you also need a procedure pointer to the TCallBack procedural type.

In the above scenario, the IterateSubtree calls Callback and passes the Data parameter to it until "Abort" is set to true.

Preserve The Value of a Value Type Pointer Parameter in Delphi Callbacks for Simple Types

The above procedure declarations are simplified versions of same-named methods found in the Virtual TreeView. The IterateSubtree will walk through all the nodes in the tree and will call the Callback procedure for each node.

And finally here comes the question: what if your Data parameter is an integer variable - you want to count how many nodes fulfill some criteria.

Real Life: Counting "Interesting" Nodes

In one of my applications, using TVirtualTreeView, I need to count how many nodes are "candidates" (never mind for what).

The TVirtualTreeView's IterateSubtree should be used.

Here's the stripped down version of the code I'm using:

 var
 candidateCount : integer;
 begin
 candidateCount := 0;
 IterateSubtree(GetCandidates, @candidateCount) ;
 end;
 
 ....
 
 procedure GetCandidates(Data: Pointer; var Abort: Boolean) ;
 begin
 if isCandidate then //some condition
 begin
 Integer(Data^) := 1 + Integer(Data^) ;
 end;
 end;
 
Now, what's so special about the above code. Pointers and pointer "arithmetics". Here's what:
  1. GetCandidates should count something - the ideal type for this is an integer type variable: "candidateCount".
  2. IterateSubtree expects a value parameter for the Data parameter which is a Pointer.
  3. @candidateCount (in IterateSubtree function call) is used to pass the address of the candidateCount variable.
  4. In the GetCandidates I have to dereferences the pointer to get value stored at the memory address held by the pointer. Since I know this is an integer type value I cast it to integer.
  5. Once the Data pointer is dereferenced to an integer value I can simply increase the value using:

    Integer(Data^) := 1 + Integer(Data^)

    1. And that's it. Nothing smart just another trick (If I may call it like that) possible through the use of pointers:

      Data is a value parameter, therefore the "value" of Data is lost when function exists. Since the IterateSubtree calls the GetCandidates several times I needed a way to preserve the value of the Data parameter. This was possible using Pointer manipulation.

      Note: if the Data parameter was not a simple type (integer) no pointers are required. Just type cast the pointer back to the original passed type.

      Delphi tips navigator:
      » Quickly Load MDI Child Windows in Delphi MDI Applications - Avoid Resize Animation
      « TVatCalculator - Value Added Tax Calculator Implementation in Delphi

©2014 About.com. All rights reserved.