[原創]《C#高級GDI+實戰:從零開發一個流程圖》第08章:增加菱形、平行四邊形、圓角矩形,文本居中顯示
一、前言
前面的課程我們已經完成了形狀和連線的抽象,并獨立出了畫布控件,基礎已經打好,下面就要添磚加瓦了。我們本節課程就來添加一些不同的形狀,如:菱形、平行四邊形、圓角矩形等。而且我們前面發現形狀內的文本都不是居中顯示的,我們也順便優化下。
相信看完的你,一定會有所收獲!
本文地址:http://www.rzrgm.cn/lesliexin/p/18997090
二、先看效果
我們可以看到添加了不同的形狀,且都支持拖動、連線。
看完本篇的代碼,我們會發現實現起來很簡單,只需要給繼承形狀基類實現下就行了,主程序只是添加個控件、生成個形狀類,調用畫布的添加形狀方法就行了。
所以本節的課程重點在于如何去用GDI+“畫”出這些形狀。
三、菱形
像菱形及本文中的形狀,就沒有現在的GDI+方法來實現了,只能通過各個子方法來組合繪制出想要的形狀。
我們先看下圖的菱形圖示:

我們的所做的就是依次繪制菱形的四個邊,這四個頂點的坐標怎么來的呢?
我們在前面的抽象出形狀基類那節講過,屬性Rect是指示形狀所在的矩形區域,所以我們就要在這個矩形區域內,指定4個頂點并計算出坐標。
當有了坐標后,我可以使用GDI+的AddPolygon方法來將多個坐標點添加成一個多邊形,其MSDN的解釋如下:

最后使用GDI+的FillPath將此多邊形繪制出來,具體的代碼如下:

四、平行四邊形
同菱形,我們也是使用類似的方法求出四個頂點的坐標,這里我們將傾斜距離設置為1/5的寬度:

代碼定義里直接按圖示取值即可:

五、圓角矩形
圓角矩形就和上面的兩個形狀不一樣了,因為不再是由直線組成,而是要有弧度:

這里要使用一個新的GDI+方法:AddArc,添加一段弧線,其MSDN的解釋如下:

注意看最下面那段話:
如果圖中有上一條直線或曲線,則會添加一條線,用于將上一段的端點連接到弧線的開頭。
所以我們并不需要添加4條直線4個弧線,只需要添加4個弧線就行了,我們暫時將弧線所在圓的直徑固定為20。
其中:
1,左上角

2,右上角

3,右下角

4,左下角

我們參照上圖的坐標及角度編寫代碼即可:

六、文本居中顯示
上面的形狀實現后,我們會發現文本位置都不統一,我們下面就來讓文本統一居中顯示。
核心是使用GDI+的DrawString的一個重載方法:

我們像下面這樣寫就能讓文本居中顯示:

關于StringFormat的詳細講解,請參照教程:
http://www.rzrgm.cn/lesliexin/p/12879270.html
具體的代碼改造如下,不再贅述:
點擊查看代碼
/// <summary>
/// 菱形定義
/// </summary>
public class LozengeShapeV2 : ShapeBase
{
public override void Draw(Graphics g)
{
var x2 = Rect.X;
var y2 = Rect.Y;
var w2 = Rect.Width;
var h2 = Rect.Height;
var x = x2 + w2 / 2;
var y = y2 + h2 / 2;
//左-上-右-下
var r0 = new Point(x2, y);
var r1 = new Point(x, y2);
var r2 = new Point(x2 + w2, y);
var r3 = new Point(x, y2 + h2);
var path = new GraphicsPath();
path.Reset();
path.AddPolygon(new Point[]{ r0,r1,r2,r3});
path.CloseFigure();
g.FillPath(new SolidBrush(BackgroundColor), path);
g.DrawString(Text, TextFont, new SolidBrush(FontColor), Rect,
new StringFormat() { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center });
}
}
/// <summary>
/// 平行四邊形定義
/// </summary>
public class ParallelogramShapeV2 : ShapeBase
{
public override void Draw(Graphics g)
{
var x2 = Rect.X;
var y2 = Rect.Y;
var w2 = Rect.Width;
var h2 = Rect.Height;
var f = w2 / 5;
//左-上-右-下
var r0 = new Point(x2 + f, y2);
var r1 = new Point(x2 + w2, y2);
var r2 = new Point(x2 + w2 - f, y2 + h2);
var r3 = new Point(x2, y2 + h2);
var path = new GraphicsPath();
path.Reset();
path.AddPolygon(new Point[]{ r0,r1,r2,r3});
path.CloseFigure();
g.FillPath(new SolidBrush(BackgroundColor), path);
g.DrawString(Text, TextFont, new SolidBrush(FontColor), Rect,
new StringFormat() { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center });
}
}
/// <summary>
/// 圓角矩形定義
/// </summary>
public class RoundRectShapeV2 : ShapeBase
{
public override void Draw(Graphics g)
{
float diameter = 20;
var path = new GraphicsPath();
path.Reset();
RectangleF arc = new RectangleF(Rect.X, Rect.Y, diameter, diameter);
// 左上角
path.AddArc(arc, 180, 90);
// 右上角
arc.X = Rect.Right - diameter;
path.AddArc(arc, 270, 90);
// 右下角
arc.Y = Rect.Bottom - diameter;
path.AddArc(arc, 0, 90);
// 左下角
arc.X = Rect.Left;
path.AddArc(arc, 90, 90);
path.CloseFigure();
g.FillPath(new SolidBrush(BackgroundColor), path);
g.DrawString(Text, TextFont, new SolidBrush(FontColor), Rect,
new StringFormat() { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center });
}
}
七、添加形狀方法抽象出泛型方法
我們看之前添加矩形和圓形的方法:

