[原創]《C#高級GDI+實戰:從零開發一個流程圖》第04章:來個圓形,連線它!
一、前言
上一節我們實現了在矩形與矩形之間添加連線,光是矩形太單調了,某些問題也暴露不出來,我們本節就來看一下,如何添加一個圓形,且支持圓形與圓形、圓形與矩形、矩形與矩形間的連線。在這個過程中我們會發現一些問題,這些問題我們后續課程會進行處理,大家也請帶著自己的思考和理解去看。
相信看完的你,一定會有所收獲!
本文地址:http://www.rzrgm.cn/lesliexin/p/18923109
二、先看效果
我們先來看一下本節課整體要實現的效果,先有個整體印象。
特別說明一下,課程的編寫是根據實際情況實時調整的,所以有時候與視頻無法一一對應,像本篇教程,只需要看視頻中的前半截就行,后半截視頻的講解在下節教課程中。
本節課程我們要依次實現兩個效果:
繪制不同顏色顏色的、可拖動的圓形
連線支持圓形與圓形、圓形與矩形、矩形與矩形間連線
我們下面就來開始講解。
三、實現效果1:添加不同顏色的、可拖動的圓形
有前面幾節課程的基礎,我們不需要過多的講解,和矩形一樣,只是在繪制時繪制成圓的,且拖動時要判斷選的是圓形還是矩形。
我們下面就來看一下代碼實操。
1,設計器界面

很簡單的界面,就兩個按鈕:添加矩形、添加圓形
2,圓形定義
就像矩形的定義一樣,我們也定義一個圓形的類,用來描述這個圓形:

我們注意到圓形核心也是一個Rectangle類型,這是因為GDI+在繪制圓形是需要的就是Rectangle,不過過多糾結:

因為整個界面我們要添加多個圓形,所以我們定義一個圓形集合:

在繪制時,依次繪制所有圓形:

3,鼠標點擊事件
在鼠標點擊時,我們這里就要多判斷一步:點擊的是圓形?還是矩形?

4,鼠標移動事件
在鼠標移動時,我們同樣要判斷當前點按著的是圓形還是矩形,并修改對應形狀的位置。

5,添加圓形的方法
和添加矩形一樣,往圓形集合中添加一個圓形:

