运行界面如下所示:
//================================code begin=============================//
using System;<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Data;
using System.Windows.Forms;
namespace datalink.userCtrl
{
/// <summary>
/// 实现网络拓扑的自动绘制的自定义控件。
/// </summary>
public class Canvas : System.Windows.Forms.PictureBox
{
/// <summary>
/// Required designer variable.
/// </summary>
// private int netID = -1;
// private int outID = -1;
private int items=0;
private int active_item = 0;
private int hover_item = -1;
public string clickedText = "";
public int clickedIndex = -1;
private const int MAX_ELEMENTS = 255;
private string[] menuitems = new string[MAX_ELEMENTS];
private string[] tags = new string[MAX_ELEMENTS];
private System.Drawing.Point[] item_start = new System.Drawing.Point[MAX_ELEMENTS];
private System.Drawing.Point[] item_end = new System.Drawing.Point[MAX_ELEMENTS];
private ImageList imageList = null;
private Bitmap swImage = new Bitmap("sw.jpg");
private Bitmap hostImage = new Bitmap("host.jpg");
private Bitmap hostHoverImage = new Bitmap("hostHover.jpg");
private Bitmap cloudImage = new Bitmap("cloud.jpg");
private Bitmap hostSelectedImage = new Bitmap("hostSelted.jpg");
private Bitmap hostTitle = new Bitmap("host.ico");
private DataTable dataTab=null;
private FrmFuseResult fuseFrm = new FrmFuseResult();
private string sessionID="";
private Graphics thisG;
Brush bgBrush = Brushes.Chocolate;
Brush fgBrush = Brushes.DarkBlue;
Brush titleBrush = Brushes.White;
//交换机水平间距switch vertical space
private const int svSpace = 150;
//主机(交换机)垂直间距 host vertical space
private const int hvSpace = 120;
//主机与交换机的水平间距
private const int hshSpace = 60;
//主机水平间距
private const int hhSpace = 60;
//主机与交换机连线水平间距
private const int lhSpace = 5;
//主机与交换机连线垂直间距
private const int lvSpace = 10;
//交换机长度
private const int sWidth = 51;
//交换机宽度
private const int sHeight = 26;
//主机长度
private const int hWidth = 36;
//主机宽度
private const int hHeight = 39;
//一个交换机挂接的主机数
private const int hostsInSwitcher = 3;
private int xMoved = 0,yMoved = 0;
bool moved = false;
int itemIndex = 0;
int currentIndex = 0;//已经读到第几个主机。
Pen bchPen = new Pen(Color.Black,2);
Pen bchErasePen = new Pen(Color.White,2);
Pen bonePen = new Pen(Color.Black,2);
Point[] leftPoints = new Point[3];
Point[] rightPoints = new Point[3];
// Point[] hLeftPoints = new Point[3];
// Point[] hRightPoints = new Point[3];
private System.ComponentModel.Container components = null;
public ImageList TabImageList
{
get { return imageList; }
set { imageList = value;}
}
public DataTable DataTab
{
set { dataTab = value;}
}
public Canvas(System.ComponentModel.IContainer container)
{
///
/// Required for Windows.Forms Class Composition Designer support
///
container.Add(this);
InitializeComponent();
//
// TODO: Add any constructor code after InitializeComponent call
//
}
public Canvas()
{
///
/// Required for Windows.Forms Class Composition Designer support
///
InitializeComponent();
//
// TODO: Add any constructor code after InitializeComponent call
//
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
public void add_item()
{
if( items >= MAX_ELEMENTS )
{
MessageBox.Show("超过最多允许显示的按钮数量,请与系统管理员联系", "系统信息",MessageBoxButtons.OKCancel,MessageBoxIcon.Error);
return;
}
item_start[items] = new System.Drawing.Point(0);
item_end[items] = new System.Drawing.Point(0);
items++;
this.Refresh();
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
this.Paint += new System.Windows.Forms.PaintEventHandler(this.Canvas_Paint);
this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.Canvas_MouseMove);
this.MouseLeave += new System.EventHandler(this.Canvas_MouseLeave);
this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.Canvas_MouseDown);
this.MouseUp +=new MouseEventHandler(Canvas_MouseUp);
}
#endregion
private void Canvas_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
{
// if(dataTab != null)
DrawTree(new Point(this.Width/2,this.Height/2),e);
itemIndex = 0;
}
public void DrawTree(Point centerP, System.Windows.Forms.PaintEventArgs e)
{
if(dataTab == null ) return;
items = this.dataTab.Rows.Count;
if(items == 0 ) return;
int switches = items/hostsInSwitcher + 1;//交换机的个数。每个交换机最多挂接hostsInSwitcher个终端
if(items % hostsInSwitcher == 0 ) switches--;
this.Navigate(xMoved,yMoved,e);
Pen outPen = new Pen(Color.Purple,4);
outPen.SetLineCap(LineCap.DiamondAnchor,LineCap.ArrowAnchor,DashCap.Triangle);
e.Graphics.DrawImage(cloudImage,centerP.X-50,centerP.Y -200,150,82);
e.Graphics.DrawLine(outPen,centerP.X +10,centerP.Y,centerP.X+10,centerP.Y -118);
outPen.Dispose();
Point sLeftEndPoint = new Point(centerP.X - 2*svSpace/3,centerP.Y);//中心交换机与边缘交换机间左边第一个转接点
Point sRightEndPoint = new Point(centerP.X + 2*svSpace/3,centerP.Y);//中心交换机与边缘交换机间右边第一个转接点
this.DrawBone(centerP,sLeftEndPoint,e);
// Create array of points that define lines to draw.
Point[] leftPoints =
{
new Point( sLeftEndPoint.X, sLeftEndPoint.Y),//xy都不变
new Point( sLeftEndPoint.X, sLeftEndPoint.Y),//x不变,y与下面点y坐标相同
new Point( centerP.X - svSpace, sLeftEndPoint.Y),//x不变,y与上面点y坐标相同
};
Point[] rightPoints =
{
new Point( sRightEndPoint.X, sRightEndPoint.Y),//xy都不变
new Point( sRightEndPoint.X, sRightEndPoint.Y),//x不变,y与下面点y坐标相同
new Point( centerP.X + svSpace, sRightEndPoint.Y),//x不变,y与上面点y坐标相同
};
int leftSwitches =1;//已经在右边画了多少个交换机数
int rightSwitches = 1;
if(switches > 0)
{
e.Graphics.DrawLines(bonePen, leftPoints);
this.DrawLeftHosts(leftPoints,e);
this.DrawSwitcher(leftPoints[2].X-sWidth,leftPoints[2].Y - sHeight/2,e);
if(switches > 1)
{
this.DrawBone(centerP,sRightEndPoint,e);
e.Graphics.DrawLines(bonePen,rightPoints);
this.DrawRightHosts(rightPoints,e);
this.DrawSwitcher(rightPoints[2].X,rightPoints[2].Y - sHeight/2,e);
}
}
this.DrawSwitcher(centerP.X-sWidth/2,centerP.Y-sHeight/2,e);
//Draw lines to screen.
for(int i=2;i<switches;i++)
{
if(i%2==0)//draw the left part
{
if(leftSwitches % 2 == 0)
leftPoints[1].Y -= hvSpace * leftSwitches;
else
leftPoints[1].Y += hvSpace * leftSwitches;
leftPoints[2].Y = leftPoints[1].Y;
e.Graphics.DrawLines(bonePen, leftPoints);
this.DrawLeftHosts(leftPoints,e);
this.DrawSwitcher(leftPoints[2].X-sWidth,leftPoints[2].Y - sHeight/2,e);
leftSwitches++;
}
else//draw the right part
{
if(rightSwitches % 2 == 0)
rightPoints[1].Y -= hvSpace * rightSwitches;
else
rightPoints[1].Y += hvSpace * rightSwitches;
rightPoints[2].Y = rightPoints[1].Y;
e.Graphics.DrawLines(bonePen,rightPoints);
this.DrawRightHosts(rightPoints,e);
this.DrawSwitcher(rightPoints[2].X,rightPoints[2].Y - sHeight/2,e);
rightSwitches++;
}
}
currentIndex = 0;
}
public void DrawBch(Point fromP,Point toP,int width,System.Windows.Forms.PaintEventArgs e)
{
bchPen.Width = width;
e.Graphics.DrawLine(bchPen,fromP,toP);
}
public void DrawBone(Point fromP,Point toP,System.Windows.Forms.PaintEventArgs e)
{
bonePen.DashStyle = DashStyle.DashDot;
e.Graphics.DrawLine(bonePen,fromP,toP);
}
public void DrawSwitcher(int x,int y,System.Windows.Forms.PaintEventArgs e)
{
e.Graphics.DrawImageUnscaled(swImage,x,y,sWidth,sHeight);
}
public void DrawBaseHost(int x,int y,System.Windows.Forms.PaintEventArgs e,Image i)
{
string hostName = dataTab.Rows[itemIndex]["ip_address"].ToString();
e.Graphics.DrawImageUnscaled(i,x,y,sWidth,sHeight);
// Set world transform of graphics object to translate.
e.Graphics.TranslateTransform(x-30, y-35);
// Then to rotate, appending rotation matrix.
e.Graphics.RotateTransform(<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />20.0F, MatrixOrder.Prepend);
e.Graphics.DrawString(hostName,new Font("Arial", 9),Brushes.Purple,0,0);
e.Graphics.ResetTransform();
this.Navigate(xMoved,yMoved,e);
this.menuitems[itemIndex] = hostName;
this.tags[itemIndex] = dataTab.Rows[itemIndex]["session_id"].ToString();
itemIndex++;
}
public void DrawHost(int x,int y,System.Windows.Forms.PaintEventArgs e)
{
this.DrawBaseHost(x,y,e,this.hostImage);
}
public void DrawHostHover(int x,int y,System.Windows.Forms.PaintEventArgs e)
{
this.DrawBaseHost(x,y,e,this.hostHoverImage);
}
public void DrawHostAtcive(int x,int y,System.Windows.Forms.PaintEventArgs e)
{
this.DrawBaseHost(x,y,e,this.hostSelectedImage);
}
public void DrawRightHosts(Point[] p,System.Windows.Forms.PaintEventArgs e)
{
int hostNum = 0;
for(int j=currentIndex;j<items;j++)
{
hostNum = j-currentIndex;
int spaceToOrgn = (hostsInSwitcher - hostNum ) * hhSpace;
item_start[itemIndex].X = p[2].X + spaceToOrgn +hshSpace-hWidth;
item_start[itemIndex].Y = p[2].Y - sHeight/2;
item_end[itemIndex].X = item_start[itemIndex].X + hWidth;
item_end[itemIndex].Y = item_start[itemIndex].Y + hHeight;
//绘出连接线
e.Graphics.DrawRectangle(bchPen,p[2].X + sWidth - lhSpace * (hostsInSwitcher - hostNum),p[2].Y + sHeight/2,
hshSpace + (lhSpace + hhSpace) * (hostsInSwitcher - hostNum-1),
20 + lvSpace*(hostsInSwitcher - hostNum));
e.Graphics.DrawLine(bchErasePen,p[2].X + sWidth - lhSpace * (hostsInSwitcher - hostNum),p[2].Y + sHeight/2,
p[2].X + sWidth - lhSpace * (hostsInSwitcher - hostNum) + hshSpace + (lhSpace + hhSpace) * (hostsInSwitcher - hostNum-1),
p[2].Y + sHeight/2);
if(active_item == itemIndex)
this.DrawHostAtcive(item_start[itemIndex].X,item_start[itemIndex].Y,e);
else if(hover_item == itemIndex)
this.DrawHostHover(item_start[itemIndex].X,item_start[itemIndex].Y,e);
else
this.DrawHost(item_start[itemIndex].X,item_start[itemIndex].Y,e);
if(hostNum == (hostsInSwitcher-1))
{
currentIndex +=hostsInSwitcher;
break;
}
}
}
public void DrawLeftHosts(Point[] p,System.Windows.Forms.PaintEventArgs e)
{
int hostNum = 0;
for(int j=currentIndex;j<items;j++)
{
hostNum = j-currentIndex;
int spaceToOrgn = (hostsInSwitcher - hostNum ) * hhSpace;
item_start[itemIndex].X = p[2].X - spaceToOrgn - hshSpace;
item_start[itemIndex].Y = p[2].Y - sHeight/2;
item_end[itemIndex].X = item_start[itemIndex].X + hWidth;
item_end[itemIndex].Y = item_start[itemIndex].Y + hHeight;
e.Graphics.DrawRectangle(bchPen,item_start[itemIndex].X + hWidth/2,item_start[itemIndex].Y + hHeight/2,
hshSpace + (lhSpace + hhSpace) * (hostsInSwitcher - hostNum -1 ),
20+lvSpace*(hostsInSwitcher - hostNum ));
e.Graphics.DrawLine(bchErasePen,item_start[itemIndex].X + hWidth/2,item_start[itemIndex].Y + hHeight/2,
item_start[itemIndex].X + hWidth/2 + hshSpace + (lhSpace + hhSpace) * (hostsInSwitcher - hostNum ),
item_start[itemIndex].Y + hHeight/2);
int xPos = item_start[itemIndex].X;
if(active_item == itemIndex)
this.DrawHostAtcive(xPos,item_start[itemIndex].Y,e);
else if(hover_item == itemIndex)
this.DrawHostHover(xPos,item_start[itemIndex].Y,e);
else
this.DrawHost(xPos,item_start[itemIndex].Y,e);
if(hostNum == (hostsInSwitcher-1))
{
currentIndex +=hostsInSwitcher;
break;
}
}
}
private void Navigate(int x,int y,System.Windows.Forms.PaintEventArgs e)
{
if(moved)
e.Graphics.TranslateTransform(x,y);
}
private void Canvas_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
{
bool need_activation;
for(int i=0;i<items;i++)
{
if( (e.X > item_start[i].X && e.Y > item_start[i].Y) &&
(e.X < item_end[i].X && e.Y < item_end[i].Y)
)
{
this.Cursor = System.Windows.Forms.Cursors.Hand;
need_activation = (hover_item!=i);
hover_item = i;
if(need_activation) this.Refresh();
return;
}
}
this.Cursor = System.Windows.Forms.Cursors.Default;
}
private void Canvas_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
// this.Cursor = System.Windows.Forms.Cursors.Cross;
xMoved = e.X;
yMoved = e.Y;
this.clickedText = "";
active_item = hover_item;
for(int i=0;i<items;i++)
{
if( (e.X > item_start[i].X && e.Y > item_start[i].Y) &&
(e.X < item_end[i].X && e.Y < item_end[i].Y)
)
{
// childs[i].Activate();
clickedText = menuitems[i];
clickedIndex = i;
active_item = i;
this.sessionID = tags[i];
this.Refresh();
ShowTips(e.X,e.Y);
return;
}
}
}
private void ShowTips(float xPos, float yPos)
{
thisG = this.CreateGraphics();
float tipWidth = 250,tipHeight = 150;//信息提示窗口的大小。
int m = 0;
float x = xPos,y=yPos;
string[] values = new string[3];
fuseFrm.FillBaseInfo(sessionID,ref values);
Font tipF = new Font("Arial", 9);
values[0] = "计算机名:" + values[0];
values[1] = "地理位置:" + values[1];
values[2] = "机构名称:" + values[2];
string[] values2 = new string[3]{"","",""};
fuseFrm.FillOS(sessionID,ref values2);
values2[0] = "操作系统:" + values2[0];
SizeF size = thisG.MeasureString(values[0],tipF);
//计算出提示框的大小
for(int i=0;i<3;i++)
{
size = thisG.MeasureString(values2[i],tipF);
if(size.Width > tipWidth) tipWidth = size.Width;
size = thisG.MeasureString(values[i],tipF);
if(size.Width > tipWidth ) tipWidth = size.Width;
}
if(values2[1] != "") tipHeight += size.Height;
if(values2[2] != "") tipHeight += size.Height;
//根据鼠标点位置确定提示框显示的位置
if(this.Width - xPos < tipWidth)
{
xPos -= tipWidth;
}
if(this.Height - yPos < tipHeight)
{
yPos =yPos - tipHeight -25 ;
}
yPos += 25;
Bitmap map = new Bitmap(Convert.ToInt32(tipWidth),Convert.ToInt32(tipHeight));
Graphics g = Graphics.FromImage(map);
x = xPos ;
y = yPos ;
xPos=yPos=0;
// map.MakeTransparent(Color.DarkRed);
//绘出背景框
g.DrawRectangle(Pens.Black,xPos -2,yPos-2,tipWidth+4,tipHeight+4);
g.FillRectangle(bgBrush,xPos,yPos,tipWidth,tipHeight);
//文字缩进设置
xPos +=3;
yPos +=3;
//绘出标题
g.FillRectangle(Brushes.DarkRed,xPos-2,yPos - 2,tipWidth -2,size.Height +4 );
g.DrawLine(Pens.Black,xPos,yPos + size.Height + 2,xPos + tipWidth -4,yPos + size.Height + 2);
g.DrawRectangle(new Pen(Color.DarkRed,2),xPos-2,yPos - 2,tipWidth -2,tipHeight-2);
Font titleFont = new Font("Arial",10,FontStyle.Bold);
g.DrawImage(hostTitle,xPos,yPos,size.Height,size.Height);
g.DrawString(this.clickedText,titleFont,titleBrush,xPos + size.Height,yPos); m += 4;
titleFont.Dispose();
yPos +=4;
g.DrawString(values[0],tipF,fgBrush,xPos,yPos + m * size.Height/3); m += 4;
g.DrawString(values[1],tipF,fgBrush,xPos,yPos + m * size.Height/3); m += 4;
g.DrawString(values[2],tipF,fgBrush,xPos,yPos + m * size.Height/3); m += 4;
g.DrawString(values2[0],tipF,fgBrush,xPos,yPos + m * size.Height/3);m += 4;
if(values2[1] != "")
{
values2[1] = ">>> " + values2[1];
g.DrawString(values2[1],tipF,fgBrush,xPos,yPos + m * size.Height/3); m += 4;
if(values2[2] != "")
{
values2[2] = ">>> " + values2[2];
g.DrawString(values2[2],tipF,fgBrush,xPos,yPos + m * size.Height/3); m += 4;
}
}
string vuls = "漏洞数目:" + fuseFrm.GetVulCount(sessionID).ToString();
g.DrawString(vuls,tipF,fgBrush,xPos,yPos + m * size.Height/3); m += 4;
string ports = "开放端口:" + fuseFrm.GetPortCount(sessionID).ToString();
g.DrawString(ports,tipF,fgBrush,xPos,yPos + m * size.Height/3);
map.MakeTransparent(Color.Cornsilk);
thisG.DrawImage(map,x-2,y-2);
thisG.Dispose();
tipF.Dispose();
g.Dispose();
}
private void Canvas_MouseLeave(object sender, System.EventArgs e)
{
hover_item = -1;
this.Refresh();
}
private void Canvas_MouseUp(object sender, MouseEventArgs e)
{
}
}
}
调用方法如下:
private datalink.userCtrl.Canvas myCanvas;
this.myCanvas.BackColor = System.Drawing.SystemColors.ActiveCaptionText;
this.myCanvas.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
this.myCanvas.Dock = System.Windows.Forms.DockStyle.Fill;
this.myCanvas.Location = new System.Drawing.Point(211, 44);
this.myCanvas.Name = "myCanvas";
this.myCanvas.Size = new System.Drawing.Size(581, 380);
this.myCanvas.TabIndex = 5;
this.myCanvas.TabStop = false;
this.myCanvas.DoubleClick +=new EventHandler(myCanvas_DoubleClick);
for(int i=0;i<45;i++)
{
this.myCanvas.add_item();
}
this.myCanvas.DataTab = ds.Tables[0];