會發現很類似,類似是因為矩形和圓形都是形狀基類的實現,那么我們本節課程添加了這三個新的形狀,再這樣寫就太繁瑣了,我們直接抽象出一個泛型方法來解決此問題:

可以看到,就是將生成矩形和圓形的方法使用泛型替代。
我們再寫一個泛型方法來將形狀添加到畫布:

好了,到此我們的代碼就進一步簡化了,添加不同形狀只需要傳入對應的形狀類型就行了:

是不是很優雅~
完整代碼如下,大家可自行嘗試:
點擊查看代碼
using Elements;
using Elements.Links;
using Elements.Shapes;
using FlowChartCanvas;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace FlowChartDemo
{
public partial class FormDemo07V4 : FormBase
{
public FormDemo07V4()
{
InitializeComponent();
DemoTitle = "第09節隨課Demo Part4";
DemoNote = "效果:所有形狀內文本居中顯示。";
//添加畫布控件
_fcc = new FCCanvasV1();
_fcc.FCC_LinkColor += _fcc_FCC_LinkColor;
_fcc.FCC_LinkState += _fcc_FCC_LinkState;
_fcc.Dock = DockStyle.Fill;
panel1.Controls.Add(_fcc);
}
private void _fcc_FCC_LinkState(string obj)
{
toolStripStatusLabel1.Text = obj;
}
private Color _fcc_FCC_LinkColor()
{
return GetColor(_linkColorIndex++);
}
FCCanvasV1 _fcc;
/// <summary>
/// 形狀顏色序號
/// </summary>
int _shapeColorIndex = 0;
/// <summary>
/// 連線顏色序號
/// </summary>
int _linkColorIndex = 0;
/// <summary>
/// 獲取不同的背景顏色
/// </summary>
/// <param name="i"></param>
/// <returns></returns>
Color GetColor(int i)
{
switch (i)
{
case 0: return Color.Red;
case 1: return Color.Green;
case 2: return Color.Blue;
case 3: return Color.Orange;
case 4: return Color.Purple;
default: return Color.Red;
}
}
//注:文章中說明:再次抽象
/// <summary>
/// 創建形狀
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="shapeText"></param>
/// <returns></returns>
T CreateShape<T>(string shapeText) where T:ShapeBase
{
var t = Activator.CreateInstance<T>();
t.Id = shapeText + Guid.NewGuid().ToString();
t.Rect = new Rectangle()
{
X = 50,
Y = 50,
Width = 100,
Height = 100,
};
t.FontColor = Color.White;
t.BackgroundColor = GetColor(_shapeColorIndex++);
t.Text = shapeText + _shapeColorIndex;
t.TextFont = Font;
return t;
}
/// <summary>
/// 創建指定類型的形狀并添加到當前流程圖畫布中。
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="shapeText"></param>
void CreateShapeAndAddToFCCanvas<T>(string shapeText) where T : ShapeBase
{
var sp = CreateShape<T>(shapeText);
_fcc.FCC_AddShapes(new List<ShapeBase>() { sp });
_fcc.FCC_Refresh();
}
private void toolStripButton1_Click(object sender, EventArgs e)
{
CreateShapeAndAddToFCCanvas<RectShapeV2>("矩形");
}
private void toolStripButton4_Click(object sender, EventArgs e)
{
CreateShapeAndAddToFCCanvas<EllipseShapeV2>("圓形");
}
private void toolStripButton5_Click(object sender, EventArgs e)
{
CreateShapeAndAddToFCCanvas<LozengeShapeV2>("菱形");
}
private void toolStripButton6_Click(object sender, EventArgs e)
{
CreateShapeAndAddToFCCanvas<ParallelogramShapeV2>("平行四邊形");
}
private void toolStripButton7_Click(object sender, EventArgs e)
{
CreateShapeAndAddToFCCanvas<RoundRectShapeV2>("圓角矩形");
}
private void toolStripButton2_Click(object sender, EventArgs e)
{
_fcc.FCC_StartLink();
}
private void toolStripButton3_Click(object sender, EventArgs e)
{
_fcc.FCC_StopLink();
}
}
}
八、結語
我們本節課添加了多個不同的形狀,這些形狀也是流程圖中常用的形狀,有了這些基礎,用戶可按自己的需求添加自己的形狀。當然現在的形狀屬性還很少,會隨著課程的深入而豐富,以支持更多效果。
我們還抽象出一泛型方法來簡化添加形狀的操作,使用起來很是優雅。
現在基本的形狀都有了,我們下節課就來添加新的連線:貝塞爾曲線,這個幾乎是最常見的曲線。
同時,有了新的連線,我們還會增加不同的連接點用來連線,而不再只連接形狀的中心點。
敬請期待。
感謝大家的觀看,本人水平有限,文章不足之處歡迎大家評論指正。
-[END]-

浙公網安備 33010602011771號