繁体   English   中英

如何让用户在WPF中使用画布绘制一条线

[英]How to let a user draw a line using a canvas in WPF

我正在尝试制作一个简单的图像编辑器,用户可以在其中加载图像并在其上绘制箭头,文本和矩形。

现在我有一个带有一些按钮的窗口和一个带有画布的视图框,里面有一个图像。

基本上,用户可以单击箭头按钮,单击画布上的某个位置,移动显示线条的鼠标,然后单击其他位置以实际绘制线条。

如何在单击绘制按钮后告诉画布开始侦听鼠标单击? 这是我到目前为止所拥有的。

<Window x:Class="ImageEditor.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="600" Width="800">
    <Window.CommandBindings>
        <CommandBinding Command="local:CapturePointsCommand" Executed="CommandBinding_Executed" CanExecute="CommandBinding_CanExecute"/>
    </Window.CommandBindings>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Button Grid.Row="0" Name="_drawArrow" Height="69" Width="69" Click="_drawArrow_Click" HorizontalAlignment="Left" Margin="5,5,0,5">
            <Image Source="Media/arrow.png"/>
        </Button>
        <Button Grid.Row="0" Name="_drawBox" Height="69" Width="69" Click="_drawBox_Click" HorizontalAlignment="Left" Margin="79,5,0,5">
            <Image Source="Media/rectangle.png"/>
        </Button>
        <Button Grid.Row="0" Name="_drawText" Height="69" Width="69" Click="_drawText_Click" HorizontalAlignment="Left" Margin="153,5,0,5">
            <Image Source="Media/text.png"/>
        </Button>
        <Viewbox Grid.Row="1">
            <Canvas Name="_canvas" Height="{Binding Height, ElementName=_picture}" Width="{Binding Width, ElementName=_picture}" MouseLeftButtonUp="_canvas_MouseLeftButtonUp">
                <Image  Name="_picture" Source="{Binding Image}" Height="488" Width="800"/>
            </Canvas>
        </Viewbox>
        <Button Grid.Row="2" HorizontalAlignment="Right" Name="_Load_Button" Content="Load" Margin="0,5,5,5" Width="75" Height="23" Click="_Load_Button_Click" />
        <Button Grid.Row="2" HorizontalAlignment="Right" Name="_Save_Button" Content="Save" Margin="0,5,85,5" Width="75" Height="23" Click="_Save_Button_Click" />
        <Button Grid.Row="2" HorizontalAlignment="Right" Name="_Cancel_Button" Content="Cancel" Margin="0,5,165,5" Width="75" Height="23" Click="_Cancel_Button_Click" />
        <Button Grid.Row="2" HorizontalAlignment="Right" Name="_Reset_Button" Content="Reset" Margin="0,5,245,5" Width="75" Height="23" Click="_Reset_Button_Click" />
    </Grid>
</Window>

以此作为代码背后:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Forms;
using System.IO;

namespace ImageEditor
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public static readonly RoutedCommand CapturePointsCommand = new RoutedCommand();

        private ImageSource _image;

        public MainWindow()
        {
            InitializeComponent();
        }

        public ImageSource Image
        {
            get
            {
                return this._image;
            }
            set
            {
                this._image = value;
            }
        }

        private List<Point> _points = new List<Point>();

        public List<Point> Points
        {
            get
            {
                return this._points;
            }
            set
            {
                this._points = value;
            }
        }

        private void _Save_Button_Click(object sender, RoutedEventArgs e)
        {
            if (Image == null)
                System.Windows.Forms.MessageBox.Show("There is nothing to save");
            else
            {
                Image = this._picture.Source;
                this.Close();
            }
        }

        private void _Reset_Button_Click(object sender, RoutedEventArgs e)
        {
            this._picture.Source = Image;
        }

        private void _Cancel_Button_Click(object sender, RoutedEventArgs e)
        {
            Image = null;
            this._picture.Source = null;
            this.Close();
        }

        private void _Load_Button_Click(object sender, RoutedEventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            string path;
            if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                path = ofd.FileName;
                Uri pathUri = new Uri(path);
                PngBitmapDecoder decoder = new PngBitmapDecoder(pathUri, BitmapCreateOptions.None, BitmapCacheOption.None);
                BitmapSource pathSrc = decoder.Frames[0];
                Image = pathSrc;
                this._picture.Source = Image;
            }
            else
            {
                path = null;
            }
        }

        private void _drawArrow_Click(object sender, RoutedEventArgs e)
        {
            Line line = new Line();
            line.Stroke = Brushes.Black;
            line.X1 = Points[0].X;
            line.Y1 = Points[0].Y;
            line.X2 = Points[1].X;
            line.Y2 = Points[1].Y;

            this._canvas.Children.Add(line);
        }

        private void _drawBox_Click(object sender, RoutedEventArgs e)
        {

        }

        private void _drawText_Click(object sender, RoutedEventArgs e)
        {

        }

        private void _canvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            Point p = Mouse.GetPosition(_canvas);
            Points.Add(p);
        }

        private void _drawArrow_MouseDown(object sender, MouseButtonEventArgs e)
        {

        }

        private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
        {

        }

        private void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {

        }
    }
}

