玩轉(zhuǎn)控件:GDI+動(dòng)態(tài)繪制流程圖
- 前言
今天,要跟大家一起分享是“GDI+動(dòng)態(tài)生成流程圖”的功能。別看名字高大上(也就那樣兒--!),其實(shí)就是動(dòng)態(tài)生成控件,然后GDI+繪制直線連接控件罷了。實(shí)際項(xiàng)目效果圖如下:

- Talk is Cheap,Show me the Code
首先,人靠衣裝馬靠鞍!在繪制流程圖之前,我們得有個(gè)高大上的背景來襯托,比如網(wǎng)格背景:

代碼如下:
/// <summary>
/// 初始化網(wǎng)格
/// </summary>
private void InitGridLine()
{
pictureBox1.BorderStyle = BorderStyle.Fixed3D;
pictureBox1.Focus();
m_picture = pictureBox1.CreateGraphics();
Bitmap canvas = new Bitmap(pictureBox1.Width, pictureBox1.Height);
Graphics gp = Graphics.FromImage(canvas);
DrawGrid(gp);
pictureBox1.BackgroundImage = canvas;
pictureBox1.Refresh();
}
//繪制網(wǎng)格
private void DrawGrid(Graphics gp)
{
for (int i = 0; i < Row; i++)
{
gp.DrawLine(new Pen(Color.LightCyan), (i + 1) * pictureBox1.Width / Row, 0, (i + 1) * pictureBox1.Width / Row, pictureBox1.Height);
}
for (int i = 0; i < colums; i++)
{
gp.DrawLine(new Pen(Color.LightCyan), 0, (i + 1) * pictureBox1.Height / colums, pictureBox1.Width, (i + 1) * pictureBox1.Height / colums);
}
}
我們此處以PictureBox為畫布,初始化好網(wǎng)格背景后,就可以開始創(chuàng)建流程標(biāo)簽了,效果如下:

代碼如下:
/// <summary>
/// 繪制元素,此處以Label為例
/// </summary>
/// <returns></returns>
private Label createBlock(string lblName)
{
try
{
Label label = new Label();
label.AutoSize = false;
//TODO:如需動(dòng)態(tài)生成每個(gè)標(biāo)簽元素位置,請(qǐng)根據(jù)實(shí)際情況,初始化標(biāo)簽的Location即可。此處默認(rèn)X=150,Y 以75間隔遞增
label.Location = new Point(150, iPosition);
iPosition = iPosition + 75;
label.Size = new Size(89, 36);
label.BackColor = Color.DarkOliveGreen;
label.ForeColor = Color.Black;
label.FlatStyle = FlatStyle.Flat;
label.TextAlign = ContentAlignment.MiddleCenter;
label.Text = lblName;
//TODO;可以綁定標(biāo)簽元素的右鍵事件
//label.ContextMenuStrip = contextBlock;
pictureBox1.Controls.Add(label);
//拖拽移動(dòng)
MoveBlock(label);
return label;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
return null;
}
實(shí)現(xiàn)動(dòng)態(tài)生成的標(biāo)簽拖拽移動(dòng)效果,方法如下:
//標(biāo)簽移動(dòng)效果
private void MoveBlock(Label block, Label endBlock = null)
{
block.MouseDown += (ss, ee) =>
{
if (ee.Button == System.Windows.Forms.MouseButtons.Left)
fPoint = Control.MousePosition;
};
block.MouseMove += (ss, ee) =>
{
if (ee.Button == System.Windows.Forms.MouseButtons.Left)
{
Point temp = Control.MousePosition;
Point res = new Point(fPoint.X - temp.X, fPoint.Y - temp.Y);
block.Location = new Point(block.Location.X - res.X,
block.Location.Y - res.Y);
fPoint = temp;
pictureBox1.Invalidate(); // <------- draw the new lines
}
};
}
生成好背景網(wǎng)格和標(biāo)簽,以及實(shí)現(xiàn)標(biāo)簽的拖拽后,就需要繪制直線按自己需求,實(shí)現(xiàn)連接了。本文我們用 Tuple 來實(shí)現(xiàn)兩個(gè)標(biāo)簽的連接關(guān)系。
//用于存儲(chǔ)需要直線連接的元素 List<Tuple<Label, Label>> lines = new List<Tuple<Label, Label>>();
綁定PictureBox的Paint事件,利用GDI+的DrawLine實(shí)現(xiàn)繪制直線。
private void PictureBox1_Paint(object sender, PaintEventArgs e)
{
foreach (Tuple<Label, Label> t in lines)
{
Point p1 = new Point(t.Item1.Left + t.Item1.Width / 2,
t.Item1.Top + t.Item1.Height / 2);
Point p2 = new Point(t.Item2.Left + t.Item2.Width / 2,
t.Item2.Top + t.Item2.Height / 2);
e.Graphics.DrawLine(Pens.Black, p1, p2);
}
}
好了,所有工作都已完成,此時(shí),只需要把想要連接的兩個(gè)標(biāo)簽添加到當(dāng)前集合中,即可完成直線的連接功能。效果如圖

參考文獻(xiàn):
https://docs.microsoft.com/zh-cn/dotnet/api/system.tuple-2?view=netcore-3.1
https://stackoverflow.com/questions/31626027/how-to-connect-with-line-shapes-labels-on-runtime/31642448#31642448?newreg=de162494b077460383555e4da76bdd18
- 結(jié)束語
由于后續(xù)所有重寫/重繪控件都在同一個(gè)項(xiàng)目使用,而且Dev系統(tǒng)引用文件較多,壓縮后源碼文件仍然很大,如果有需要源碼的朋友,可以微信公眾號(hào)回復(fù):erp,即可獲取Fucking ERP所有源碼示例~!有疑問的也可以CALL我一起探討。
最后,感謝您的耐心陪伴!如果覺得本篇博文對(duì)您或者身邊朋友有幫助的,麻煩點(diǎn)個(gè)關(guān)注!贈(zèng)人玫瑰,手留余香,您的支持就是我寫作最大的動(dòng)力,感謝您的關(guān)注,期待和您一起探討!再會(huì)!
作者:Stephen-kzx
出處:http://www.rzrgm.cn/axing/
公眾號(hào):會(huì)定時(shí)分享寫工作中或者生活中遇到的小游戲和小工具源碼。有興趣的幫忙點(diǎn)下關(guān)注!感恩!
本文版權(quán)歸作者和博客園共有,歡迎轉(zhuǎn)載,但未經(jīng)作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責(zé)任的權(quán)利。

浙公網(wǎng)安備 33010602011771號(hào)