我有一个 c# WinForm 项目,其中包含以下代码来绘制矩形和椭圆形:
public partial class Form1 : Form
{
List<Rectangle> _rectangles = new();
List<Rectangle> _ellipses = new();
Rectangle _rectInProgress;
bool DrawingRectangle = false;
bool DrawingEllipse = false;
public Form1()
{
InitializeComponent();
DoubleBuffered = true;
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
if (DrawingRectangle || DrawingEllipse)
{
_rectInProgress = new Rectangle(e.Location, new Size());
}
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (MouseButtons == MouseButtons.Left && (DrawingRectangle || DrawingEllipse))
{
_rectInProgress.Width = e.Location.X - _rectInProgress.X;
_rectInProgress.Height = e.Location.Y - _rectInProgress.Y;
Invalidate();
}
}
private void Form1_MouseUp(object sender, MouseEventArgs e)
{
if (DrawingRectangle)
{
_rectangles.Add(_rectInProgress);
Invalidate();
}
else if (DrawingEllipse)
{
_ellipses.Add(_rectInProgress);
Invalidate();
}
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
if (_rectangles.Any())
{
e.Graphics.DrawRectangles(new Pen(Color.Blue, 3), _rectangles.ToArray());
}
if (_ellipses.Any())
{
foreach (var ell in _ellipses)
{
e.Graphics.DrawEllipse(new Pen(Color.Blue, 3), ell);
}
}
if (MouseButtons == MouseButtons.Left)
{
if (DrawingEllipse)
{
e.Graphics.DrawEllipse(new Pen(Color.Red, 3), _rectInProgress);
}
else if (DrawingRectangle)
{
e.Graphics.DrawRectangle(new Pen(Color.Red, 3), _rectInProgress);
}
}
}
private void button1_Click(object sender, EventArgs e)
{
DrawingRectangle = !DrawingRectangle;
DrawingEllipse = false;
}
private void button2_Click(object sender, EventArgs e)
{
DrawingEllipse = !DrawingEllipse;
DrawingRectangle = false;
}
}
下一步是使形状可选择,以便可以调整它们的大小。我对这种事情很陌生,所以我不知道从哪里开始。我在互联网上找到了很多示例,但它们都有一个共同点:它们检查光标是否在形状内单击。我需要检查光标是否单击了形状(边框)。
有人对如何进行有任何建议吗?预先感谢!
一种不错的方法是将绘制的矩形或椭圆形的
GraphicsPath
转换为分配给控件的Region。当您执行此操作时,除了图形路径之外,该控件实际上“不存在”。当您单击边框时,与单击控件相同,而当您单击内部时,则不同。
这里有两个可以通过单击边框来调整大小的控件示例,但在这个非常基本的演示中,大小只能从右下角增加或减小。而且,人们可能希望为鼠标单击保持一个计时器,并将其切换到“移动”而不是“调整大小”。不管怎样,这给了你一些可以尝试的东西。
class RectangleControl : Control
{
public RectangleControl()
{
MouseDown += (sender, e) =>
{
_isResizing = true;
_mouseDownPosition = e.Location;
_mouseDownSize = Size;
};
MouseUp += (sender, e) => _isResizing = false;
MouseEnter += (sender, e) => Cursor = Cursors.Cross;
MouseLeave += (sender, e) => Cursor = Cursors.Default;
MouseMove += (sender, e) =>
{
if (_isResizing && e.Button == MouseButtons.Left)
{
int deltaX = e.Location.X - _mouseDownPosition.X;
int deltaY = e.Location.Y - _mouseDownPosition.Y;
var newSize = new Size(
_mouseDownSize.Width + deltaX,
_mouseDownSize.Height + deltaY);
Size = newSize;
}
};
SizeChanged += (sender, e) =>
{
GraphicsPath path = new GraphicsPath();
path.AddRectangle(new Rectangle(0, 0, Width, Height));
Region region = new Region(path);
Rectangle inflatedRect = new Rectangle(
BorderWidth,
BorderWidth,
Width - (BorderWidth * 2),
Height - (BorderWidth * 2));
region.Exclude(inflatedRect);
Region = region;
};
}
private Point _mouseDownPosition;
private Size _mouseDownSize;
bool _isResizing = default;
public int BorderWidth { get; set; } = 4;
}
class EllipseControl : Control
{
public EllipseControl()
{
MouseDown += (sender, e) =>
{
_isResizing = true;
_mouseDownPosition = e.Location;
_mouseDownSize = Size;
};
MouseUp += (sender, e) => _isResizing = false;
MouseEnter += (sender, e) => Cursor = Cursors.Cross;
MouseLeave += (sender, e) => Cursor = Cursors.Default;
MouseMove += (sender, e) =>
{
if (_isResizing && e.Button == MouseButtons.Left)
{
int deltaX = e.Location.X - _mouseDownPosition.X;
int deltaY = e.Location.Y - _mouseDownPosition.Y;
var newSize = new Size(
_mouseDownSize.Width + deltaX,
_mouseDownSize.Height + deltaY);
Size = newSize;
}
};
SizeChanged += (sender, e) =>
{
GraphicsPath path = new GraphicsPath();
path.AddEllipse(new Rectangle(0, 0, Width, Height));
Region region = new Region(path);
GraphicsPath innerPath = new GraphicsPath();
innerPath.AddEllipse(
BorderWidth,
BorderWidth,
Width - (BorderWidth * 2),
Height - (BorderWidth * 2));
region.Exclude(innerPath);
Region = region;
};
}
private Point _mouseDownPosition;
private Size _mouseDownSize;
bool _isResizing = default;
public float BorderWidth { get; set; } = 4;
}
public partial class MainForm : Form
{
Rectangle _rectInProgress;
public MainForm()
{
InitializeComponent();
DoubleBuffered = true;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
if (MouseButtons == MouseButtons.Left && _isDrawing)
{
if(radioButtonRectangle.Checked)
{
using (var pen = new Pen(Brushes.Red, 4F))
{
e.Graphics.DrawRectangle(pen, _rectInProgress);
}
}
else
{
using (var pen = new Pen(Brushes.Red, 4F))
{
e.Graphics.DrawEllipse(pen, _rectInProgress);
}
}
}
}
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
_isDrawing = true;
_rectInProgress = new Rectangle(e.Location, new Size());
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
if (MouseButtons == MouseButtons.Left)
{
_rectInProgress.Width = e.Location.X - _rectInProgress.X;
_rectInProgress.Height = e.Location.Y - _rectInProgress.Y;
Invalidate();
}
}
protected override void OnMouseUp(MouseEventArgs e)
{
base.OnMouseUp(e);
_isDrawing = false;
Invalidate();
Control control;
if (radioButtonRectangle.Checked)
{
control = new RectangleControl
{
Location = _rectInProgress.Location,
Size = _rectInProgress.Size,
BackColor = Color.Blue,
};
}
else
{
control = new EllipseControl
{
Location = _rectInProgress.Location,
Size = _rectInProgress.Size,
BackColor = Color.Green,
};
}
Controls.Add(control);
}
bool _isDrawing = false;
}