好了,代碼很簡單,到此就實現了效果1,下面是完整的代碼,大家試試吧。
點擊查看代碼
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 FormDemo03V1 : FormBase
{
public FormDemo03V1()
{
InitializeComponent();
DemoTitle = "第05節隨課Demo Part1";
DemoNote = "效果:支持添加圓形,支持不同顏色,支持拖動";
}
/// <summary>
/// 矩形定義
/// </summary>
public class RectShape
{
/// <summary>
/// 矩形ID
/// </summary>
public string Id { get; set; }
/// <summary>
/// 矩形位置和尺寸
/// </summary>
public Rectangle Rect { get; set; }
}
/// <summary>
/// 圓形定義
/// </summary>
public class EllipseShape
{
/// <summary>
/// 矩形ID
/// </summary>
public string Id { get; set; }
/// <summary>
/// 矩形位置和尺寸
/// </summary>
public Rectangle Rect { get; set; }
}
/// <summary>
/// 直線連線定義
/// </summary>
public class LineLink
{
/// <summary>
/// 連線ID
/// </summary>
public string Id { get; set; }
/// <summary>
/// 開始形狀是否是矩形
/// </summary>
public bool StartShapeIsRect { get; set; }
/// <summary>
/// 結束開關是否是矩形
/// </summary>
public bool EndShapeIsRect { get; set; }
/// <summary>
/// 連線開始形狀ID
/// </summary>
public string StartShapeId { get; set; }
/// <summary>
/// 連線結束形狀ID
/// </summary>
public string EndShapeId { get; set; }
}
/// <summary>
/// 矩形集合
/// </summary>
List<RectShape> RectShapes = new List<RectShape>();
/// <summary>
/// 圓形集合
/// </summary>
List<EllipseShape> EllipseShapes = new List<EllipseShape>();
/// <summary>
/// 當前界面連線集合
/// </summary>
List<LineLink> Links = new List<LineLink>();
/// <summary>
/// 畫一個矩形(不同顏色)
/// </summary>
/// <param name="g"></param>
/// <param name="shape"></param>
void DrawRectShape2(Graphics g, RectShape shape)
{
var index = RectShapes.FindIndex(a => a.Id == shape.Id);
g.FillRectangle(GetBrush(index), shape.Rect);
g.DrawString(shape.Id, Font, Brushes.White, shape.Rect);
}
/// <summary>
/// 畫一個圓形(不同顏色)
/// </summary>
/// <param name="g"></param>
/// <param name="shape"></param>
void DrawEllipseShape2(Graphics g, EllipseShape shape)
{
var index = EllipseShapes.FindIndex(a => a.Id == shape.Id);
g.FillEllipse(GetBrush(index), shape.Rect);
g.DrawString(shape.Id, Font, Brushes.White, shape.Rect.X+20,shape.Rect.Y+20); //注:這里可以講一下,要+20,是顯示文本
}
/// <summary>
/// 繪制一條連線(不同顏色)
/// </summary>
/// <param name="g"></param>
/// <param name="line"></param>
void DrawLine2(Graphics g, LineLink line)
{
//通過連線的開始形狀ID和結束形狀ID,計算兩個形狀的中心點坐標
var startPoint = line.StartShapeIsRect? GetCentertPointRect(line.StartShapeId):
GetCentertPointEllipse(line.StartShapeId);
var endPoint =line.EndShapeIsRect? GetCentertPointRect(line.EndShapeId) :
GetCentertPointEllipse(line.EndShapeId);
var index = Links.FindIndex(a => a.Id == line.Id);
//繪制一條直線
g.DrawLine(GetPen(index), startPoint, endPoint);
}
/// <summary>
/// 重新繪制當前所有矩形和連線
/// </summary>
/// <param name="g"></param>
void DrawAll(Graphics g)
{
g.Clear(panel1.BackColor);
//繪制所有矩形
foreach (var sp in RectShapes)
{
DrawRectShape2(g, sp);
}
//繪制所有圓形
foreach (var sp in EllipseShapes)
{
DrawEllipseShape2(g, sp);
}
//繪制所有連線
foreach (var ln in Links)
{
DrawLine2(g, ln);
}
}
//注:文章中說明;此處不過于抽象,后續章節會有
/// <summary>
/// 當前是否有鼠標按下,且有矩形被選中
/// </summary>
bool _isMouseDown = false;
/// <summary>
/// 是否是矩形被選中,不是則是圓形
/// </summary>
bool _isRectMouseDown = true;
/// <summary>
/// 最后一次鼠標的位置
/// </summary>
Point _lastMouseLocation = Point.Empty;
/// <summary>
/// 當前被鼠標選中的矩形
/// </summary>
RectShape _selectedRectShape = null;
/// <summary>
/// 當前被鼠標選中的圓形
/// </summary>
EllipseShape _selectedEllipseShape = null;
/// <summary>
/// 獲取不同的背景顏色
/// </summary>
/// <param name="i"></param>
/// <returns></returns>
Brush GetBrush(int i)
{
switch (i)
{
case 0: return Brushes.Red;
case 1: return Brushes.Green;
case 2: return Brushes.Blue;
case 3: return Brushes.Orange;
case 4: return Brushes.Purple;
default: return Brushes.Red;
}
}
/// <summary>
/// 獲取不同的畫筆顏色
/// </summary>
/// <param name="i"></param>
/// <returns></returns>
Pen GetPen(int i)
{
return new Pen(GetBrush(i), 2);
}
/// <summary>
/// 根據形狀ID獲取形狀的中心點,以作為連線的起點或終點
/// </summary>
/// <param name="shapeId"></param>
/// <returns></returns>
Point GetCentertPointRect(string shapeId)
{
var sp = RectShapes.Find(a => a.Id == shapeId);
if (sp != null)
{
var line1X = sp.Rect.X + sp.Rect.Width / 2;
var line1Y = sp.Rect.Y + sp.Rect.Height / 2;
return new Point(line1X, line1Y);
}
return Point.Empty;
}
/// <summary>
/// 根據形狀ID獲取形狀的中心點,以作為連線的起點或終點
/// </summary>
/// <param name="shapeId"></param>
/// <returns></returns>
Point GetCentertPointEllipse(string shapeId)
{
var sp = EllipseShapes.Find(a => a.Id == shapeId);
if (sp != null)
{
var line1X = sp.Rect.X + sp.Rect.Width / 2;
var line1Y = sp.Rect.Y + sp.Rect.Height / 2;
return new Point(line1X, line1Y);
}
return Point.Empty;
}
private void toolStripButton1_Click(object sender, EventArgs e)
{
var rs = new RectShape()
{
Id = "矩形" + (RectShapes.Count + 1),
Rect = new Rectangle()
{
X = 50,
Y = 50,
Width = 100,
Height = 100,
},
};
RectShapes.Add(rs);
//重繪所有矩形
DrawAll(panel1.CreateGraphics());
}
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
//當鼠標按下時
//取最上方的矩形,也就是最后添加的矩形
var sp = RectShapes.FindLast(a => a.Rect.Contains(e.Location));
//取最上方的圓形,也就是最后添加的圓形
var ep = EllipseShapes.FindLast(a => a.Rect.Contains(e.Location));
//注:說明,這里是簡化情況,因為是兩個LIST,無法判斷序號,就先判斷矩形
//當前沒有處理連線狀態
if (sp != null)
{
//設置狀態及選中矩形
_isMouseDown = true;
_lastMouseLocation = e.Location;
_selectedRectShape = sp;
_selectedEllipseShape = null;
_isRectMouseDown = true;
}
else if (ep != null)
{
//設置狀態及選中圓形
_isMouseDown = true;
_lastMouseLocation = e.Location;
_selectedRectShape = null;
_selectedEllipseShape = ep;
_isRectMouseDown = false;
}
}
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
if (_isMouseDown)
{
//當且僅當:有鼠標按下且有矩形被選中時,才進行后續操作
//改變選中矩形的位置信息,隨著鼠標移動而移動
//計算鼠標位置變化信息
var moveX = e.Location.X - _lastMouseLocation.X;
var moveY = e.Location.Y - _lastMouseLocation.Y;
//將選中形狀的位置進行同樣的變化
if (_isRectMouseDown)
{
var oldXY = _selectedRectShape.Rect.Location;
oldXY.Offset(moveX, moveY);
_selectedRectShape.Rect = new Rectangle(oldXY, _selectedRectShape.Rect.Size);
}
else
{
var oldXY = _selectedEllipseShape.Rect.Location;
oldXY.Offset(moveX, moveY);
_selectedEllipseShape.Rect = new Rectangle(oldXY, _selectedEllipseShape.Rect.Size);
}
//記錄當前鼠標位置
_lastMouseLocation.Offset(moveX, moveY);
//重繪所有矩形
DrawAll(panel1.CreateGraphics());
}
}
private void panel1_MouseUp(object sender, MouseEventArgs e)
{
//當鼠標松開時
if (_isMouseDown)
{
//當且僅當:有鼠標按下且有矩形被選中時,才進行后續操作
//重置相關記錄信息
_isMouseDown = false;
_lastMouseLocation = Point.Empty;
_selectedRectShape = null;
_selectedEllipseShape = null;
}
}
private void toolStripButton4_Click(object sender, EventArgs e)
{
var rs = new EllipseShape()
{
Id = "圓形" + (EllipseShapes.Count + 1),
Rect = new Rectangle()
{
X = 50,
Y = 50,
Width = 100,
Height = 100,
},
};
EllipseShapes.Add(rs);
//重繪所有矩形
DrawAll(panel1.CreateGraphics());
}
}
}
四、實現效果2:連線支持圓形與圓形、圓形與矩形、矩形與矩形間連線
上一小節我們添加上了圓形,下面就來支持連線。
1,設計器界面
我們在上節的基礎上稍做添加:

