WPF:使用鼠标在Canvas面板上画线

          主要使用布局面板Canvas作为背景,通过其属性Children添加Line 来实现画线。可以理解为 每一个Line 就是一个点。

     不清楚Canvas的用法可以参见:点击打开链接  Line的参见:点击打开链接

代码解析

         线由点组成,当然我这里的点其实就是线。线由开始点与结束点构成,想必看到过msdn上line的解释就会一目了然。至于鼠标事件,会有鼠标左键按下以及移动,松开动作。 还需要有个一集合来存放点,取名为List<Point> 类型。  在鼠标按下事件中可以这样写:

        

/// <summary>
        /// 起始位置
        /// </summary>
        Point startPoint;
        /// <summary>
        /// 点集合
        /// </summary>
        List<Point> pointList = new List<Point>();
        /// <summary>
        /// 鼠标左键按下获取开始Point
        /// </summary>
        private void Canvas_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            startPoint = e.GetPosition(myCanvas);
        }

  记录开始位置startPoint 。按下之后随之的就是Move动作,在移动事件中这样写:

/// <summary>
        /// 按下鼠标左键移动
        /// </summary>
        private void Canvas_PreviewMouseMove(object sender, MouseEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed)
            {
                // 返回指针相对于Canvas的位置
                Point point = e.GetPosition(myCanvas);
 
                if (pointList.Count == 0)
                {
                    // 加入起始点
                    pointList.Add(new Point(this.startPoint.X, this.startPoint.Y));
                }
                else
                {
                    // 加入移动过程中的point
                    pointList.Add(point);
                }
 
                // 去重复点
                var disList = pointList.Distinct().ToList();
                var count = disList.Count(); // 总点数
                if (point != this.startPoint && this.startPoint != null)
                {
                    var l = new Line();
                    string color = (cboColor.SelectedItem as ComboBoxItem).Content as string;
 
                    if (color == "默认")
                    {
                        l.Stroke = Brushes.Black;
                    }
                    if (color == "红色")
                    {
                        l.Stroke = Brushes.Red;
                    }
                    if (color == "绿色")
                    {
                        l.Stroke = Brushes.Green;
                    }
                    l.StrokeThickness = 1;
                    if (count < 2)
                        return;
                    l.X1 = disList[count - 2].X;  // count-2  保证 line的起始点为点集合中的倒数第二个点。
                    l.Y1 = disList[count - 2].Y;
                    // 终点X,Y 为当前point的X,Y
                    l.X2 = point.X;
                    l.Y2 = point.Y;
                    myCanvas.Children.Add(l);
                }
            }
        }

  移动过程中创建Line对象并加入Canvas中。    代码中的颜色判断最好修改成枚举类型。

/// <summary>
        /// 选择颜色
        /// </summary>
        private void cboColor_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            string color = (cboColor.SelectedItem as ComboBoxItem).Content as string;
            if (this.myCanvas != null)
            {
 
                List<Line> list = GetChildObjects<Line>(this.myCanvas);
                if (list.Count > 0)
                {
                    list.ForEach(l =>
                    {
                        if (color == "默认")
                        {
                            l.Stroke = Brushes.Black;
                        }
                        if (color == "红色")
                        {
                            l.Stroke = Brushes.Red;
                        }
                        if (color == "绿色")
                        {
                            l.Stroke = Brushes.Green;
                        }
                    });
                    list.Clear();
                }
            }
        }
/// <summary>
        /// 选择style
        /// </summary>
        private void cboStyle_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            string style = (cboStyle.SelectedItem as ComboBoxItem).Content as string;
            if (this.myCanvas == null)
            {
                return;
            }
            List<Line> list = GetChildObjects<Line>(this.myCanvas);
            if (list.Count > 0)
            {
                list.ForEach(l =>
                {
                    if (style == "默认")
                    {
                        l.StrokeDashArray = new DoubleCollection(new List<double>() { });
                    }
                    if (style == "虚线")
                    {
                        l.StrokeDashArray = new DoubleCollection(new List<double>() { 
                     1,1,1,1
                    });
                    }
                });
                list.Clear();
            }
        }

前台XAML

              主要用到了WrapPanel,StackPanel布局控件。

