//
基本原理:
//
1. 从下往上计算位置
//
2. 模仿Word中组织结构图的特点
//
调用代码:
Tree
<
string
> tree =
new
Tree<
string
>(
null
,
"
董事会
"
);
tree.Add(
"
北京公司
"
);
tree.Add(
"
董事秘书室特殊机构
"
);
tree.Add(
"
上海公司
"
);
tree.Childs[
0
].Add(
"
总经理办公室
"
);
tree.Childs[
0
].Add(
"
财务部
"
);
tree.Childs[
0
].Add(
"
销售部
"
);
tree.Childs[
2
].Add(
"
上海销售部
"
);
Bitmap bmp
=
tree.DrawAsImage();
//
实现代码:
using
System;
using
System.Collections.Generic;
using
System.Text;
using
System.Drawing;
namespace
Test
{
///
<summary>
///
用来输出组织结构图的类
///
</summary>
///
<typeparam name="T"></typeparam>
public
class
Tree<T>
{
Tree
<T> _Parent =
null
;
T _Content;
List
<Tree<T>> _Childs =
new
List<Tree<T>>
();
SizeF _Size;
Rectangle _Rec;
public
Tree(Tree<T>
parent, T content)
{
_Parent
=
parent;
_Content
=
content;
}
public
Tree<T>
Add(T content)
{
Tree
<T> tree =
new
Tree<T>(
this
, content);
_Childs.Add(tree);
return
tree;
}
public
Tree<T> Parent {
get
{
return
_Parent; } }
public
T Content {
get
{
return
_Content; } }
public
List<Tree<T>> Childs {
get
{
return
_Childs; } }
public
SizeF Size {
get
{
return
_Size; }
set
{ _Size =
value; } }
public
Rectangle Rec {
get
{
return
_Rec; }
set
{ _Rec =
value; } }
void
MeatureAllSize(Graphics g, Font font,
int
addWidth)
{
_Size
=
g.MeasureString(_Content.ToString(), font);
_Size.Width
+=
addWidth;
foreach
(Tree<T> tree
in
Childs)
tree.MeatureAllSize(g, font, addWidth);
}
List
<List<Tree<T>>>
GetTreeLayers()
{
List
<List<Tree<T>>> layers =
new
List<List<Tree<T>>>
();
GetTreeLayers(layers,
new
List<Tree<T>>(
new
Tree<T>[] {
this
}),
0
);
return
layers;
}
void
GetTreeLayers(List<List<Tree<T>>> layers, List<Tree<T>> childs,
int
level)
{
if
(childs.Count ==
0
)
return
;
if
(layers.Count <= level) layers.Add(
new
List<Tree<T>>
());
for
(
int
i =
0
; i < childs.Count; i++
)
{
layers[level].Add(childs[i]);
GetTreeLayers(layers, childs[i].Childs, level
+
1
);
}
}
///
<summary>
///
设置显示区域(从最后一层最左开始)
///
</summary>
///
<param name="level"></param>
///
<param name="height"></param>
///
<param name="interval"></param>
///
<param name="left"></param>
void
SetRectangle(
int
level,
int
height,
int
hInterval,
int
vInterval,
int
left)
{
int
index =
0
;
if
(Parent !=
null
) index = Parent.Childs.IndexOf(
this
);
if
(Childs.Count ==
0
)
{
//
没有儿子,就向前靠
if
(left >
0
) left +=
hInterval;
}
else
{
//
有儿子,就在儿子中间
int
centerX = (Childs[
0
].Rec.Left + Childs[Childs.Count -
1
].Rec.Right) /
2
;
left
= centerX - (
int
)_Size.Width /
2
;
//
并且不能和前面的重复,如果重复,联同子孙和子孙的右边节点右移
if
(Parent !=
null
&& index >
0
)
{
int
ex = (Parent.Childs[index -
1
].Rec.Right + hInterval) -
left;
if
(index >
0
&& ex >
0
)
{
for
(
int
i = index; i < Parent.Childs.Count; i++
)
Parent.Childs[i].RightChilds(ex);
left
+=
ex;
}
}
}
_Rec
=
new
Rectangle(left, (height + vInterval) * level, (
int
)_Size.Width, height);
}
///
<summary>
///
所有子孙向右平移
///
</summary>
///
<param name="ex"></param>
void
RightChilds(
int
ex)
{
Rectangle rec;
for
(
int
i =
0
; i < _Childs.Count; i++
)
{
rec
=
_Childs[i].Rec;
rec.Offset(ex,
0
);
_Childs[i].Rec
=
rec;
_Childs[i].RightChilds(ex);
}
}
void
Offset(
int
x,
int
y)
{
_Rec.Offset(x, y);
for
(
int
i =
0
; i < _Childs.Count; i++
)
_Childs[i].Offset(x, y);
}
public
Bitmap DrawAsImage()
{
return
DrawAsImage(Pens.Black,
new
Font(
"
宋体
"
,
10.5f
),
26
,
20
,
5
,
20
,
26
);
}
public
Bitmap DrawAsImage(Pen pen, Font font,
int
h,
int
horPadding,
int
horInterval,
int
verInterval,
int
borderWidth)
{
Bitmap bmp
=
new
Bitmap(
1
,
1
);
Graphics g
=
Graphics.FromImage(bmp);
//
把树扁平化
List<List<Tree<T>>> layers =
GetTreeLayers();
//
算出每个单元的大小
MeatureAllSize(g, font, horPadding);
g.Dispose();
bmp.Dispose();
//
从最后一层开始排列
int
left =
0
;
for
(
int
i = layers.Count -
1
; i >=
0
; i--
)
{
for
(
int
j =
0
; j < layers[i].Count; j++
)
{
layers[i][j].SetRectangle(i, h, horInterval, verInterval, left);
left
=
layers[i][j].Rec.Right;
}
}
Offset(borderWidth, borderWidth);
//
获取画布需要的大小
int
maxHeight = (h + verInterval) * layers.Count - verInterval + borderWidth *
2
;
int
maxWidth =
0
;
for
(
int
i = layers.Count -
1
; i >=
0
; i--
)
{
for
(
int
j =
0
; j < layers[i].Count; j++
)
{
if
(layers[i][j].Rec.Right >
maxWidth)
maxWidth
=
layers[i][j].Rec.Right;
}
}
maxWidth
+= borderWidth;
//
边宽
//
画
bmp =
new
Bitmap(maxWidth, maxHeight);
g
=
Graphics.FromImage(bmp);
g.Clear(Color.White);
StringFormat format
=
(StringFormat)StringFormat.GenericDefault.Clone();
format.Alignment
=
StringAlignment.Center;
format.LineAlignment
=
StringAlignment.Center;
Rectangle rec, recParent;
for
(
int
i =
0
; i < layers.Count; i++
)
{
for
(
int
j =
0
; j < layers[i].Count; j++
)
{
//
画字
rec =
(Rectangle)layers[i][j].Rec;
g.DrawRectangle(pen, rec);
g.DrawString(layers[i][j].Content.ToString(), font,
new
SolidBrush(pen.Color),
rec, format);
//
画到父亲的线
if
(layers[i][j].Parent !=
null
)
{
recParent
=
layers[i][j].Parent.Rec;
g.DrawLine(pen, rec.Left
+ rec.Width /
2
, rec.Top,
rec.Left
+ rec.Width /
2
, rec.Top - verInterval /
2
);
g.DrawLine(pen, recParent.Left
+ recParent.Width /
2
, recParent.Bottom,
recParent.Left
+ recParent.Width /
2
, rec.Top - verInterval /
2
);
g.DrawLine(pen, rec.Left
+ rec.Width /
2
, rec.Top - verInterval /
2
,
recParent.Left
+ recParent.Width /
2
, rec.Top - verInterval /
2
);
}
}
}
g.Flush();
g.Dispose();
return
bmp;
}
}
}