2,連線定義修改
因為我們要支持圓形與矩形間不同組合的連線,所以我們需要對連線定義進行擴展:

我們增加了兩個布爾變量,來標識開始形狀和結束形狀是否是矩形,不是矩形則是圓形。
注:各位讀者看到這里,可能會感覺很死板和繁瑣。是的,確實如此。我們現在是剛開始起步,所以要從簡入深,從繁化簡,也是在這樣一步步深入,我們明白了其中的痛點,引導著我們去調整、去優化。大概下下節課,我們就會使用抽象大法,到時一切都會變得優雅。
3,繪制連線
在繪制連線時,我們通過判斷形狀是圓形還是矩形,來取不同的中心點,并繪制連線。
注:當然,現在連線的是形狀的圓心,所以并沒有太大的區別。


4,鼠標點擊事件
這部分不難理解但會比較繁瑣,在判斷是否連線時,還要判斷開始形狀與結束形狀的類型等。

剩下的就和上一小節沒多少差別了,不再贅述。下面是完整的代碼,大家可以參照嘗試。
點擊查看代碼
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 FormDemo03V2 : FormBase
{
public FormDemo03V2()
{
InitializeComponent();
DemoTitle = "第05節隨課Demo Part2";
DemoNote = "效果:支持矩形與矩形間連線、矩形與圓形間連線、圓形與圓形間連線";
}
/// <summary>
/// 矩形定義
/// </summary>
public class RectShape
{
/// <summary>
/// 矩形ID
/// </summary>
public string Id { get; set; }
/// <summary>
/// 矩形位置和尺寸
/// </summary>
public Rectangle Rect { get; set; }
}
/// <summary>
/// 圓形定義
/// </summary>
public class EllipseShape
{
/// <summary>
/// 矩形ID
/// </summary>
public string Id { get; set; }
/// <summary>
/// 矩形位置和尺寸
/// </summary>
public Rectangle Rect { get; set; }
}
/// <summary>
/// 直線連線定義
/// </summary>
public class LineLink
{
/// <summary>
/// 連線ID
/// </summary>
public string Id { get; set; }
/// <summary>
/// 開始形狀是否是矩形
/// </summary>
public bool StartShapeIsRect { get; set; }
/// <summary>
/// 結束開關是否是矩形
/// </summary>
public bool EndShapeIsRect { get; set; }
/// <summary>
/// 連線開始形狀ID
/// </summary>
public string StartShapeId { get; set; }
/// <summary>
/// 連線結束形狀ID
/// </summary>
public string EndShapeId { get; set; }
}
/// <summary>
/// 矩形集合
/// </summary>
List<RectShape> RectShapes = new List<RectShape>();
/// <summary>
/// 圓形集合
/// </summary>
List<EllipseShape> EllipseShapes = new List<EllipseShape>();
/// <summary>
/// 當前界面連線集合
/// </summary>
List<LineLink> Links = new List<LineLink>();
/// <summary>
/// 畫一個矩形(不同顏色)
/// </summary>
/// <param name="g"></param>
/// <param name="shape"></param>
void DrawRectShape2(Graphics g, RectShape shape)
{
var index = RectShapes.FindIndex(a => a.Id == shape.Id);
g.FillRectangle(GetBrush(index), shape.Rect);
g.DrawString(shape.Id, Font, Brushes.White, shape.Rect);
}
/// <summary>
/// 畫一個圓形(不同顏色)
/// </summary>
/// <param name="g"></param>
/// <param name="shape"></param>
void DrawEllipseShape2(Graphics g, EllipseShape shape)
{
var index = EllipseShapes.FindIndex(a => a.Id == shape.Id);
g.FillEllipse(GetBrush(index), shape.Rect);
g.DrawString(shape.Id, Font, Brushes.White, shape.Rect.X+20,shape.Rect.Y+20); //注:這里可以講一下,要+20,是顯示文本
}
/// <summary>
/// 繪制一條連線(不同顏色)
/// </summary>
/// <param name="g"></param>
/// <param name="line"></param>
void DrawLine2(Graphics g, LineLink line)
{
//通過連線的開始形狀ID和結束形狀ID,計算兩個形狀的中心點坐標
var startPoint = line.StartShapeIsRect? GetCentertPointRect(line.StartShapeId): GetCentertPointEllipse(line.StartShapeId);
var endPoint =line.EndShapeIsRect? GetCentertPointRect(line.EndShapeId) : GetCentertPointEllipse(line.EndShapeId);
var index = Links.FindIndex(a => a.Id == line.Id);
//繪制一條直線
g.DrawLine(GetPen(index), startPoint, endPoint);
}
/// <summary>
/// 重新繪制當前所有矩形和連線
/// </summary>
/// <param name="g"></param>
void DrawAll(Graphics g)
{
g.Clear(panel1.BackColor);
//繪制所有矩形
foreach (var sp in RectShapes)
{
DrawRectShape2(g, sp);
}
//繪制所有圓形
foreach (var sp in EllipseShapes)
{
DrawEllipseShape2(g, sp);
}
//繪制所有連線
foreach (var ln in Links)
{
DrawLine2(g, ln);
}
}
//注:文章中說明;此處不過于抽象,后續章節會有
/// <summary>
/// 當前是否有鼠標按下,且有矩形被選中
/// </summary>
bool _isMouseDown = false;
/// <summary>
/// 是否是矩形被選中,不是則是圓形
/// </summary>
bool _isRectMouseDown = true;
/// <summary>
/// 最后一次鼠標的位置
/// </summary>
Point _lastMouseLocation = Point.Empty;
/// <summary>
/// 當前被鼠標選中的矩形
/// </summary>
RectShape _selectedRectShape = null;
/// <summary>
/// 當前被鼠標選中的圓形
/// </summary>
EllipseShape _selectedEllipseShape = null;
/// <summary>
/// 添加連線時選中的第一個是否是矩形,不是則是圓形
/// </summary>
bool _selectedStartIsRect = true;
/// <summary>
/// 添加連線時選中的第一個矩形
/// </summary>
RectShape _selectedStartRectShape = null;
/// <summary>
/// 添加連線時選中的第一個圓形
/// </summary>
EllipseShape _selectedStartEllipseShape = null;
/// <summary>
/// 添加連線時選中的第二個是否是矩形,不是則是圓形
/// </summary>
bool _selectedEndIsRect = true;
/// <summary>
/// 添加連線時選中的第二個矩形
/// </summary>
RectShape _selectedEndRectShape = null;
/// <summary>
/// 添加連線時選中的第二個圓形
/// </summary>
EllipseShape _selectedEndEllipseShape = null;
/// <summary>
/// 是否正添加連線
/// </summary>
bool _isAddLink = false;
/// <summary>
/// 獲取不同的背景顏色
/// </summary>
/// <param name="i"></param>
/// <returns></returns>
Brush GetBrush(int i)
{
switch (i)
{
case 0: return Brushes.Red;
case 1: return Brushes.Green;
case 2: return Brushes.Blue;
case 3: return Brushes.Orange;
case 4: return Brushes.Purple;
default: return Brushes.Red;
}
}
/// <summary>
/// 獲取不同的畫筆顏色
/// </summary>
/// <param name="i"></param>
/// <returns></returns>
Pen GetPen(int i)
{
return new Pen(GetBrush(i), 2);
}
/// <summary>
/// 根據形狀ID獲取形狀的中心點,以作為連線的起點或終點
/// </summary>
/// <param name="shapeId"></param>
/// <returns></returns>
Point GetCentertPointRect(string shapeId)
{
var sp = RectShapes.Find(a => a.Id == shapeId);
if (sp != null)
{
var line1X = sp.Rect.X + sp.Rect.Width / 2;
var line1Y = sp.Rect.Y + sp.Rect.Height / 2;
return new Point(line1X, line1Y);
}
return Point.Empty;
}
/// <summary>
/// 根據形狀ID獲取形狀的中心點,以作為連線的起點或終點
/// </summary>
/// <param name="shapeId"></param>
/// <returns></returns>
Point GetCentertPointEllipse(string shapeId)
{
var sp = EllipseShapes.Find(a => a.Id == shapeId);
if (sp != null)
{
var line1X = sp.Rect.X + sp.Rect.Width / 2;
var line1Y = sp.Rect.Y + sp.Rect.Height / 2;
return new Point(line1X, line1Y);
}
return Point.Empty;
}
private void toolStripButton1_Click(object sender, EventArgs e)
{
var rs = new RectShape()
{
Id = "矩形" + (RectShapes.Count + 1),
Rect = new Rectangle()
{
X = 50,
Y = 50,
Width = 100,
Height = 100,
},
};
RectShapes.Add(rs);
//重繪所有矩形
DrawAll(panel1.CreateGraphics());
}
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
//當鼠標按下時
//取最上方的矩形,也就是最后添加的矩形
var sp = RectShapes.FindLast(a => a.Rect.Contains(e.Location));
//取最上方的圓形,也就是最后添加的圓形
var ep = EllipseShapes.FindLast(a => a.Rect.Contains(e.Location));
if (!_isAddLink)
{
//注:說明,這里是簡化情況,因為是兩個LIST,無法判斷序號,就先判斷矩形
//當前沒有處理連線狀態
if (sp != null)
{
//設置狀態及選中矩形
_isMouseDown = true;
_lastMouseLocation = e.Location;
_selectedRectShape = sp;
_selectedEllipseShape = null;
_isRectMouseDown = true;
}
else if (ep != null)
{
//設置狀態及選中圓形
_isMouseDown = true;
_lastMouseLocation = e.Location;
_selectedRectShape = null;
_selectedEllipseShape = ep;
_isRectMouseDown = false;
}
}
else
{
//正在添加連線
if (_selectedStartRectShape == null && _selectedStartEllipseShape == null)
{
//證明沒有矩形和圓形被選中則設置開始形狀
if (sp != null)
{
//設置開始形狀是矩形
_selectedStartRectShape = sp;
_selectedStartEllipseShape = null;
_selectedStartIsRect = true;
}
else if (ep != null)
{
//設置開始形狀是圓形
_selectedStartRectShape = null;
_selectedStartEllipseShape = ep;
_selectedStartIsRect = false;
}
toolStripStatusLabel1.Text = "請點擊第2個形狀";
}
else
{
//判斷第2個形狀是否是第1個形狀
if (sp != null)
{
//證明當前選中的是矩形
if (_selectedStartRectShape != null)
{
//證明第1步選中的矩形
//判斷當前選中的矩形是否是第1步選中的矩形
if (_selectedStartRectShape.Id == sp.Id)
{
toolStripStatusLabel1.Text = "不可選擇同一個形狀,請重新點擊第2個形狀";
return;
}
}
}
else if (ep != null)
{
//證明當前選中的圓形
if (_selectedStartEllipseShape != null)
{
//證明第1步選中的矩形
//判斷當前選中的矩形是否是第1步選中的矩形
if (_selectedStartEllipseShape.Id == ep.Id)
{
toolStripStatusLabel1.Text = "不可選擇同一個形狀,請重新點擊第2個形狀";
return;
}
}
}
//注:文章中說明:因為太過復雜,且不是本節重點,但不再進行去重判斷
if (sp != null)
{
//設置結束形狀是矩形
_selectedEndRectShape = sp;
_selectedEndEllipseShape = null;
_selectedEndIsRect = true;
}
else if (ep != null)
{
//設置結束形狀是圓形
_selectedEndRectShape = null;
_selectedEndEllipseShape = ep;
_selectedEndIsRect = false;
}
else
{
return;
}
//兩個形狀都設置了,便添加一條新連線
Links.Add(new LineLink()
{
Id = "連線" + (Links.Count + 1),
StartShapeId =_selectedStartIsRect? _selectedStartRectShape.Id:_selectedStartEllipseShape.Id,
EndShapeId =_selectedEndIsRect? _selectedEndRectShape.Id:_selectedEndEllipseShape.Id,
StartShapeIsRect=_selectedStartIsRect,
EndShapeIsRect=_selectedEndIsRect,
});
//兩個形狀都已選擇,結束添加連線狀態
_isAddLink = false;
toolStripStatusLabel1.Text = "";
//重繪以顯示連線
DrawAll(panel1.CreateGraphics());
}
}
}
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
//當鼠標移動時
//如果處于添加連線時,則不移動形狀
if (_isAddLink) return;
if (_isMouseDown)
{
//當且僅當:有鼠標按下且有矩形被選中時,才進行后續操作
//改變選中矩形的位置信息,隨著鼠標移動而移動
//計算鼠標位置變化信息
var moveX = e.Location.X - _lastMouseLocation.X;
var moveY = e.Location.Y - _lastMouseLocation.Y;
//將選中形狀的位置進行同樣的變化
if (_isRectMouseDown)
{
var oldXY = _selectedRectShape.Rect.Location;
oldXY.Offset(moveX, moveY);
_selectedRectShape.Rect = new Rectangle(oldXY, _selectedRectShape.Rect.Size);
}
else
{
var oldXY = _selectedEllipseShape.Rect.Location;
oldXY.Offset(moveX, moveY);
_selectedEllipseShape.Rect = new Rectangle(oldXY, _selectedEllipseShape.Rect.Size);
}
//記錄當前鼠標位置
_lastMouseLocation.Offset(moveX, moveY);
//重繪所有矩形
DrawAll(panel1.CreateGraphics());
}
}
private void panel1_MouseUp(object sender, MouseEventArgs e)
{
//當鼠標松開時
if (_isMouseDown)
{
//當且僅當:有鼠標按下且有矩形被選中時,才進行后續操作
//重置相關記錄信息
_isMouseDown = false;
_lastMouseLocation = Point.Empty;
_selectedRectShape = null;
_selectedEllipseShape = null;
}
}
private void toolStripButton2_Click(object sender, EventArgs e)
{
_isAddLink = true;
_selectedStartRectShape = null;
_selectedEndRectShape = null;
_selectedStartEllipseShape = null;
_selectedEndEllipseShape = null;
toolStripStatusLabel1.Text = "請點擊第1個形狀";
}
private void toolStripButton3_Click(object sender, EventArgs e)
{
_isAddLink = false;
_selectedStartRectShape = null;
_selectedEndRectShape = null;
toolStripStatusLabel1.Text = "";
DrawAll(panel1.CreateGraphics());
}
private void toolStripButton4_Click(object sender, EventArgs e)
{
var rs = new EllipseShape()
{
Id = "圓形" + (EllipseShapes.Count + 1),
Rect = new Rectangle()
{
X = 50,
Y = 50,
Width = 100,
Height = 100,
},
};
EllipseShapes.Add(rs);
//重繪所有矩形
DrawAll(panel1.CreateGraphics());
}
}
}
五、結語
本一小節總體而言很簡單,就是增加一個新的形狀:圓形。但是在代碼流程上卻復雜很多,這也是我們后面課程使用抽象來優化的原因之一。
下節課我們就來到了顯示效果優化部分了,除了顯示質量外,還有拖動時閃爍的問題也會同步解決。敬請期待。
感謝大家的觀看,本人水平有限,文章不足之處歡迎大家評論指正。
-[END]-

浙公網安備 33010602011771號