<WrapPanel>
        <StackPanel>
            <WrapPanel>
                <Label Content="颜色:" VerticalAlignment="Center"></Label>
                <ComboBox x:Name="cboColor" SelectedIndex="0" Width="120" Margin="10" SelectionChanged="cboColor_SelectionChanged">
                    <ComboBoxItem>默认</ComboBoxItem>
                    <ComboBoxItem>红色</ComboBoxItem>
                    <ComboBoxItem>绿色</ComboBoxItem>
                </ComboBox>
            </WrapPanel>
            <WrapPanel>
                <Label Content="样式:" VerticalAlignment="Center"></Label>
                <ComboBox x:Name="cboStyle" Width="120" Margin="10" SelectionChanged="cboStyle_SelectionChanged">
                    <ComboBoxItem IsSelected="True">默认</ComboBoxItem>
                    <ComboBoxItem>虚线</ComboBoxItem>
                </ComboBox>
            </WrapPanel>
        </StackPanel>
        <Canvas Width="500" Height="500" Background="Gray" x:Name="myCanvas" PreviewMouseLeftButtonDown="Canvas_PreviewMouseLeftButtonDown" PreviewMouseMove="Canvas_PreviewMouseMove">
        </Canvas>
    </WrapPanel>
   /// <summary>
        /// 获得指定元素的所有子元素
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public List<T> GetChildObjects<T>(DependencyObject obj) where T : FrameworkElement
        {
            DependencyObject child = null;
            List<T> childList = new List<T>();

            for (int i = 0; i <= VisualTreeHelper.GetChildrenCount(obj) - 1; i++)
            {
                child = VisualTreeHelper.GetChild(obj, i);

                if (child is T)
                {
                    childList.Add((T)child);
                }
                childList.AddRange(GetChildObjects<T>(child));
            }
            return childList;
        }

 

WPF 中,可以使用鼠标事件和 Canvas.SetLeft / Canvas.SetTop 方法来实现拖动控件在 Canvas 上移动的效果。以下是一个示例: ```xaml <Canvas> <Button Content="Drag me!" Canvas.Left="50" Canvas.Top="50" MouseLeftButtonDown="Button_MouseLeftButtonDown" MouseMove="Button_MouseMove" MouseLeftButtonUp="Button_MouseLeftButtonUp"/> </Canvas> ``` 在代码中,我们为 Button 控件注册了三个鼠标事件:MouseLeftButtonDown、MouseMove 和 MouseLeftButtonUp。这三个事件将分别在鼠标按下、移动和松开时触发。 ```csharp private bool isDragging; private Point startPoint; private void Button_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { // 开始拖动 isDragging = true; startPoint = e.GetPosition(null); ((UIElement)sender).CaptureMouse(); } private void Button_MouseMove(object sender, MouseEventArgs e) { if (isDragging) { // 计算拖动距离 Point mousePos = e.GetPosition(null); Vector diff = startPoint - mousePos; // 移动控件 Button button = sender as Button; double left = Canvas.GetLeft(button); double top = Canvas.GetTop(button); Canvas.SetLeft(button, left - diff.X); Canvas.SetTop(button, top - diff.Y); // 更新起始点 startPoint = mousePos; } } private void Button_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { // 结束拖动 isDragging = false; ((UIElement)sender).ReleaseMouseCapture(); } ``` 在这个示例中,我们首先定义了两个变量:isDragging 和 startPoint。isDragging 变量表示当前是否正在拖动控件,startPoint 变量表示拖动开始时鼠标的位置。 在 MouseLeftButtonDown 事件中,我们将 isDragging 设为 true,并记录当前鼠标的位置。然后,我们调用 CaptureMouse 方法来捕获鼠标,以确保鼠标移动事件被正确处理。 在 MouseMove 事件中,我们首先判断当前是否正在拖动。如果是,就计算出当前鼠标位置和上一次鼠标位置的差值,然后使用 Canvas.SetLeft 和 Canvas.SetTop 方法更新控件的位置。最后,我们将当前鼠标位置保存到 startPoint 变量中,以便下一次计算差值。 在 MouseLeftButtonUp 事件中,我们将 isDragging 设为 false,并调用 ReleaseMouseCapture 方法来释放鼠标捕获。 通过这种方式,我们就可以实现在 Canvas 上拖动控件移动的效果。如果需要支持多个控件同时拖动,可以使用类似的方法为每个控件注册鼠标事件。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值