【发布时间】:2016-03-01 16:08:50
【问题描述】:
所以,我正在 WPF 中创建一个类似绘画的程序。 在画布上,我具有以下功能:
- 画一条线
- 移动一行
- 旋转一行
为此,我有 3 个事件:MouseDown、MouseMove、MouseUp
当我开始在画布上绘图时,MouseDown & MouseMove 事件被完美触发。但是,MouseUp 没有被触发......当我在移动时绘图时会出现这个问题。在触发所有事件后调用绘图函数时,它可以正常工作。
Redraw 函数中的注释部分弄乱了 MouseUp 事件。评论时,该活动运行良好
代码:
namespace Roomplanner.Controls
{
/// <summary>
/// Interaction logic for DrawingControl.xaml
/// </summary>
public partial class DrawingControl : UserControl
{
//Size settings
private double _zoomLevel = 1.1;
private int _mapWidth = 765;
private int _mapHeight = 430;
private static MouseState _mouseState = MouseState.Idle;
//Wall variables
private List<Point> Pt1 = new List<Point>();
private List<Point> Pt2 = new List<Point>();
private Point _NewPt1, _NewPt2;
private bool _isDrawing = false;
private const int object_radius = 3;
// We're over an object if the distance squared
// between the mouse and the object is less than this.
private const int over_dist_squared = object_radius * object_radius;
public DrawingControl()
{
//Automated
InitializeComponent();
//
drawingCanvas.Width = _mapWidth;
drawingCanvas.Height = _mapHeight;
drawingCanvas.MouseWheel += DrawingCanvas_MouseWheel;
}
//==================================================================================
//MOUSE FUNCTIONS
//==================================================================================
private void DrawingCanvas_MouseDown(object sender, MouseButtonEventArgs e)
{
// See what we're over.
Point hit_point;
int segment_number;
if (MouseIsOverEndpoint(Mouse.GetPosition(drawingCanvas), out segment_number, out hit_point))
{
// Start moving this end point.
drawingCanvas.MouseMove -= DrawingCanvas_MouseMove_NotDown;
drawingCanvas.MouseMove += DrawingCanvas_MouseMove_MovingEndPoint;
drawingCanvas.MouseUp += DrawingCanvas_MouseUp_MovingEndPoint;
// Remember the segment number.
MovingSegment = segment_number;
// See if we're moving the start end point.
MovingStartEndPoint = (Pt1[segment_number].Equals(hit_point));
// Remember the offset from the mouse to the point.
OffsetX = hit_point.X - e.GetPosition(drawingCanvas).X;
OffsetY = hit_point.Y - e.GetPosition(drawingCanvas).Y;
}
else if (MouseIsOverSegment(Mouse.GetPosition(drawingCanvas), out segment_number))
{
// Start moving this segment.
drawingCanvas.MouseMove -= DrawingCanvas_MouseMove_NotDown;
drawingCanvas.MouseMove += DrawingCanvas_MouseMove_MovingSegment;
drawingCanvas.MouseUp += DrawingCanvas_MouseUp_MovingSegment;
// Remember the segment number.
MovingSegment = segment_number;
// Remember the offset from the mouse to the segment's first point.
OffsetX = Pt1[segment_number].X - e.GetPosition(drawingCanvas).X;
OffsetY = Pt1[segment_number].Y - e.GetPosition(drawingCanvas).Y;
}
else
{
// Start drawing a new segment.
drawingCanvas.MouseMove -= DrawingCanvas_MouseMove_NotDown;
drawingCanvas.MouseMove += DrawingCanvas_MouseMove_Drawing;
drawingCanvas.MouseUp += DrawingCanvas_MouseUp_Drawing;
_isDrawing = true;
_NewPt1 = new Point(e.GetPosition(drawingCanvas).X, e.GetPosition(drawingCanvas).Y);
_NewPt2 = new Point(e.GetPosition(drawingCanvas).X, e.GetPosition(drawingCanvas).Y);
}
}
// We're drawing a new segment.
private void DrawingCanvas_MouseMove_Drawing(object sender, MouseEventArgs e)
{
// Save the new point.
_NewPt2 = new Point(e.GetPosition(drawingCanvas).X, e.GetPosition(drawingCanvas).Y);
// Redraw.
Redraw();
}
// Stop drawing.
private void DrawingCanvas_MouseUp_Drawing(object sender, MouseEventArgs e)
{
_isDrawing = false;
Console.WriteLine("UP");
// Reset the event handlers.
drawingCanvas.MouseMove -= DrawingCanvas_MouseMove_Drawing;
drawingCanvas.MouseMove += DrawingCanvas_MouseMove_NotDown;
drawingCanvas.MouseUp -= DrawingCanvas_MouseUp_Drawing;
// Create the new segment.
Pt1.Add(_NewPt1);
Pt2.Add(_NewPt2);
// Redraw.
Redraw();
}
private void DrawingCanvas_MouseMove_NotDown(object sender, MouseEventArgs e)
{
//See what we're hovering
Point hit_point;
int segment_number;
Point curpos = Mouse.GetPosition(drawingCanvas);
if (MouseIsOverEndpoint(curpos, out segment_number, out hit_point))
Cursor = Cursors.Arrow;
else if (MouseIsOverSegment(curpos, out segment_number))
Cursor = Cursors.Hand;
}
private void DrawingCanvas_MouseWheel(object sender, MouseWheelEventArgs e)
{
if(e.Delta > 0)
{
sourceGridST.ScaleX *= _zoomLevel;
sourceGridST.ScaleY *= _zoomLevel;
}
else
{
sourceGridST.ScaleX /= _zoomLevel;
sourceGridST.ScaleY /= _zoomLevel;
}
}
// The segment we're moving or the segment whose end point we're moving.
private int MovingSegment = -1;
// The end point we're moving.
private bool MovingStartEndPoint = false;
// The offset from the mouse to the object being moved.
private double OffsetX, OffsetY;
// See if the mouse is over an end point.
private bool MouseIsOverEndpoint(Point mouse_pt, out int segment_number, out Point hit_pt)
{
for (int i = 0; i < Pt1.Count; i++)
{
// Check the starting point.
if (FindDistanceToPointSquared(mouse_pt, Pt1[i]) < over_dist_squared)
{
// We're over this point.
segment_number = i;
hit_pt = Pt1[i];
return true;
}
// Check the end point.
if (FindDistanceToPointSquared(mouse_pt, Pt2[i]) < over_dist_squared)
{
// We're over this point.
segment_number = i;
hit_pt = Pt2[i];
return true;
}
}
segment_number = -1;
hit_pt = new Point(-1, -1);
return false;
}
// See if the mouse is over a line segment.
private bool MouseIsOverSegment(Point mouse_pt, out int segment_number)
{
for (int i = 0; i < Pt1.Count; i++)
{
// See if we're over the segment.
Point closest;
if (FindDistanceToSegmentSquared(
mouse_pt, Pt1[i], Pt2[i], out closest)
< over_dist_squared)
{
// We're over this segment.
segment_number = i;
return true;
}
}
segment_number = -1;
return false;
}
#region "Moving End Point"
// We're moving an end point.
private void DrawingCanvas_MouseMove_MovingEndPoint(object sender, MouseEventArgs e)
{
// Move the point to its new location.
if (MovingStartEndPoint)
Pt1[MovingSegment] =
new Point(e.GetPosition(drawingCanvas).X + OffsetX, e.GetPosition(drawingCanvas).Y + OffsetY);
else
Pt2[MovingSegment] =
new Point(e.GetPosition(drawingCanvas).X + OffsetX, e.GetPosition(drawingCanvas).Y + OffsetY);
// Redraw.
Redraw();
}
// Stop moving the end point.
private void DrawingCanvas_MouseUp_MovingEndPoint(object sender, MouseEventArgs e)
{
// Reset the event handlers.
drawingCanvas.MouseMove += DrawingCanvas_MouseMove_NotDown;
drawingCanvas.MouseMove -= DrawingCanvas_MouseMove_MovingEndPoint;
drawingCanvas.MouseUp -= DrawingCanvas_MouseUp_MovingEndPoint;
// Redraw.
Redraw();
}
#endregion // Moving End Point
#region "Moving Segment"
// We're moving a segment.
private void DrawingCanvas_MouseMove_MovingSegment(object sender, MouseEventArgs e)
{
// See how far the first point will move.
double new_x1 = e.GetPosition(drawingCanvas).X + OffsetX;
double new_y1 = e.GetPosition(drawingCanvas).Y + OffsetY;
double dx = new_x1 - Pt1[MovingSegment].X;
double dy = new_y1 - Pt1[MovingSegment].Y;
if (dx == 0 && dy == 0) return;
// Move the segment to its new location.
Pt1[MovingSegment] = new Point(new_x1, new_y1);
Pt2[MovingSegment] = new Point(
Pt2[MovingSegment].X + dx,
Pt2[MovingSegment].Y + dy);
// Redraw.
Redraw();
}
// Stop moving the segment.
private void DrawingCanvas_MouseUp_MovingSegment(object sender, MouseEventArgs e)
{
// Reset the event handlers.
drawingCanvas.MouseMove += DrawingCanvas_MouseMove_NotDown;
drawingCanvas.MouseMove -= DrawingCanvas_MouseMove_MovingSegment;
drawingCanvas.MouseUp -= DrawingCanvas_MouseUp_MovingSegment;
// Redraw.
Redraw();
}
#endregion // Moving End Point
//==================================================================================
//END MOUSE FUNCTIONS
//==================================================================================
// Calculate the distance squared between two points.
private int FindDistanceToPointSquared(Point pt1, Point pt2)
{
int dx = (int)pt1.X - (int)pt2.X;
int dy = (int)pt1.Y - (int)pt2.Y;
return dx * dx + dy * dy;
}
// Calculate the distance squared between
// point pt and the segment p1 --> p2.
private double FindDistanceToSegmentSquared(Point pt, Point p1, Point p2, out Point closest)
{
float dx = (float)p2.X - (float)p1.X;
float dy = (float)p2.Y - (float)p1.Y;
if ((dx == 0) && (dy == 0))
{
// It's a point not a line segment.
closest = p1;
dx = (float)pt.X - (float)p1.X;
dy = (float)pt.Y - (float)p1.Y;
return dx * dx + dy * dy;
}
// Calculate the t that minimizes the distance.
float t = (float)((pt.X - p1.X) * dx + (pt.Y - p1.Y) * dy) / (dx * dx + dy * dy);
// See if this represents one of the segment's
// end points or a point in the middle.
if (t < 0)
{
closest = new Point(p1.X, p1.Y);
dx = (float)pt.X - (float)p1.X;
dy = (float)pt.Y - (float)p1.Y;
}
else if (t > 1)
{
closest = new Point(p2.X, p2.Y);
dx = (float)pt.X - (float)p2.X;
dy = (float)pt.Y - (float)p2.Y;
}
else
{
closest = new Point(p1.X + t * dx, p1.Y + t * dy);
dx = (float)pt.X - (float)closest.X;
dy = (float)pt.Y - (float)closest.Y;
}
return dx * dx + dy * dy;
}
private void DrawWalls(Line wall)
{
wall.Stroke = Brushes.Black;
drawingCanvas.Children.Add(wall);
}
private void ChangeSize(int x, int y)
{
drawingCanvas.Height = y;
drawingCanvas.Width = x;
}
private void Redraw()
{
drawingCanvas.Children.Clear();
// Draw the segments.
for (int i = 0; i < Pt1.Count; i++)
{
// Draw the segment
Line wall = new Line();
wall.X1 = Pt1[i].X;
wall.X2 = Pt2[i].X;
wall.Y1 = Pt1[i].Y;
wall.Y2 = Pt2[i].Y;
wall.Stroke = Brushes.Black;
drawingCanvas.Children.Add(wall);
}
// Draw the end points.
foreach (Point pt in Pt1)
{
Rectangle rect = new Rectangle();
rect.Stroke = Brushes.LightGray;
rect.Width = 6;
rect.Height = 6;
Canvas.SetTop(rect, pt.Y - object_radius);
Canvas.SetLeft(rect, pt.X - object_radius);
drawingCanvas.Children.Add(rect);
}
foreach (Point pt in Pt2)
{
Rectangle rect = new Rectangle();
rect.Stroke = Brushes.LightGray;
rect.Width = 6;
rect.Height = 6;
Canvas.SetTop(rect, pt.Y - object_radius);
Canvas.SetLeft(rect, pt.X - object_radius);
drawingCanvas.Children.Add(rect);
}
// If there's a new segment under constructions, draw it.
if (_isDrawing)
{
//When Uncommented the MouseUP event is never called
//Line wall = new Line();
//wall.X1 = _NewPt1.X;
//wall.X2 = _NewPt2.Y;
//wall.Y1 = _NewPt1.Y;
//wall.Y2 = _NewPt2.Y;
//wall.Stroke = Brushes.Black;
//drawingCanvas.Children.Add(wall);
}
}
private void btnSizeChanged_Click(object sender, RoutedEventArgs e)
{
ChangeSize(int.Parse(tbxHeight.Text), int.Parse( tbxWidth.Text));
}
private void MouseMove_(object sender, MouseEventArgs e)
{
}
private void btnDraw_Click(object sender, RoutedEventArgs e)
{
_mouseState = ( _mouseState == MouseState.DrawStart )? MouseState.DrawEnd : MouseState.DrawStart;
}
public enum MouseState
{
DrawStart, DrawEnd, Idle
}
}
}
【问题讨论】:
-
试试
PreviewMouseUp -
试过了,也试过 MouseLeftButtonUp
-
修复注释部分的代码,它甚至没有编译还记得你将鼠标向上事件绑定到画布,所以确保你在画布上释放鼠标而不是一些子元素。
-
我错了!当然!我怎么没想到……
-
@JanneMatikainen 非常感谢!解决了它:)