You are on page 1of 16

TREEVIEW4GL

version 6.5

www.4GL.fr

This freeware is delivered as "as-is" software and no responsibility can be assumed in any case of malfunctions.
If you want to be informed of new versions and updates, you just need to subscribe to the 4GL mailing list.

// Feel free to try vpxPrint //


www.4GL.fr TREEVIEW4GL

The 4GLTreeview is an Active-x control developed by Marcel FONDACCI (m.fondacci@4gl.fr) from 4GL. It is an 'easy to use' OCX
Treeview based on VirtualTreeview. This control is not richer than other similar commercial controls, but in many cases, the problem to
be solved is quite simple… and the complexity of these controls becomes THE problem.
You'll find it easier to use and efficient with reasonable (and understandable) code to get a good result.

You can change size, font, color, image list, node expansion... Based on code well understood by PROGRESS users (like variable lists), it's
easy to integrate within your PROGRESS application.

You'll find demo programs (to use with a sports database): *.w to show the basics.

The use of this control is free. You can distribute freely your applications with this control.

This freeware is delivered as "as-is" software and no responsibility can be assumed in any case of malfunctions.

Enjoy with TreeView4GL!

Marcel

Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND,
either express or implied. See the License for the specific language governing rights and limitations under the
License.

The original code is VirtualTrees.pas, released September 30, 2000.

The initial developer of the original code is digital publishing AG (Munich, Germany, www.digitalpublishing.de),
most code was written by Mike Lischke 2000-2009 (public@soft-gems.net, www.soft-gems.net)

Portions created by digital publishing AG are Copyright


(C) 1999-2001 digital publishing AG. All Rights Reserved.

2
www.4GL.fr TREEVIEW4GL

History of changes:

❖ 08/09/2022: Version 6.5


o Different fixes on image size.
o Updated doc about addImage() method, the addImage returns the image number.
o New onNodeClick event that returns the clicked node info even if it hasn't changed.
(useful for state changes)
❖ 06/06/2022: Version 6.4
o Documentation of 64bit version,
o Different fixes… node click and more.
❖ 23/04/2015 : Version 6
o Treeview4GL is now based on Virtual Treeview instead of Microsoft treeview, due to problems in 64bit on some OS
❖ 11/2014: Version 5.1 - 32/64 bit version
❖ Version 4.6: Vista+ compatibility
❖ 17/03/2000 : bug corrected in addAfterNode. The inserted node was not correctly inserted and appears as a child node.
❖ 17/03/2000 : New method : deleteHNode()
❖ 17/03/2000 : New attribute : expanded( hNode ) to control the expansion of a node
❖ 17/03/2000 : New attribute : TreeRefresh
❖ 17/03/2000 : update of the testocx.w demo program.

❖ 27/03/2000: Version 2.3


❖ 27/03/2000: new event OnCollapsed,
❖ 27/03/2000: Image index allows now an opened/closed node image
❖ 27/03/2000: update of the testocx.w demo program
❖ 27/03/2000: the name of Active-X is now Treeview4GL.ocx
❖ 31/03/2000: minor bug corrected. When open/close images specified, the expand of the SELECTED node does not correctly
display the good icon. (Version 2.3b)
❖ 14/04/2000: Version 2.4
new methods: imageSize(width, height) to change the size of icons in the treeview,
resetImages() to reset to standard image list
the bitmaps added to the treeview are now transparent.
Set of includes provided to facilitate the treeview usage with PROGRESS.

❖ 10/05/2000 Version 2.5


new properties :
- lines display/hide of treeview lines
- buttons display/hide buttons + -
- track display a hot spot on mouse over
- images display/hide images icons

❖ 18/08/2000 Version 2.6


new property :
- getParent to get the parent node info.
New event OnKeyPress

Testocx.w demo program has been renamed to demo.w

❖ 28/11/2000 Version 3.2


The returned value of addafternode() has been changed.

3
www.4GL.fr TREEVIEW4GL

The actual value does not return the node number


This has been made to speed up the addafternode() method.
For compatibility with other methods, the same output format is kept except for the node number (always '').
This minor update results in considerable performance increase.
You must control if this update is not a problem for you.
To get the node number, use gethNode( {nodehandle.i} ) to obtain it after your addaftermode() call.

