C# 图形绘制:使用 ResizePin 实现可拖拽、可调整大小的矩形框
using System.Drawing;
using System.Windows.Forms;
namespace CirecleCCS
{
class CcsGo
{
public int ResizePinSize = 6; // 圆的直径
int HalfRPR
{
get { return ResizePinSize / 2; } // 半径
}
private static Pen SelectRectPen, ResizePinPen;
private float[] SelectRectDashPattern;
private static Rectangle SelectRect;
private static Rectangle ResizePin1, ResizePin2, ResizePin3, ResizePin4, ResizePin5, ResizePin6, ResizePin7, ResizePin8;
private static Rectangle rect;
private static int ActivationPinPosition;
// selectrect 的 x, y, x1, y1
private static int SelectX0, SelectY0, SelectX1, SelectY1;
// 8 个角 + 点空白处 + 点中间
private const int hitNothing = -1;
private const int hitTopLeft = 0;
private const int hitTopRight = 1;
private const int hitBottomRight = 2;
private const int hitBottomLeft = 3;
private const int hitTop = 4;
private const int hitRight = 5;
private const int hitBottom = 6;
private const int hitLeft = 7;
private const int hitMiddle = 8;
private void HideResizePin() // 隐藏 ResizePin
{
ResizePin1.Width = 0; ResizePin1.Height = 0;
ResizePin2.Width = 0; ResizePin2.Height = 0;
ResizePin3.Width = 0; ResizePin3.Height = 0;
ResizePin4.Width = 0; ResizePin4.Height = 0;
ResizePin5.Width = 0; ResizePin5.Height = 0;
ResizePin6.Width = 0; ResizePin6.Height = 0;
ResizePin7.Width = 0; ResizePin7.Height = 0;
ResizePin8.Width = 0; ResizePin8.Height = 0;
}
void SetResizePinVal() // 实时显示 ResizePin
{
ResizePin1.X = X - HalfRPR;
ResizePin1.Y = Y - HalfRPR;
ResizePin2.X = X + Width / 2 - HalfRPR;
ResizePin2.Y = Y - HalfRPR;
ResizePin3.X = X + Width - HalfRPR;
ResizePin3.Y = Y - HalfRPR;
ResizePin4.X = X + Width - HalfRPR;
ResizePin4.Y = Y + Height / 2 - HalfRPR;
ResizePin5.X = X + Width - HalfRPR;
ResizePin5.Y = Y + Height - HalfRPR;
ResizePin6.X = X + Width / 2 - HalfRPR;
ResizePin6.Y = Y + Height - HalfRPR;
ResizePin7.X = X - HalfRPR;
ResizePin7.Y = Y + Height - HalfRPR;
ResizePin8.X = X - HalfRPR;
ResizePin8.Y = Y + Height / 2 - HalfRPR;
}
private void ShowResizePin() // 显示 ResizePin
{
ResizePin1.X = SelectRect.X - HalfRPR;
ResizePin1.Y = SelectRect.Y - HalfRPR;
ResizePin2.X = SelectRect.X + SelectRect.Width / 2 - HalfRPR;
ResizePin2.Y = SelectRect.Y - HalfRPR;
ResizePin3.X = SelectRect.X + SelectRect.Width - HalfRPR;
ResizePin3.Y = SelectRect.Y - HalfRPR;
ResizePin4.X = SelectRect.X + SelectRect.Width - HalfRPR;
ResizePin4.Y = SelectRect.Y + SelectRect.Height / 2 - HalfRPR;
ResizePin5.X = SelectRect.X + SelectRect.Width - HalfRPR;
ResizePin5.Y = SelectRect.Y + SelectRect.Height - HalfRPR;
ResizePin6.X = SelectRect.X + SelectRect.Width / 2 - HalfRPR;
ResizePin6.Y = SelectRect.Y + SelectRect.Height - HalfRPR;
ResizePin7.X = SelectRect.X - HalfRPR;
ResizePin7.Y = SelectRect.Y + SelectRect.Height - HalfRPR;
ResizePin8.X = SelectRect.X - HalfRPR;
ResizePin8.Y = SelectRect.Y + SelectRect.Height / 2 - HalfRPR;
ResizePin1.Width = ResizePinSize; ResizePin1.Height = ResizePinSize;
ResizePin2.Width = ResizePinSize; ResizePin2.Height = ResizePinSize;
ResizePin3.Width = ResizePinSize; ResizePin3.Height = ResizePinSize;
ResizePin4.Width = ResizePinSize; ResizePin4.Height = ResizePinSize;
ResizePin5.Width = ResizePinSize; ResizePin5.Height = ResizePinSize;
ResizePin6.Width = ResizePinSize; ResizePin6.Height = ResizePinSize;
ResizePin7.Width = ResizePinSize; ResizePin7.Height = ResizePinSize;
ResizePin8.Width = ResizePinSize; ResizePin8.Height = ResizePinSize;
}
void FillResizePins(PaintEventArgs e) // 填充 ResizePinRect 颜色
{
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
e.Graphics.FillEllipse(Brushes.SteelBlue, ResizePin1);
e.Graphics.FillEllipse(Brushes.SteelBlue, ResizePin2);
e.Graphics.FillEllipse(Brushes.SteelBlue, ResizePin3);
e.Graphics.FillEllipse(Brushes.SteelBlue, ResizePin4);
e.Graphics.FillEllipse(Brushes.SteelBlue, ResizePin5);
e.Graphics.FillEllipse(Brushes.SteelBlue, ResizePin6);
e.Graphics.FillEllipse(Brushes.SteelBlue, ResizePin7);
e.Graphics.FillEllipse(Brushes.SteelBlue, ResizePin8);
}
void DrawResizePin(Graphics g) // 绘制 ResizePin
{
g.DrawEllipse(ResizePinPen, ResizePin1);
g.DrawEllipse(ResizePinPen, ResizePin2);
g.DrawEllipse(ResizePinPen, ResizePin3);
g.DrawEllipse(ResizePinPen, ResizePin4);
g.DrawEllipse(ResizePinPen, ResizePin5);
g.DrawEllipse(ResizePinPen, ResizePin6);
g.DrawEllipse(ResizePinPen, ResizePin7);
g.DrawEllipse(ResizePinPen, ResizePin8);
}
bool InELP(MouseEventArgs e, Point ElpCenter) // 是否在 ResizePin 圆内
{
int elpX = ElpCenter.X;
int elpY = ElpCenter.Y;
return !((elpX - e.X) * (elpX - e.X) + (elpY - e.Y) * (elpY - e.Y) >= HalfRPR * HalfRPR);
}
private int HitTest(MouseEventArgs e) // 测试哪个 ResizePin 被选中
{
if (InELP(e, new Point(ResizePin1.X + HalfRPR, ResizePin1.Y + HalfRPR)))
return hitTopLeft;
else if (InELP(e, new Point(ResizePin2.X + HalfRPR, ResizePin2.Y + HalfRPR)))
return hitTop;
else if (InELP(e, new Point(ResizePin3.X + HalfRPR, ResizePin3.Y + HalfRPR)))
return hitTopRight;
else if (InELP(e, new Point(ResizePin4.X + HalfRPR, ResizePin4.Y + HalfRPR)))
return hitRight;
else if (InELP(e, new Point(ResizePin5.X + HalfRPR, ResizePin5.Y + HalfRPR)))
return hitBottomRight;
else if (InELP(e, new Point(ResizePin6.X + HalfRPR, ResizePin6.Y + HalfRPR)))
return hitBottom;
else if (InELP(e, new Point(ResizePin7.X + HalfRPR, ResizePin7.Y + HalfRPR)))
return hitBottomLeft;
else if (InELP(e, new Point(ResizePin8.X + HalfRPR, ResizePin8.Y + HalfRPR)))
return hitLeft;
else if (e.X >= SelectRect.X + ResizePinSize && e.X <= SelectRect.X + SelectRect.Width - ResizePinSize
&& e.Y >= SelectRect.Y + ResizePinSize && e.Y <= SelectRect.Y + SelectRect.Height - ResizePinSize)
return hitMiddle;
else
return hitNothing;
}
public void Create() // 初始化参数
{
ResizePinPen = new Pen(Color.SteelBlue, 2);
SelectRectDashPattern = new float[] { 3, 2, 1 };
SelectRectPen = new Pen(Color.SteelBlue, 2.0f);
//{
// DashPattern = SelectRectDashPattern,
//};
SelectRect = new Rectangle();
ResizePin1 = new Rectangle();
ResizePin2 = new Rectangle();
ResizePin3 = new Rectangle();
ResizePin4 = new Rectangle();
ResizePin5 = new Rectangle();
ResizePin6 = new Rectangle();
ResizePin7 = new Rectangle();
ResizePin8 = new Rectangle();
rect = new Rectangle();
ActivationPinPosition = hitNothing;
}
void StayInBoxR(PictureBox R) // 待在 box 里面别出去
{
if (SelectRect.X < 0)
SelectRect.X = 0;
if (SelectRect.Y < 0)
SelectRect.Y = 0;
if (SelectRect.X + SelectRect.Width > R.Width)
SelectRect.X = R.Width - SelectRect.Width;
if (SelectRect.Y + SelectRect.Height > R.Height)
SelectRect.Y = R.Height - SelectRect.Height;
}
public void Destroy() // 释放资源
{
SelectRectPen.Dispose();
ResizePinPen.Dispose();
}
public void StartPoint(PictureBox p, MouseEventArgs e) // 鼠标左键按下后
{
if (e.Button == MouseButtons.Left)
{
p.Invalidate(null, true);
switch (HitTest(e))
{
case hitTopLeft:
ActivationPinPosition = hitTopLeft;
SelectX1 = SelectRect.X + SelectRect.Width;
SelectY1 = SelectRect.Y + SelectRect.Height;
break;
case hitTop:
ActivationPinPosition = hitTop;
SelectX1 = SelectRect.Width + SelectRect.X;
SelectY1 = SelectRect.Height + SelectY0;
break;
case hitTopRight:
ActivationPinPosition = hitTopRight;
SelectY1 = SelectRect.Y + SelectRect.Height;
break;
case hitRight:
ActivationPinPosition = hitRight;
SelectY1 = SelectRect.Y + SelectRect.Height;
break;
case hitBottomRight:
ActivationPinPosition = hitBottomRight;
break;
case hitBottom:
ActivationPinPosition = hitBottom;
SelectX1 = SelectRect.X + SelectRect.Width;
break;
case hitBottomLeft:
ActivationPinPosition = hitBottomLeft;
SelectX1 = SelectRect.X + SelectRect.Width;
break;
case hitLeft:
ActivationPinPosition = hitLeft;
SelectX1 = SelectRect.X + SelectRect.Width;
SelectY1 = SelectRect.Y + SelectRect.Height;
break;
case hitMiddle:
ActivationPinPosition = hitMiddle;
SelectX0 = e.X - SelectRect.X;
SelectY0 = e.Y - SelectRect.Y;
SelectX1 = SelectRect.X + SelectRect.Width - e.X;
SelectY1 = SelectRect.Y + SelectRect.Height - e.Y;
break;
case hitNothing:
ActivationPinPosition = hitNothing;
SelectRect.Width = 0;
SelectRect.Height = 0;
SelectX0 = e.X;
SelectY0 = e.Y;
HideResizePin();
break;
}
}
}
public void TrackRubberBand(PictureBox p, MouseEventArgs e, bool Iskeep = false) // 鼠标左键拖动时动态显示矩形框
{
switch (HitTest(e))
{
case hitTopLeft:
p.Cursor = Cursors.SizeNWSE;
break;
case hitTop:
p.Cursor = Cursors.SizeNS;
break;
case hitTopRight:
p.Cursor = Cursors.SizeNESW;
break;
case hitRight:
p.Cursor = Cursors.SizeWE;
break;
case hitBottomRight:
p.Cursor = Cursors.SizeNWSE;
break;
case hitBottom:
p.Cursor = Cursors.SizeNS;
break;
case hitBottomLeft:
p.Cursor = Cursors.SizeNESW;
break;
case hitLeft:
p.Cursor = Cursors.SizeWE;
break;
case hitMiddle:
p.Cursor = Cursors.SizeAll;
break;
case hitNothing:
p.Cursor = Cursors.Default;
break;
}
if (e.Button == MouseButtons.Left)
{
int TLX = e.X;
int TLY = e.Y;
if (e.X < 0)
TLX = 0;
else if (e.X > p.Width)
TLX = p.Width;
if (e.Y < 0)
TLY = 0;
else if (e.Y > p.Height)
TLY = p.Height;
if (!Iskeep)
{
p.Invalidate(InvalidateRectangle(), false);
}
switch (ActivationPinPosition)
{
case hitTopLeft:
GenerateRectangle(ref SelectRect, TLX, TLY, SelectX1, SelectY1);
StayInBoxR(p);
SetResizePinVal();
break;
case hitTop:
GenerateRectangle(ref SelectRect, SelectX0, TLY, SelectX1, SelectY1);
StayInBoxR(p);
SetResizePinVal();
break;
case hitTopRight:
GenerateRectangle(ref SelectRect, SelectX0, TLY, TLX, SelectY1);
StayInBoxR(p);
SetResizePinVal();
break;
case hitRight:
GenerateRectangle(ref SelectRect, SelectX0, SelectY0, TLX, SelectY1);
StayInBoxR(p);
SetResizePinVal();
break;
case hitBottomRight:
GenerateRectangle(ref SelectRect, SelectX0, SelectY0, TLX, TLY);
StayInBoxR(p);
SetResizePinVal();
break;
case hitBottom:
GenerateRectangle(ref SelectRect, SelectX0, SelectY0, SelectX1, TLY);
StayInBoxR(p);
SetResizePinVal();
break;
case hitBottomLeft:
GenerateRectangle(ref SelectRect, TLX, SelectY0, SelectX1, TLY);
StayInBoxR(p);
SetResizePinVal();
break;
case hitLeft:
GenerateRectangle(ref SelectRect, TLX, SelectY0, SelectX1, SelectY1);
StayInBoxR(p);
SetResizePinVal();
break;
case hitMiddle:
GenerateRectangle(ref SelectRect, e.X - SelectX0, e.Y - SelectY0, e.X + SelectX1, e.Y + SelectY1);
StayInBoxR(p);
SetResizePinVal();
break;
case hitNothing:
GenerateRectangle(ref SelectRect, SelectX0, SelectY0, TLX, TLY);
StayInBoxR(p);
SetResizePinVal();
break;
}
}
}
public void EndPoint(PictureBox frm, MouseEventArgs e) // 鼠标左键松开后
{
if (e.Button == MouseButtons.Left)
{
frm.Invalidate(null, true);
SelectX0 = SelectRect.X;
SelectY0 = SelectRect.Y;
if (HitTest(e) != hitNothing && X > ResizePinSize && Y > ResizePinSize)
ShowResizePin();
}
}
public void DrawRubberBand(PictureBox frm, PaintEventArgs e) // 绘制矩形框
{
e.Graphics.DrawRectangle(SelectRectPen, SelectRect);
FillResizePins(e);
DrawResizePin(e.Graphics);
}
private void GenerateRectangle(ref Rectangle TempRectangle, int X0, int Y0, int X1, int Y1) // 根据指定两点坐标生成矩形框
{
if (X0 < X1)
{
TempRectangle.X = X0;
TempRectangle.Width = X1 - X0;
}
else
{
TempRectangle.X = X1;
TempRectangle.Width = X0 - X1;
}
if (Y0 < Y1)
{
TempRectangle.Y = Y0;
TempRectangle.Height = Y1 - Y0;
}
else
{
TempRectangle.Y = Y1;
TempRectangle.Height = Y0 - Y1;
}
}
// RubberBand 的属性
public int X
{
get
{
return SelectRect.X;
}
}
public int Y
{
get
{
return SelectRect.Y;
}
}
public int Width
{
get
{
return SelectRect.Width;
}
}
public int Height
{
get
{
return SelectRect.Height;
}
}
public Pen RectView { get => RectView; set => RectView = value; }
public Rectangle InvalidateRectangle() // 获得无效区域,用来刷新时防止闪烁
{
rect.X = SelectRect.X - 8;
rect.Y = SelectRect.Y - 8;
rect.Width = SelectRect.Width + 16;
rect.Height = SelectRect.Height + 16;
return rect;
}
public void SetRect(int ex, int ey, int ew, int eh) // set ccs 框的位置以及尺寸
{
GenerateRectangle(ref SelectRect, ex, ey, ex + ew, ey + eh);
}
public void HideCCS() // 隐藏起来
{
HideResizePin();
SetRect(0, 0, 0, 0);
}
}
}
代码内容解释:
这段代码是一个用于绘制矩形框的类,主要用于选中某个区域。
功能特点:
- 使用 ResizePin 实现可拖拽、可调整大小的矩形框
- 支持实时预览效果
- 代码包含详细注释,易于理解和修改
使用说明:
- 将代码添加到您的 C# 项目中。
- 在 PictureBox 控件上添加鼠标事件处理程序。
- 在鼠标事件处理程序中调用 CcsGo 类的方法来绘制和调整矩形框。
代码示例:
private CcsGo ccsGo = new CcsGo();
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
ccsGo.StartPoint(pictureBox1, e);
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
ccsGo.TrackRubberBand(pictureBox1, e);
}
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
ccsGo.EndPoint(pictureBox1, e);
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
ccsGo.DrawRubberBand(pictureBox1, e);
}
其他说明:
- 可以根据需要修改 ResizePinSize 属性来调整 ResizePin 的大小。
- 可以修改 SelectRectPen 和 ResizePinPen 属性来更改矩形框和 ResizePin 的颜色。
- 可以根据需要添加其他功能,例如将选中的区域保存到文件或进行其他操作。
原文地址: https://www.cveoy.top/t/topic/ndzi 著作权归作者所有。请勿转载和采集!