用鼠标移动一条画好的线
本文关键字:一条 鼠标 移动 | 更新日期: 2023-09-27 18:17:14
我正在尝试通过鼠标抓取它来移动已绘制的线。
这条线已经和Graphics.DrawLine(Pen P, Point A, Point B)
画好了。
创建直线并在表单上绘制它绝对没有问题。
我试过:
-
将线添加到
GraphicsPath
-这甚至不画OnPaint
线 -
检查
MouseEventArgs e.Location
是否在线与一些基本代数(计算,我已经扔掉了)
总结一下,我想抓取线条并拖动到某个地方但我甚至无法检查。location是否在线条上,我该怎么做呢?
编辑:当我使用GraphicsPath时,这是代码的样子。
当我不使用GraphicsPath时,我有:
if (s.thisShape == ShapeType.Line) {
g.DrawLine(pen, s.p1, s.p2);
} else { ... }`
在drawingShapes方法。
来自drawStuff: Usercontrol类:
private void drawStuff_MouseDown(object sender, MouseEventArgs e)
{
pointRegion = e.Location;
for (int i = 0; i < Shapes.Count; i++)
{
if (Shapes[i].Region.IsVisible(pointRegion))
{
isDragging = true;
count = i;
break;
}
}
}
private void drawStuff_MouseMove(object sender, MouseEventArgs e)
{
if (isDragging)
{
Shapes[count].moveWithDiff(pointRegion, e.Location);
pointRegion = e.Location;
Refresh();
}
}
private void drawStuff_MouseUp(object sender, MouseEventArgs e)
{
isDragging = false;
Refresh();
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
drawShapes(e.Graphics);
}
private void drawShapes(Graphics g)
{
temporaryPen = pennaLeft;
foreach (Shape s in Shapes)
{
g.FillRegion(temporaryPen, s.Region);
}
}
来自Shape: Usercontrol类:
public void moveWithDiff(Point pr, Point mp)
{
Point p = new Point();
if (this.thisShape == ShapeType.Line)
{
p.X = mp.X - pr.X;
p.Y = mp.Y - pr.Y;
this.p1.X += p.X;
this.p1.Y += p.Y;
this.p2.X += p.X;
this.p2.Y += p.Y;
}
RefreshPath();
}
private void RefreshPath()
{
gPath = new GraphicsPath();
switch (thisShape)
{
case ShapeType.Line:
gPath.AddLine(this.p1, this.p2);
break;
}
this.Region = new Region(gPath);
}
现在这甚至不画线,然而,在drawingShapes()中使用if语句,它画得很好,但我不能把它拖到其他地方
让我们从基础开始,在屏幕上获得一行。我创建了一个自定义类来处理我希望在此过程中可用的一些函数:
public class MyLine
{
public Pen pen { get; set; }
public Point Start { get; set; }
public Point End { get; set; }
public MyLine(Pen p, Point p1, Point p2)
{
pen = p;
Start = p1;
End = p2;
}
public float slope
{
get
{
return (((float)End.Y - (float)Start.Y) / ((float)End.X - (float)Start.X));
}
}
public float YIntercept
{
get
{
return Start.Y - slope*Start.X;
}
}
public bool IsPointOnLine(Point p, int cushion)
{
float temp = (slope * p.X + YIntercept);
if (temp >= (p.Y-cushion) && temp <=(p.Y+cushion))
{
return true;
}
else
{
return false;
}
}
}
这个类提供了一些帮助函数,使我们的工作更轻松。我们有返回斜率和y轴截距的性质,所以我们可以确定某一点是否在直线上。然后提供一个辅助函数IsPointOnLine(),它接受一个点和一个缓冲。缓冲器的作用是允许用户在离行足够近的地方单击,使其返回true。
接下来我要实例化这条线,并在窗体的paint事件中绘制它:
MyLine m;
private void Form1_Load(object sender, EventArgs e)
{
m= new MyLine(Pens.Black, new Point(20, 20), new Point(40, 40));
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawLine(m.pen, m.Start, m.End);
}
现在你应该能够运行你的应用程序,并在屏幕上看到从20,20到40,40的一行。
现在我想处理鼠标与线的交互,所以在MouseDown上,我们将查看点击点是否与线相交,以及它是否设置了一个标志,并保持与端点的差值。在MouseMove事件中,我们将查看该行是否已被单击但未被释放,并适当地重置坐标。在MouseUp事件中,我们简单地重置我们的标志:
Point deltaStart;
Point deltaEnd;
bool dragging = false;
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left && m.IsPointOnLine(e.Location, 5))
{
dragging = true;
deltaStart = new Point(m.Start.X - e.Location.X, m.Start.Y - e.Location.Y);
deltaEnd = new Point(m.End.X - e.Location.X, m.End.Y - e.Location.Y);
}
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (dragging && deltaStart != null && deltaEnd != null )
{
m.Start = new Point(deltaStart.X + e.Location.X, deltaStart.Y + e.Location.Y);
m.End = new Point(deltaEnd.X + e.Location.X, deltaEnd.Y + e.Location.Y);
this.Refresh();
}
}
private void Form1_MouseUp(object sender, MouseEventArgs e)
{
dragging = false;
}
现在你应该能够点击线的5像素内,并使其移动与您的鼠标。
注意,代码中有一些地方需要额外的错误处理,特别是处理除0的错误。
我建议你创建一个矩形,它是线的宽度和线的长度,然后你可以使用
if(rectangle.Contains(Point p))
{
// do your move
}
你也可以用:
增大矩形使其更容易抓取rectangle.Inflate(1, 1);