❖ 16/11/2001 Version 3.7 (later…)


new event :
- onrightClick to get the parent node info.
Corrections: open/close images were not always correct,
Nodes deletes cause some malfunctions.
Updated doc by Sebastien Lacroix (thanks). Special attention to node 0.

❖ 16-jan-2005:
Added properties: fontName and fontSize are accessible at run-time to change the value of the standard font.
Alternate image list with new icons has been added.

❖ Performance issue (jul-2000):


If the number of nodes added by a single addnodes() is important, you may encounter an excessive response time
due to the splitting of the large size of the load info into individual entries. See the discussion about addnodes() later
in this document.

4
www.4GL.fr TREEVIEW4GL

64bit considerations
The major problem with the 64 bits version is that the 'node handle' which is a 32 bits integer becomes a 64 bits
integer.

If your development software is 64bits, you must therefore:


1. Use 64 bits integers for all node-handles,
2. Be sure to use all new includes nodeHandle.i, etc…
3. Call the following 64-bit functions instead of the standard ones:
procedure DeleteHNode64(hNode: Int64);
function GethNode64(hNode: Int64) : String;
function GetParent64(hNode: Int64) : String;
function GotohNode64(hNode: Int64): String;
function FirstChild64( hNode: Int64 ) : Int64;
function LastChild64( hNode: Int64 ) : Int64;
function NextSibling64( hNode: Int64 ) : Int64;
function ChildrenNumber64(hNode: Int64): Integer;
procedure Set_Expanded64(hNode: Int64; NodeStatus: logical);
function Get_Expanded64(hNode: Int64): logical;
4. The include file ‘treeview.i’ may help you to maintain independent 32/64bit source code:
&IF "{&PROCESS-ARCHITECTURE}" = "64" &THEN
&GLOBAL-DEFINE INTEGERTYPE INT64
&GLOBAL-DEFINE S64 64
&ELSE
&GLOBAL-DEFINE INTEGERTYPE INT
&ENDIF

&IF "{&hTreeview}" = "" &THEN


&GLOBAL-DEFINE hTreeview chChTreeview:TreeView4GL
&ENDIF

DEF VAR hSelected AS {&INTEGERTYPE} NO-UNDO.


DEF VAR hNode AS {&INTEGERTYPE} NO-UNDO.

Example:
DEF VAR A AS CHAR NO-UNDO.
DEF VAR ChildrenNumber AS INT NO-UNDO.

A = {&hTreeview}:GetSelectedNode().

hSelected = {nodeHandle.i A}. /* be sure to use the new nodeHandle.i */


ChildrenNumber = {&hTreeview}:ChildrenNumber{&S64}(hSelected).

hNode = {&hTreeview}:NextSibling{&S64}( hSelected ).

IF hnode > 0 THEN


{&hTreeview}:gotoHNode{&S64}(hNode).

5
www.4GL.fr TREEVIEW4GL

TreeView LOADING :

<Component-Handle frame>:TreeView4GL:AddNodes ( <Char variable> ).

Parameters :
<Char variable> is a ~n delimited variable.

Each node of the treeview is separated by a "~n", each tree line is a list delimited by tabs (~t).

General Format :
A = "<Line 1 attributes>~n<Line 2 attributes> …………………".

Line Format :
Each attribute line is a tab delimited field wich contains :

The level (0 to n) MANDATORY


The title MANDATORY
The normal image number [ , Open image number ] MANDATORY
The selected image number MANDATORY
The state image number OPTIONAL
The 'PRIVATE-DATA'… of course ! OPTIONAL

With the 2.3 version, it's possible to set a second image number in the normal image index. If you specify a second image
number, then Treeview4GL.ocx will display this 2nd image when the node is expanded and return to the first one if the
node is collapsed.

Example :
Def var A as char no-undo.

For each customer no-lock


by name:
A = A + "~n0~t" + Customer.Name
+ "~t7~t16~t~tCustomer=" + string(Cust-num).
For each order of customer no-lock :
A = A + "~n1~t" + "Order " + string(Order-Num)
+ "~t0,1~t16~t17~tOrder=" + string(Order-num).
end.
end.

a = substring(a, 2).

chTreeView:TreeView4GL:clear().
chTreeView:TreeView4GL:addnodes(a).

