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

时间:2014-02-28 13:35:51

标签: c# wpf wpf-controls image-editing

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

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

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

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

<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)
        {

        }
    }
}

2 个答案:

答案 0 :(得分:2)

以下代码为我提供了适合您的功能。

枚举是您希望用户能够绘制的所有不同形状的列表。您实现的按钮应设置 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;
            }
        }
    }

答案 1 :(得分:0)

我使用InkCanvas做了类似的事情,绘制并在画布上添加符号。

然而,我用bool控制了大部分事情,所以当你点击一个按钮时,你知道你所处的状态。

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

我认为您正在寻找的是什么

向下,向上移动功能。

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

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

希望这有任何帮助。