Today I am discussing how to draw a
tree in a F# Windows Forms application. The first thing you need to know is
what is a tree. A tree is a collection of nodes or items that are
connected to each other in such a way that no cycle or relationships are allowed.
Trees are incredibly useful structures because they allow us to represents
hierarchies and compose complex structures and basic parts and simple
relationships.
If you want to draw a tree you will
define a function drawTree. This function will Take two parameters a graphics
object and the tree you want to draw; like below.
let drawTree (g
: Graphics) t =
In
programming languages trees provide a mechanism for extensibility across many
domains and a container to assist us in sorting, searching, compressing and
processing data in efficient way.
To
implement drawTree first you calculate many constants the function will use
like maxWidth and center. These constants can not be seen by the function
outside the drawTree. You can use them in drawTree's inner function without
having to pass them around parameters. Like below.
// constants that relate to the size and position of
the tree
let
center = g.ClipBounds.Width / 2.0F
let
maxWidth = 32.0F * raise2ToPower (getDepth t)
You
will also break the main function into inner function to make the structure of
tree easy to understand. Like drawLeaf function to Draw the leaf nodes. Like
below.
// function for drawing a leaf node
let
drawLeaf (x : float32) (y : float32) v =
let value = sprintf "%A"
v
let l = g.MeasureString(value, font)
g.DrawString(value, font, brush, x - (l.Width / 2.0F),
y)
If
you want to use connection between nodes than you use connectNodeS method like
below.
// draw a connector between the nodes when necessary
let
connectNodes (x : float32) y p =
match p with
|
Some(px, py) -> g.DrawLine(pen, px, py, x,
y)
| None -> ()
Lastly
for final touch you will use drawTreeInner function that is a recursive
function which do the real work for drawing the tree like below.
// the main function to walk the tree structure
drawing the nodes as we go
let rec
drawTreeInner t d w p =
let x = center - (maxWidth * w)
let y = d * 32.0F
connectNodes
x y p
match t with
|
Node (l, r) ->
g.FillPie(brush, x - 3.0F, y - 3.0F, 7.0F, 7.0F, 0.0F, 360.0F)
let d = (d + 1.0F)
drawTreeInner l d (w + (1.0F / d)) (Some(x, y))
drawTreeInner r d (w - (1.0F / d)) (Some(x, y))
| Leaf v -> drawLeaf x y v
drawTreeInner t 0.0F 0.0F None
Getting
Started
Step
1: First open a new project in F# using
Visual Studio 2010 and give a name to it.

Step
2: Then click on Program.fs file in
solution explorer.

Step
3: Write the below code in Program.fs
window, your Program.fs window will look like below.


open System
open System.Drawing
open System.Windows.Forms
// The tree type
type 'N Tree =
| Node of 'N Tree * 'N Tree
| Leaf of 'N
// The definition of the tee
let tree =
Node(
Node(
Leaf "C#",
Node(Leaf "F#", Leaf "WPF")),
Node(
Node(Leaf "SILVERLIGHT", Leaf "WINFORM"),
Leaf "WEBAPP"))
// A function for finding the maximum depth of a tree
let getDepth A =
let rec
getDepthInner A B =
match A with
|
Node (l, n) ->
max
(getDepthInner l B + 1.0F)
(getDepthInner n B + 1.0F)
| Leaf x -> B
getDepthInner A 0.0F
// Constants required for drawing the form
let brush = new
SolidBrush(Color.Black)
let pen = new
Pen(Color.Black)
let font = new
Font(FontFamily.GenericSerif, 8.0F)
// a useful function for calculating the maximum
number
// of nodes at any given depth
let raise2ToPower (x : float32) =
Convert.ToSingle(Math.Pow(2.0,
Convert.ToDouble(x)))
let drawTree (g : Graphics) t =
// constants that relate to the size and position of
the tree
let
center = g.ClipBounds.Width / 2.0F
let
maxWidth = 32.0F * raise2ToPower (getDepth t)
// function for drawing a leaf node
let
drawLeaf (x : float32) (y : float32) v =
let value = sprintf "%A"
v
let l = g.MeasureString(value, font)
g.DrawString(value, font, brush, x - (l.Width / 2.0F), y
// draw a connector between the nodes when necessary
let
connectNodes (x : float32) y p =
match p with
|
Some(px, py) -> g.DrawLine(pen, px, py, x,
y)
| None -> ()
// the main function to walk the tree structure
drawing the nodes as we go
let
rec drawTreeInner t d w p =
let x = center - (maxWidth * w)
let y = d * 32.0F
connectNodes
x y p
match t with
|
Node (l, r) ->
g.FillPie(brush, x - 3.0F, y - 3.0F, 7.0F, 7.0F, 0.0F, 360.0F)
let d = (d + 1.0F)
drawTreeInner l d (w + (1.0F / d)) (Some(x, y))
drawTreeInner r d (w - (1.0F / d)) (Some(x, y))
| Leaf v -> drawLeaf x y v
drawTreeInner t 0.0F 0.0F None
// create the form object
let form =
let
temp = new Form(WindowState =
FormWindowState.Maximized)
temp.Resize.Add(fun _ ->
temp.Invalidate())
temp.Paint.Add
(fun e ->
e.Graphics.Clip <-
new Region(new
Rectangle(0, 0, temp.Width, temp.Height))
drawTree e.Graphics tree)
temp
Application.Run(form)
Step
4: Now press F5 to execute the code.
Output

Summary
In
this article I have discussed how to draw a Tree in F#.