下面的代码为我提供了可以适应您的功能。

枚举是您希望用户能够绘制的所有不同形状的列表。 您实现的按钮应设置activeShapeType值。 将绘制矩形,圆等的方法添加到Canvas_MouseLeftButtonDown事件中的switch语句。

右键单击事件将允许用户在第二次单击之前取消他们正在绘制的线。

    public bool IsFirstPoint = true;
    public Point StartPoint;
    public enum ShapeType
    {
        line,
        circle, 
        rectangle
    }
    public ShapeType activeShapeType = ShapeType.line;


    private void Canvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        if (IsFirstPoint)
        {
            StartPoint = (Mouse.GetPosition(Surface));
            IsFirstPoint = false;
        }
        else
        {
            switch (activeShapeType)
            {
                case ShapeType.line:
                    Line line = new Line() { X1 = StartPoint.X, Y1 = StartPoint.Y, X2 = Mouse.GetPosition(Surface).X, Y2 = Mouse.GetPosition(Surface).Y, Stroke = Brushes.Black };
                    Surface.Children.Add(line);
                    break;
                case ShapeType.rectangle:
                   /*Your code to draw rectangle here*/
                   break;
            }
            IsFirstPoint = true;
        }
    }

    private void Surface_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
    {
        IsFirstPoint = true;
    }

此代码应在移动鼠标时添加临时行。

private void Surface_MouseMove(object sender, MouseEventArgs e)
    {
        if (!IsFirstPoint)
        {

            if (Surface.Children.Count > 0)
            {
                var child = (from c in Surface.Children.OfType<FrameworkElement>()
                             where "tempLine".Equals(c.Tag)
                             select c).First();
                if (child != null)
                {
                    Surface.Children.Remove(child);
                }
            }


            switch (activeShapeType)
            {
                case ShapeType.line:
                    Line line = new Line() { Tag="tempLine", X1 = StartPoints.X, Y1 = StartPoints.Y, X2 = Mouse.GetPosition(Surface).X, Y2 = Mouse.GetPosition(Surface).Y, Stroke = Brushes.Black };
                    Surface.Children.Add(line);                      


                    return;
            }
        }
    }

我使用InkCanvas,绘图和向画布添加符号做了类似的事情。

但是我用bool控制了大部分的东西,所以你知道当你点击按钮时你所处的状态。

然后,当你点击画布时,状态用于表示我处于方形/箭头状态,这就是我应该画的。 然而。 我认为你在寻找的是

向下,向上移动功能。

单击画布mousedown时,您将获得想要开始绘制图形的位置,当您按下鼠标时移动鼠标时,可以执行拖动动画,或者跳过该动画并直接转到画布上释放的位置。 获得另一个位置,然后从那些位置画出线条..

x1,y1(画布上的mousedown位置)x2,y2(画布上的mouseup)我现在没有时间提供一个例子,因为我正在回家的路上,但它不应该太难,只需要分解它在您单击之前,从您所在的位置向前移动一小步。

希望这有任何帮助。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM