<< Prev | - Up - | Next >> |
The following examples describes how to use the TreeNode
class with Tk and QTk. The last example shows how an application can take full control over the tree.
declare
[Tree]={Module.link ["Tree.ozf"]}
TreeNode=Tree.treeNode
T={New Tk.toplevel tkInit}
C={New Tk.canvas tkInit(parent:T)}
{Tk.send pack(C)}
RootNode={New TreeNode init(canvas:C
font:"Helvetica 10"
height:18
label:"Node"
)}
{RootNode draw(x:2 y:2 height:_)}
proc{AddNodes Node Nu}
Label={Node get(label:$)}
in
{List.forAllInd {List.make Nu}
proc{$ I _}
NewNode={New TreeNode init(parent:Node
label:Label#" "#I)}
in
{Node addLeaf(node:NewNode)}
{AddChildren NewNode Nu-1}
end}
end
{AddNodes RootNode 5}
{RootNode expand}
The root node of the tree is an instance of TreeNode
where the canvas parameter has been set. As shown in the example, a font can be specified by the font
parameter. Each node of the tree will take the height that is the height of the font used to display the label of node, unless the height
parameter force another value. The label parameter sets the text displayed in the node.
Once the root node is created, it is not yet shown in the canvas. You must explicitly specify where you want to display this node the calling the method show
, hence :
{RootNode draw(x:2 y:2 height:_)}
The tree parameters x
, y
and height
are required. The first two corresponds to the position where to place the top left corner of the node. The height
parameter binds the specified variable to the height taken to draw the whole node (including subnodes if needed). In this case, this value can be ignored, hence _
.
The procedure AddNodes
recursively add nodes to a node. Adding a node is done in two steps :
Creating a new instance of the TreeNode
class. The initialisation parameters are somewhat different from the root node. The parent
parameter specifies the parent node. The canvas
, font
and height
parameters of the root node of the tree MUST NOT and CAN'T be specified for all other nodes of the tree. The font and height used by nodes are therefore the same for the whole tree.
Adding the new created node to the parent node. This is done by calling the addLeaf
method of the parent node : {Node addLeaf(node:NewNode)}
.
declare
[Tree QTk]={Module.link ["Tree.ozf" "http://www.info.ucl.ac.be/people/ned/qtk/QTk.ozf"]}
TreeNode=Tree.treeNode
C
{{QTk.build td(canvas(glue:nswe
handle:C
tdscrollbar:true
lrscrollbar:true))} show}
RootNode={New TreeNode init(canvas:C
font:{QTk.newFont font(family:"Helvetica" size:10)}
height:18
label:"Node"
)}
{RootNode draw(x:2 y:2 height:_)}
proc{AddChildren Node Nu}
Label={Node get(label:$)}
in
{List.forAllInd {List.make Nu}
proc{$ I _}
NewNode={New TreeNode init(parent:Node
label:Label#" "#I)}
in
{Node addLeaf(node:NewNode)}
{AddChildren NewNode Nu-1}
end}
end
{AddChildren RootNode 5}
{RootNode expand}
As shown in this example, only the way of building the window is changed. Warning : there is no parameter checking in the TreeNode
as is in QTk. If you use an invalid value for the underlying toolkit, the error will not be raised at the Oz level, but will appear at the standard error as a Tcl/Tk error.
This example will show how to bind events to user clicks on the nodes, how to manage a selection rectangle and how to make to tree be calculated lazily as the user expands the different nodes.
declare
[Tree QTk]={Module.link ["Tree.ozf" "http://www.info.ucl.ac.be/people/ned/qtk/QTk.ozf"]}
TreeNode=Tree.treeNode
C
{{QTk.build td(canvas(glue:nswe
handle:C
tdscrollbar:true
lrscrollbar:true))} show}
class CustomNode
from TreeNode
feat
calc
current:{NewCell unit}
meth init(...)=M
TreeNode,M
{self bind(event:"<1>"
action:self#SelectNode)}
end
meth SelectNode
if {Access self.current}\=unit then
{{Access self.current} select(state:false)}
end
if {Access self.current}==self then
{self switch}
end
{Assign self.current self}
{self select(state:true)}
end
meth expand(...)=M
if {IsFree self.calc} then
Label={self get(label:$)}
in
{self addLeaf(
nodes:{List.map ["a" "b" "c" "d"]
fun{$ C}
{New CustomNode init(parent:self
label:Label#" "#C)}
end})}
self.calc=unit
end
TreeNode,M
end
end
CurrentNode={NewCell unit}
RootNode={New CustomNode init(canvas:C
font:"Helvetica 10"
height:18
label:"Node"
)}
{RootNode draw(x:2 y:2 height:_)}
{RootNode expand}
Overloading the TreeNode
class allows to take full control of the tree. The bind
call in the init
method defines a method to be called when the user left clicks on the node. A node can be marked as selected by calling the method select(state:true)
. CustomNode
uses a shared feature called current
to store which node is currently selected. The selectNode
method, that is called when the user clicks on the node, checks to see if a node was previously selected to remove its selection rectangle (select(state:false)
), and mark the clicked node as selected, storing this information in self.current
. Moreover, if the user clicks several times the same node, it automatically switch between the states expanded and collapsed thanks to a call to the switch
method.
The expand
method is overloaded so that children nodes are computed on-the-fly. The first time the node tries to expand itself, the calc
feature is not yet bound. The children are then computed and added and calc
is bound to unit
.
<< Prev | - Up - | Next >> |