canExpand example
Suppose you want to display customer and their orders in a tree view named custTree. To make the form load faster, you initially add only the first order for each customer (so that customer with orders will have the + button), then load all other orders on-demand through the canExpand event. You call the following method in the form’s overridden open( ) method so that the tree is initialized before the form opens:
function initTree
local tCust
if form.rowset.first()
do
tCust = new TreeItem( form.custTree, ;
"C" + form.rowset.fields[ "CUST_ID" ].value )
tCust.demandLoaded = false // Create new properties
tCust.bookmark = form.rowset.bookmark()
with tCust
text = form.rowset.fields[ "LAST_NAME" ].value.rightTrim() + "," + ;
form.rowset.fields[ "FIRST_NAME" ].value.rightTrim()
if not form.orders1.rowset.endOfSet
with new TreeItem( tCust, ;
"O" + form.orders1.rowset.fields[ "ORDER_NUM" ].value )
text = form.orders1.rowset.fields[ "ORDER_NUM" ].value + " " + ;
form.orders1.rowset.fields[ "ORDER_DATE" ].value
endwith
endif
endwith
until not form.rowset.next()
endif
Unique names are generated for each level of tree items and passed as the second parameter to the TreeItem class constructor; duplicate names are not allowed. The customer and order rowsets are linked with masterRowset so that navigation in the customer rowset automatically navigates to the corresponding orders. The text property is assigned inside a WITH block in case other stock properties are assigned in the future, which would also go inside the WITH block. The custom demandLoaded and bookmark properties for the top-level tree item must be created outside the WITH block; you can’t create properties in a WITH block. Here is the canExpand event handler:
function CUSTTREE_canExpand
local t, r
t = this.selected // TreeItem being expanded
r = form.orders1.rowset // Detail rowset
if not t.expanded and not t.demandLoaded
form.rowset.goto( t.bookmark )
do while r.next( ) // Start with second detail row (if any)
with new TreeItem( t, "O" + r.fields[ "ORDER_NUM" ].value )
text = r.fields[ "ORDER_NUM" ].value + " " + ;
r.fields[ "ORDER_DATE" ].value
endwith
enddo
t.demandLoaded := true
endif
return true
The event handler creates some short-hand variables for the tree item being expanded and the order rowset. It then checks to see if the tree item is being expanded (it is if its expanded property is false to begin with) and has not been demand-loaded yet. If so, it goes to the saved bookmark and immediately tries to go to the second matching order. By calling next( ) at the top of the DO WHILE loop, nothing happens if there is only one matching order, and that’s all that is needed to loop through all the matching orders.
After adding the rest of the orders, the custom demandLoaded property is set to true so that this code is skipped the next time this customer’s tree item is expanded. Finally, the event handler always returns true to allow the expansion (or collapse, if that’s what triggered the event).
Note that this technique would not work in a situation where the first detail row might change while the user is viewing the tree. In that case, when the detail rows are demand-loaded, the row that was loaded when then tree was initialized would be loaded again, causing an error with the duplicate name. But if, for example, the orders are stored chronologically, this could not happen.