【问题标题】:Not able to draw rectangle on Wpf canvas from lower right corner to upper left corner无法在 Wpf 画布上从右下角到左上角绘制矩形
【发布时间】:2017-10-05 09:38:29
【问题描述】:

我正在实现允许用户在运行时通过拖动鼠标在 Wpf 画布上绘制矩形的功能。当我将鼠标从左上角拖动到左下角时,我目前能够绘制矩形,但矩形是当我将鼠标从左下角拖到顶部时不可见。下面是我正在使用的 xaml 代码:

<Canvas x:Name="CanvasContainer" MouseLeftButtonDown="CanvasContainer_MouseLeftButtonDown" MouseLeftButtonUp="CanvasContainer_MouseLeftButtonUp" MouseMove="CanvasContainer_MouseMove" >
   <Rectangle  x:Name="RectangleMarker" Canvas.Left="0"  Stroke="Red" Width="0" Height="0" Panel.ZIndex="1"></Rectangle>
   <Line x:Name="LineMarker"  Stroke="Red" X1="0" Y1="0" X2="0" Y2="0"></Line>
   <Image Canvas.Left="0" Canvas.Top="0"  x:Name="PdfImage" RenderTransformOrigin="0.5,0.5" MouseWheel="PdfImage_MouseWheel"  ClipToBounds="True" Panel.ZIndex="0">
        <Image.LayoutTransform>
            <ScaleTransform ScaleX="1" ScaleY="1"  CenterX="0.5" CenterY="0.5"  />
        </Image.LayoutTransform>
    </Image>
</Canvas>

以下是根据鼠标位置更新矩形位置的事件处理。

private void CanvasContainer_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    try
    {          
            Point startPoint = Mouse.GetPosition(CanvasContainer);
            Canvas.SetLeft(RectangleMarker, startPoint.X);
            Canvas.SetTop(RectangleMarker,startPoint.Y);      
    }
    catch (Exception ex)
    {

    }
}

private void CanvasContainer_MouseMove(object sender, MouseEventArgs e)
{
    try
    {
        if (e.LeftButton == MouseButtonState.Pressed)
        {               
                Point endPoint = Mouse.GetPosition(CanvasContainer);
                Point startPoint = new Point((double)RectangleMarker.GetValue(Canvas.LeftProperty), (double)RectangleMarker.GetValue(Canvas.TopProperty));
                double x = Math.Min(startPoint.X, endPoint.X);
                double y = Math.Min(startPoint.Y, endPoint.Y);
                double width = endPoint.X - startPoint.X;
                double height = endPoint.Y - startPoint.Y;

                if (width < 0)
                {
                    x = startPoint.X + width;
                }
                if (height < 0)
                {
                    y = startPoint.Y + height;
                }
                RectangleMarker.Width = Math.Abs(width);
                RectangleMarker.Height = Math.Abs(height);
                if (x!=startPoint.X)
                {
                    Canvas.SetLeft(RectangleMarker, x);
                }
                else if(y!=startPoint.Y)
                {
                    Canvas.SetTop(RectangleMarker, y); 
                }                
        }          
    }
    catch (Exception ex)
    {

    }
}

【问题讨论】:

  • @Sinatr 我不想画第二个矩形,只想移动现有的矩形。
  • @Sinatr 我的意思是像我们在绘画工具中那样绘制矩形。按住鼠标拖动绘制矩形。如果是向下对角线方向(UL 到 LR)拖动,则可以,但如果我们向上对角线方向(LR 到 UL)拖动,则矩形是不可见的。跨度>

标签: c# wpf rectangles


【解决方案1】:

最好使用带有 RectangleGeometry 的路径:

<Canvas Background="Transparent"
        MouseLeftButtonDown="CanvasContainer_MouseLeftButtonDown"
        MouseLeftButtonUp="CanvasContainer_MouseLeftButtonUp"
        MouseMove="CanvasContainer_MouseMove">
    <Path Stroke="Red">
        <Path.Data>
            <RectangleGeometry x:Name="selectionRect"/>
        </Path.Data>
    </Path>
</Canvas>

后面的代码:

private Point? startPoint;

private void CanvasContainer_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    var element = (UIElement)sender;
    element.CaptureMouse();
    startPoint = e.GetPosition(element);
}

private void CanvasContainer_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
    ((UIElement)sender).ReleaseMouseCapture();
    startPoint = null;
}

private void CanvasContainer_MouseMove(object sender, MouseEventArgs e)
{
    if (startPoint.HasValue)
    {
        selectionRect.Rect = new Rect(
            startPoint.Value, e.GetPosition((IInputElement)sender));
    }
}

【讨论】:

    【解决方案2】:

    正如我之前在评论中提到的,您的问题不是绘图,而是调整大小

    调整矩形大小时,有 4 个可能的方向,4 个边和 4 个角。所以有点复杂。

    最简单的方法是简单地记住开始鼠标位置,然后检查位置在哪里,在它们之间绘制矩形。显然,新的鼠标位置可以是任意一个角,具体取决于鼠标相对于起点的移动方向。

    所以:

    Point _start;
    
    void CanvasContainer_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) =>
        _start = Mouse.GetPosition(CanvasContainer);
    
    void CanvasContainer_MouseMove(object sender, MouseEventArgs e)
    {
        if (e.LeftButton == MouseButtonState.Pressed)
        {
            var mouse = Mouse.GetPosition(CanvasContainer);
            Canvas.SetLeft(RectangleMarker, _start.X > mouse.X ? mouse.X : _start.X);
            Canvas.SetTop(RectangleMarker, _start.Y > mouse.Y ? mouse.Y : _start.Y);
            RectangleMarker.Width = Math.Abs(mouse.X - _start.X);
            RectangleMarker.Height = Math.Abs(mouse.Y - _start.Y);
        }
    }
    

    Math.Abs 将处理正向或负向更改的大小调整,而对于更改位置,我们仍然需要条件检查来确定左上角是哪个点(起始点或新鼠标)。

    演示:

    【讨论】:

    • 我唯一缺少的是存储起点。谢谢。
    • “最简单的方法..”,不完全是。更简单的是从两个点创建一个矩形。无论每个 Point 代表什么确切的角,Rect 都将始终正确创建(如我的回答所示)。
    • @Clemens,这只是措辞。我喜欢你的解决方案。虽然我看不出如何让我的工作更容易。目的不是改变太多(至少是 xaml)。
    • 我正在使用@Clemens 解决方案,因为它需要的代码隐藏文件中的代码较少。但您的解决方案也有效。
    猜你喜欢
    • 1970-01-01
    • 2021-12-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-24
    相关资源
    最近更新 更多