Note :
• The state image number is a number between –1 and 16.
• This kind of structure level,title,index1,index2,index3,private-data is a common structure to TreeView4GL.
• Important performance issue ( jul-2000): if the number of nodes added by a single addnodes() is important, you may
encounter an excessive response time due to the splitting of this large area into individual entries. This would be updated
in future versions but at this time, use the following :
chTreeView.Treeview4GL:TreeRefresh = False.
For each … … /* file to load */
… … /* Node constitution in A */
chTreeview.Treeview4GL:addnodes( A ). /* a single node at a time */
end.
chTreeView.Treeview4GL:TreeRefresh = True.

6
www.4GL.fr TREEVIEW4GL

TreeView CLEAR :

<Component-Handle frame>:TreeView4GL:clear().

Parameters :
None.

Obtain Treeview INFO :

<Char variable> = <Component-Handle frame>:TreeView4GL:GetSelectedNode().


<Char variable> = <Component-Handle frame>:TreeView4GL:GetNode( <Node#> ).
<Char variable> = <Component-Handle frame>:TreeView4GL:GethNode( <NodeHandle> ).

Parameters :
Return parameter is a character variable with the following format :

Node number
Chr(1)
Node Handle
Chr(1)
<Tab> separated list. Same format as AddNodes() :

The level
The title
The Normal image numbers
The selected image number
The state image number
The 'PRIVATE-DATA'

Add a node to an existing Treeview :

[ NodeInfo ] = <Component-Handle frame>:TreeView4GL:addafterNode(


<#SelectedNode>, /* From GetSelectedNode */
<Node Description>
).
Parameters :
<#SelectedNode> : integer obtained from GetSelectedNode
Node Description : same as AddNodes
<Tab> delimited variable with the following items :

Level (1 to n) MANDATORY
Title MANDATORY
Normal image numbers MANDATORY
Selected image number MANDATORY
State image number OPTIONAL
'PRIVATE-DATA' OPTIONAL

The return parameter NodeInfo gives the node information of the newly created node.
Since the version 3.2, the nodenumber returned in the output nodeInfo parameter has a node number of ''. You have to
explicitly insert a gethNode( <node handle> ) to retrieve it.

Note :
The level determines how the new node is inserted:
- When Level = <#SelectedNode> level, add of a new BROTHER node
- When Level > <#SelectedNode> level, add of a new CHILD node
- When Level = 1, add of a new root node

7
www.4GL.fr TREEVIEW4GL

Change a node :
<Component-Handle frame>:TreeView4GL:changeNode(
<#SelectedNode>,
<Node Description>
).

8
www.4GL.fr TREEVIEW4GL

Get a Node Info:

<Char Variable> = <Component-Handle frame>:TreeView4GL:GetSelectedNode().

Return value :
Node Number from 0,
Chr(1)
Node Handle,
Chr(1)
NodeAttributes (See the Node Attributes format in addnodes() )

Goto Node :
< Component-Handle frame>:TreeView4GL:GotoNode( <NodeNumber> ).

Or if you have a node handle :

<Component-Handle frame>:TreeView4GL:GotohNode( <NodeHandle> ).

Note : the second form is more efficient.

Node delete :
<Component-Handle frame>:TreeView4GL:DeleteNode( <NodeNumber> ).

Or if you have a node handle :

<Component-Handle frame>:TreeView4GL:DeletehNode( < NodeHandle> ).

Note :
DeleteNode frees the memory allocated to the node with his 'PRIVATE-DATA' extension. But in case of
a parent node, the children are deleted too, without freeing the PRIVATE-DATA area of the sub-nodes.
At this time, it's your responsibility to delete all the children first.

9
www.4GL.fr TREEVIEW4GL

Exploring the arborescence…

It is very easy to manipulate the TreeView. Note that all the following methods use node handles, not node numbers.

Obtain the number of children of a node :


<Integer variable> =
<Component-Handle frame>:TreeView4GL:ChildrenNumber( <NodeHandle> ).

Returns the number of children (first level only) of the node.

Note : ChildrenNumber( 0 ) returns the total number of nodes of the Treeview.

Navigation :
<Integer variable> =
<Component-Handle frame>:TreeView4GL:FirstChild( <NodeHandle> ).

Returns the Handle of the first Child of the node.


(zero if not available).

<Integer variable> =
<Component-Handle frame>:TreeView4GL:LastChild( <NodeHandle> ).

Returns the Handle of the last Child of the node.


(zero if not available).

<Integer variable> =
<Component-Handle frame>:TreeView4GL:NextSibling( <NodeHandle> ).

Returns the Handle of the next sibling node for this level.
(zero if not available);

A sequential navigation in all the Treeview can be done, using the absolute node number:

do i = 1 to chChTreeview:TreeView4GL:ChildrenNumber( 0 ):
a = chChTreeview:TreeView4GL:GetNode( I - 1). /* Node number is relative
to 0 */
message "Node number" entry(1, a, chr(1)) skip
"Private Data" entry(6, a, "~t")
skip(1)
"Do you wish to continue ?" view-as alert-box QUESTION
buttons yes-no update OK.
OR
message "Node number" { nodeNumber.i a } skip
"Private Data" { nodeprivate.i a }
skip(1)
"Do you wish to continue ?" view-as alert-box QUESTION
buttons yes-no update OK.
if not ok then leave.
end.

<Character variable> =
<Component-Handle frame>:TreeView4GL:getParent( <NodeHandle>).

Returns the Node Info of the parent node, ? if not available.

10
www.4GL.fr TREEVIEW4GL

Expand / collapse the nodes:

A particular node can be expanded or collapsed by setting his EXPANDED attribute:

<Component-Handle frame>:TreeView4GL:Expanded( <NodeHandle> ) = <Logical>.

If you want to reduce a particular handle set the Expanded attribute to TRUE, a FALSE value collapses the
arborescence of this node.

This EXPANDED attribute can be queried, so the following is correct:

If Not chChTreeview:TreeView4GL:Expanded( hNode ) then


chChTreeview:TreeView4GL:Expanded( hNode ) = TRUE.

Or in a on-off mode :

chChTreeview:TreeView4GL:Expanded( hNode ) =
NOT chChTreeview:TreeView4GL:Expanded( hNode ).

Programming note :
The expand attribute controls the expand or collapse of a node handle, not of the depending sub-nodes. So
if you expand a previously collapsed node, the sub-nodes remains in the state they had before.

Treeview4GL does a refresh after each call. If you plan to expand a large amount of nodes, set the
TreeRefresh attribute to false before, then set it to true after your procedure.

This following procedure expands a complete TREEVIEW :


def var i as int no-undo.
def var a as char no-undo.
def var hNode as int no-undo.

/* Set the REFRESH MODE TO FALSE */

chChTreeview:TreeView4GL:TreeRefresh = FALSE.

do i = 1 to chChTreeview:TreeView4GL:ChildrenNumber(0) :
a = chChTreeview:TreeView4GL:GetNode( I - 1).
hNode = int(entry(2, a, chr(1))). /* Get the node handle */
/* OR hNode = {nodenumber.i a }. */
If Not chChTreeview:TreeView4GL:Expanded( hNode ) then
chChTreeview:TreeView4GL:Expanded( hNode ) = true.
end.

/* Set the REFRESH MODE TO TRUE */

chChTreeview:TreeView4GL:TreeRefresh = TRUE.

11
www.4GL.fr TREEVIEW4GL

REFRESH THE TREEVIEW


If you expect a large amount of calls (insert, delete, expand…), you can speed up the time needed by setting the
TreeRefresh attribute to OFF.

<Component-Handle frame>:TreeView4GL:TreeRefresh = FALSE.

…but don't forget to reset this attribute to TRUE after your procedure, or the treeview will not be updated on the
screen.

MANAGING IMAGE LIST


Image display:
You can deactivate or activate the display of icons with the Images property. (Get and set property)
<Component-Handle frame>:TreeView4GL:Images = true/false

Clear Image list :


<Component-Handle frame>:TreeView4GL:clearImages().

Add image to the image List:


[ imageNumber = ] <Component-Handle frame>:TreeView4GL:addImage( < ImagePath > ).
imageNumber:
• -1 the image can’t be added,
• The image number relative to 0if the image has been added to the list
Note :
< ImagePath > can be an *.ico or *.bmp file and must exist.

< ImagePath > is added to the current image list. If you plan to constitute your own image list, you have to
clear the image list with ClearImages().

Replace image in the Image List:


<Component-Handle frame>:TreeView4GL:replaceImage( <ImageNumber>, <ImagePath> ).

Standard Image list (ImageList = 1)

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 3
Default image list

12
www.4GL.fr TREEVIEW4GL

Alternate Image List (ImageList = 2)

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39

40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59

60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79

80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99

Switching from one image list to the other :


<Component-Handle frame>:TreeView4GL:ImageList = n.
where n = 1 for the standard image list and 2 for the alternate.

Changing the images size:


The standard image list is a set of 16x16 pixels images.
If you want to change the size of this image list, use the method :

<Component-Handle frame>:TreeView4GL:imageSize ( <width>, <height> ).

WARNING : this method clears the entire image list and you have to fill the image list with new images of the
corresponding size (or they'll be truncated).

Reset the standard image list:


The reset of the standard image list is accomplished by

<Component-Handle frame>:TreeView4GL:resetImages ().

WARNING : this method keeps the current size of your image list. If you want to return to the original size, use a
imageSize method(16,16) before resetImages().

13
www.4GL.fr TREEVIEW4GL

Additional METHODS and PROPERTIES

Display Lines :
<Component-Handle frame>:TreeView4GL:Lines = true/false.
Display/hide the connection lines (Default = true).

Display buttons :
<Component-Handle frame>:TreeView4GL:Buttons = true/false.
Display/hide the + and - buttons (Default = true).

Track Display:
<Component-Handle frame>:TreeView4GL:Track = true/false.
Display a hot spot on mouse over node event

Display AboutBox :
<Component-Handle frame>:TreeView4GL:AboutBox ( ).

Refresh the display :


<Component-Handle frame>:TreeView4GL:Refresh ( ).

14
www.4GL.fr TREEVIEW4GL

PROGRAMMING NOTES
About the node number :
The node number is relative to zero and indicates at any time the real sequence of nodes.
The node number is not stable. Its value is changing in accord with all Treeview updates (deletes and adds).

If the Treeview is subject to changes, the right method is to use invariant Node handles.
The access to a specific node is more efficient by handles.

With the version 2.3, you can set two normal images numbers: one for a normal (collapsed) node, one for opened
node. You can also manually program what you want in OnExpanded and OnCollapsed events. For example, on
expanded, change the node (ChangeNode() ) to set different images, texts or private-data.

INCLUDES FOR PROGRESS


The use of entry(entry(entry….."~t")) can be replaced by the following includes :
NodeHandle.i
NodeLabel.i
NodeLevel.i
NodeNormal.i
NodeNumber.i
NodePrivate.i
NodeSelected.i
NodeState.i
You can use them in place of the corresponding PROGRESS “ENTRY” instructions.
Each of these includes retrieves the corresponding value from a field p-NodeInfo (it's the name that Treeview4GL
sends as parameter on CHANGE or CLICK triggers).

Example:
IF {nodePrivate.i } begins "MyMode" then do:
……
end.
A different field than p-NodeInfo can be specified:
IF { Nodelevel.i myNode } = "3" then …

15
www.4GL.fr TREEVIEW4GL

Events

OnChange
DEFINE INPUT PARAMETER p-NodeInfo AS CHARACTER NO-UNDO.

OnNodeClick (similar to Onchange but triggered even if the node has not changed)
DEFINE INPUT PARAMETER p-NodeInfo AS CHARACTER NO-UNDO.

OnExpanded
DEFINE INPUT PARAMETER p-NodeInfo AS CHARACTER NO-UNDO.

OnCollapsed
DEFINE INPUT PARAMETER p-NodeInfo AS CHARACTER NO-UNDO.

These three events returns node info in standard form :

Node Number from 0,


Chr(1)
Node Handle,
Chr(1)
NodeAttributes See the Node Attributes format in addnodes()

OnKeyPress
DEFINE INPUT-OUTPUT PARAMETER p-Key AS INTEGER NO-UNDO.

If the key is combined with CTRL, the character can be obtained by using:

dChar:screen-value in frame {&FRAME-NAME} =


"CTRL-" + chr(p-Key + asc("a") - 1).

OnRightClick
DEFINE INPUT PARAMETER p-NodeInfo AS CHARACTER NO-UNDO.

16

You might also like