![]() |
![]() |
|
![]() |
Using the Microsoft TreeView Control in Paradox By Liz Woodhouse Introduction TreeViews are often the best way to show certain types of data. However, Paradox® does not include its own treeview object type, so to include one in a Paradox form will require using a third-party control. This article discusses the Microsoft® TreeView control which is included with most, if not all, versions of Windows®. We'll cover what's possible, details on how to accomplish what's possible, and also what's not possible with this particular treeview. Background Following are things one should know prior to reading this article. If you're not familiar with ActiveX/OCX controls, I recommend reviewing Peter Zevenaar's tutorial. First, almost all of my testing has been done using Paradox 10 and Microsoft TreeView Control 6.0 (SP4) as included in MSCOMCTL.OCX. Limited testing has been done with Paradox 8 and Microsoft TreeView Control 5.0 (SP2) as included in COMCTL32.OCX. I cannot vouch for different versions of either. Second, the MS treeview uses "Index" and "Key" as properties and there is absolutely no way to get ObjectPAL to retrieve their values. However, there are other less-attactive ways around this problem which I'll discuss in this article. Third, the MS treeview only has one column. If you want a multi-column one, you'll need to find a different one. I've found some third-party OCX's which I'll comment on briefly at the end of this article. Fourth, you'll find Microsoft's documentation of their treeview control here. Fifth - I cannot get font settings (other than bold/not bold) to take, so if you decide to use the MS treeview, you'll be stuck with Arial 12pt. Sixth - TreeViews seem to have a common terminology which it's useful to know. The treeview itself is called just that; it contains a collection object called nodes, which in turn contains the individual node objects. Different treeviews vary in terms of which objects can be accessed from other objects (some require you to go through nodes to get to an individual node, others allow you to access a specific node from the treeview itself). You'll have to study the treeview's documentation to know exactly how each control works. Using the Microsoft TreeView Control Setting up the treeview on a form In Paradox, register MSCOMCTL.OCX or COMCTL32.OCX (which should be in your Windows system directory) (the latter has the earlier version of the treeview). Do this despite the fact that they show up in Paradox's list of OCXs. Then restart Paradox. Then start a new blank form, and add the treeview to the toolbar, then add the treeview to your form. Set properties as desired: + and - signs only show for the first level of nodes if the LineStyle (OCX properties, right-click on treeview) is set to 1 - tvwRootLines, and if the Style is set to one which includes "PlusMinus" symbols. I recommend you take some time to experiment with the control's properties, so you get an idea of what the options are and what works in Paradox. I didn't try using pictures in the tree, so if you wish to do so, you'll have to experiment on your own. By default, users can edit node text, so I suggest you disable this unless it's desired (set the LabelEdit property to 1 - tvwManual). Code to get which item is selected We'll cover this first as it's easier than the code to populate the tree (which I'll do last), and you can test this code alone as the treeview has default sample nodes available at runtime. This is where key and index do not come in (because ObjectPAL refuses to accept them): Index is a changeable integer representing where in the tree the node is now. It is zero-based, and as the tree could be sorted, the Index value can change. Key is a user-definable hidden value which must be unique for each node, which does not change and which, if we could get at it, would be extremely useful, but we can't get at it. Work-arounds are to use the text of the node, or to include the key in the text and use breakapart or a similar method to extract it. (NOTE: We do use key in the add() syntax to relate parent and child nodes, so it has some use - more later.) Use the tree's click() event (not a Paradox event, so it has a red dot in Object Explorer) to get the text of the selected item. You'll also want to use the KeyUp event, in case the user uses the keyboard to move through items. I would recommend posting a UserAction from these events so you don't have to duplicate the code: var oaNode OLEAuto ;// node object is also an OCX stText String endVar ;// treeTest is the name of the OCX object on the form oaNode = treeTest.SelectedItem ;// SelectedItem is a property and returns an ;// OLEAuto value which is the selected node stText = oaNode.Text ;// Text is a node property and equates to ;// the text displayed for the node ;// now do what you want with it...Code to populate the tree I recommend either posting a UserAction on open and then doing the population in the action event after open is done, or using a button or some other event (don't try to force it in the open event). NOTE: in these examples, treeTest is the name of the treeview object on the form. MS treeviews have a property called Nodes which returns an OLEAuto var which is the collection of all nodes in the tree. The MS treeview's add() syntax is as follows: nodesObject.add(li/stRelative, liRelationShip, stKey, stText) stText (string) = the text that will display for the node. stKey (string) = the unique string to distinguish the added node from all other nodes, must be unique. I recommend you use a unique field or integer value (the key value of record would be good) so you can easily add children to the parent. However, from testing, it seems the treeview will not accept an integer cast as a string, so you'll need to add an alpha character if you decide to use an integer as key (see example). li/stRelative (longInt for Index/string for Key) = The Index or Key of the new node's relative - the node to which it will be related - how it's related is defined in the next argument. liRelationship (longInt) = the relation between the node specified in li/stRelative and this new node. Valid values are: 0 = First - First node in Nodes (on level of relative) 1 = Last - Last node in Nodes (on level of relative) 2 = Next - Next node in Nodes (on level of relative) (default) 3 = Previous - Previous node in Nodes (on level of relative) 4 = Child - Child node to node named in relative Add() returns an OLEAuto var attached to the newly inserted node (using this var is optional). Example 1: Simple master-detail (1:M) relation where the details do not have details of their own: var tcDetails, tcMasters TCursor oaNodes, oaNode OLEAuto endVar if eventInfo.id() = UserAction+1 then ;// attach to the nodes object oaNodes = treeTest.Nodes ;// clear existing values oaNodes.clear() if not tcMasters.open(":TREE:MASTERS.DB") then errorShow("Couldn't open :TREE:MASTERS.DB") return endIf ;// open details on MasterName index if not tcDetails.open(":TREE:DETAILS.DB", "MasterName") then errorShow("Couldn't open :TREE:DETAILS.DB") tcMasters.close() return endIf ;// add each master scan tcMasters : ;// set range on detail table ;//to show this master's details if not tcDetails.setRange(tcMasters."MasterName") then errorShow("Couldn't set range on " + tcMasters."MasterName") loop endIf ;// add master as parent node ;// by blanking the first two arguments ;// ("" is not allowed, no argument is not allowed) ;// the new node will be added at the end of the list ;// as a top-level node ;// mastername is both key and text to display oaNode = oaNodes.add(blank(), blank(), tcMasters."MasterName", tcMasters."MasterName") oaNode.Bold = True ;// make masters bold scan tcDetails : ;// add details as child nodes ;// relative is the mastername ;// (key from the master we just inserted) ;// relationship (4) is child ;// key and text are the DetailName value oaNodes.add(tcDetails."MasterName", 4, tcDetails."DetailName", tcDetails."DetailName") endScan endScan tcDetails.close() tcMasters.close() endIfExample 2: NOTE: The following example uses a single table (of articles and replies to articles) which contains 1:M master:detail relations within itself by means of two fields: "articlenumber" is a unique identifier for each record; "masteran" is the "articlenumber" value of this record's master - or the article being replied to (blank if no master). This relation is n deep, where n is unknown. var tcMaster, tcDetail TCursor ;// both will point to same table oaNodes OLEAuto ;// the nodes collection endVar oaNodes = treeTest.Nodes oaNodes.clear() if not tcMaster.open(":TREE:ARTICLES.DB") then errorShow("Couldn't open :TREE:ARTICLES.DB") return endIf if not tcDetail.open(":TREE:ARTICLES.DB","masteran") then errorShow("Couldn't open :TREE:ARTICLES.DB") tcMaster.close() return endIf scan tcMaster : ;// if the article has no master - ;// add it as the last node at the main level (default) if isBlank(tcMaster."masteran") then ;// key requires a string - ;// couldn't get it to take string(longIntVal), ;// so I added alpha chars ;// text = subject :: author oaNodes.add(blank(), blank(), string("an",tcMaster."articlenumber"), tcMaster."subject" + " :: " + tcMaster."author") else ;// it's a detail and has been added (as all detail ;// records appear in the table _after_ their master) ;// but it may have details, so we'll add its details endIf tcDetail.setRange(tcMaster."articlenumber", tcMaster."articlenumber") scan tcDetail : ;// add detail linked to master (via master's 'an') ;// as child (4), ;// with its own articlenumber as its key ;// and subject :: author as text oaNodes.add(string("an",tcDetail."masteran"), 4, string("an",tcDetail."articlenumber"), tcDetail."subject" + " :: " + tcDetail."author") endScan endScan tcMaster.close() tcDetail.close() msgInfo("done","done") Conclusion While some of the MS treeview's features aren't available in Paradox, in situations where the best way to display items is in a treeview, the MS treeview is simple to use once you get the basics down. Other TreeViews There are also third-party treeviews available out there. Many of these have multiple columns, making them even more useful than the MS treeview. However, I've found that each has its own limitations in Paradox. Below are some treeviews I've tested in Paradox 10 (please note that earlier version of Paradox aren't quite as cooperative when using OCX controls). UPDATE: Note that Tony McGuire recently discovered a problem with these treeviews (problem found with SftTree/OCX 4.0 and assumed to be in the others); it seems their license information gets compiled into the executable. As Paradox cannot compile an executable, we cannot find a way to use the licensed treeviews in Paradox. So, until/unless someone finds a workaround, or another treeview more Paradox-friendly, we seem to be stuck with the Microsoft treeview. SftTree/OCX 4.0 by Softel vdm, Inc. - this is the one I would recommend and is the only one whose columns seemed workable.
ActiveTreeView and TreeViewX by Infragistics I forget what was wrong with these, but I couldn't get them as far as I got the SftTree OCX AgTreeX by Brew City Software not multi-column, didn't test DataTree by GreenTree Technologies I forget what was wrong with this one. Those are all the ones I tried, or at least considered. Read this article in Italian! (PDF format). Discussion of this article |
![]() Feedback | Paradox Day | Who Uses Paradox | I Use Paradox | Downloads ![]() |
|
![]() The information provided on this Web site is not in any way sponsored or endorsed by Corel Corporation. Paradox is a registered trademark of Corel Corporation. ![]() |
|
![]() Modified: 15 May 2003 Terms of Use / Legal Disclaimer ![]() |
![]() Copyright © 2001- 2003 Paradox Community. All rights reserved. Company and product names are trademarks or registered trademarks of their respective companies. Authors hold the copyrights to their own works. Please contact the author of any article for details. ![]() |
![]() |
|