WPF Canvas draw circle,triangle,rectangle such as mark

image

 

 

 

 

 

 

image

 

 

 

 

 

 

image

 

 

 

 

 

 

 

image

 

 

 

//Window.xaml
<Window x:Class="WpfApp15.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp15"
        mc:Ignorable="d"
        WindowState="Maximized"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <StackPanel Grid.Row="0"
                    Orientation="Horizontal"
                    >
            <StackPanel.Resources>
                <Style TargetType="CheckBox">
                    <Setter Property="FontSize" Value="50"/>
                </Style>
            </StackPanel.Resources>
            <CheckBox Content="Triangle" x:Name="triangleChx"                      
                      Checked="triangleCbx_Checked"/>
            <CheckBox Content="Circle" x:Name="circleChx" 
                      Checked="circleCbx_Checked"/>
            <CheckBox Content="Rectangle" x:Name="rectangleChx"
                      Checked="rectangleChx_Checked"/>
        </StackPanel>
        <Canvas Grid.Row="1"
                x:Name="cvs"
                HorizontalAlignment="Stretch"
                VerticalAlignment="Stretch"
                Background="Transparent"
                MouseLeftButtonDown="cvs_MouseLeftButtonDown"/>
    </Grid>
</Window>


//Window.xaml.cs
using Microsoft.Win32;
using System.IO;
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;

namespace WpfApp15
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private double sideLength = 100.0d;
        int idx = 0;
        public MainWindow()
        {
            InitializeComponent();
        }

        private void cvs_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            var pt = Mouse.GetPosition(cvs);
            if (triangleChx.IsChecked == true)
            {
                DrawTriangle(pt);
            }
            else if (circleChx.IsChecked == true)
            {
                DrawCircle(pt);
            }
            else if (rectangleChx.IsChecked == true)
            {
                DrawRectangle(pt);
            }
        }

        private void DrawRectangle(Point pt)
        {
            Rectangle rect = new Rectangle();
            rect.Fill = new SolidColorBrush(Colors.Blue);
            rect.Stroke = Brushes.Black;  
            rect.StrokeThickness = 2;
            rect.Width= sideLength;
            rect.Height= sideLength;
            rect.ToolTip = $"{++idx},Center.X:{pt.X},Center.Y:{pt.Y}";
            Canvas.SetLeft(rect, pt.X - sideLength / 2);
            Canvas.SetTop(rect, pt.Y - sideLength / 2);
            cvs.Children.Add(rect);
        }

        private void DrawCircle(Point pt)
        {
            Ellipse elp=new Ellipse();
            elp.Width= sideLength;
            elp.Height= sideLength;
            elp.Stroke = Brushes.Black;
            elp.StrokeThickness = 2;            
            elp.Fill = new SolidColorBrush(Colors.Cyan);
            elp.ToolTip =$"{++idx},Center.X:{pt.X},Center.Y:{pt.Y}";
            Canvas.SetLeft(elp, pt.X - sideLength / 2);
            Canvas.SetTop(elp, pt.Y - sideLength / 2);
            cvs.Children.Add(elp);
        }

        private void DrawTriangle(Point centerPt)
        {
            try
            {
                double centerX = centerPt.X;
                double centerY = centerPt.Y;

                double height = (Math.Sqrt(3) / 2) * sideLength;

                Point topPt = new Point(centerX, centerY - height / 2);
                Point leftPt = new Point(centerX - sideLength / 2, centerY + height / 2);
                Point rightPt = new Point(centerX + sideLength / 2, centerY + height / 2);

                var triangle = new Polygon()
                {
                    Stroke = Brushes.Black,
                    StrokeThickness = 2,
                    Fill = Brushes.Red
                };

                triangle.Points.Add(topPt);
                triangle.Points.Add(leftPt);
                triangle.Points.Add(rightPt);
                triangle.ToolTip = $"Id:{++idx},Center.X:{centerPt.X},Center.Y:{centerPt.Y}";
                CreateTriagnleWithContextMenu(triangle);
                cvs.Children.Add(triangle);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void CreateTriagnleWithContextMenu(Polygon triangle)
        {
            ContextMenu contextMenu = new ContextMenu();

            //Save As Picture menu item.
            MenuItem saveMenuItem = new MenuItem();
            saveMenuItem.Header = "Save As Picture";
            saveMenuItem.Tag = triangle;
            saveMenuItem.Click += (s, e) => SaveTriangleAsPicture(s, e);

            //Remove
            MenuItem removeItem = new MenuItem();
            removeItem.Header = "Remove Triangle";
            removeItem.Tag = triangle;
            removeItem.Click += (s, e) => RemoveTriangle(s, e);

            contextMenu.Items.Add(saveMenuItem);
            contextMenu.Items.Add(removeItem);

            triangle.ContextMenu = contextMenu;

            triangle.MouseRightButtonDown += (s, e) =>
            {
                triangle.ContextMenu.IsOpen = true;
                e.Handled = true;
            };
        }

        private void RemoveTriangle(object sender, RoutedEventArgs e)
        {
            try
            {
                var triangle = (sender as MenuItem)?.Tag as Polygon;
                if (triangle != null)
                {
                    cvs.Children.Remove(triangle);
                    triangle = null;
                    MessageBox.Show("Triangle has been removed!");
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void SaveTriangleAsPicture(object sender, RoutedEventArgs e)
        {
            var triangle = (sender as MenuItem)?.Tag as Polygon;
            if (triangle == null)
            {
                MessageBox.Show("No triangle to save!");
                return;
            }

            try
            {
                SaveFileDialog dialog = new SaveFileDialog()
                {
                    Filter = "PNG Image|*.png|Jpeg Image|*.jpg|BMP Image|*.bmp",
                    Title = "Save Triangle as Picture",
                    FileName = $"Triangle_{DateTime.Now:yyyyMMddHHmmssffff}.png"
                };

                if (dialog.ShowDialog() == true)
                {
                    BitmapEncoder bmpEncoder = System.IO.Path.GetExtension(dialog.FileName).ToLower() switch
                    {
                        ".jpg" or ".jpeg" => new JpegBitmapEncoder(),
                        ".bmp" => new BmpBitmapEncoder(),
                        _ => new PngBitmapEncoder()
                    };

                    // Calculate the bounds of the triangle
                    Rect bounds = GetTriangleBounds(triangle);

                    // Add some padding around the triangle
                    double padding = 10;
                    bounds = new Rect(
                        bounds.X - padding,
                        bounds.Y - padding,
                        bounds.Width + padding * 2,
                        bounds.Height + padding * 2);

                    // Create a visual for the triangle only
                    DrawingVisual drawingVisual = new DrawingVisual();
                    using (DrawingContext drawingContext = drawingVisual.RenderOpen())
                    {
                        // Draw white background
                        drawingContext.DrawRectangle(Brushes.White, null, bounds);

                        // Draw the triangle
                        DrawTriangleGeometry(drawingContext, triangle, bounds);
                    }

                    var dpi = VisualTreeHelper.GetDpi(this);

                    // Render the visual to bitmap
                    RenderTargetBitmap rtb = new RenderTargetBitmap(
                        (int)(bounds.Width * dpi.DpiScaleX),
                        (int)(bounds.Height * dpi.DpiScaleY),
                        dpi.PixelsPerInchX,
                        dpi.PixelsPerInchY,
                        PixelFormats.Pbgra32);

                    rtb.Render(drawingVisual);

                    // Save to file
                    using (FileStream fileStream = new FileStream(dialog.FileName, FileMode.Create))
                    {
                        bmpEncoder.Frames.Add(BitmapFrame.Create(rtb));
                        bmpEncoder.Save(fileStream);
                    }

                    MessageBox.Show($"Triangle saved as {dialog.FileName} successfully!");
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private Rect GetTriangleBounds(Polygon triangle)
        {
            if (triangle.Points.Count == 0)
            {
                return new Rect(0, 0, sideLength, sideLength);
            }

            double minX = triangle.Points[0].X;
            double maxX = triangle.Points[0].X;
            double minY = triangle.Points[0].Y;
            double maxY = triangle.Points[0].Y;

            foreach (Point point in triangle.Points)
            {
                if (point.X < minX)
                {
                    minX = point.X;
                }
                if (point.X > maxX)
                {
                    maxX = point.X;
                }
                if (point.Y < minY)
                {
                    minY = point.Y;
                }
                if (point.Y > maxY)
                {
                    maxY = point.Y;
                }
            }
            return new Rect(minX, minY, maxX - minX, maxY - minY);
        }

        private void DrawTriangleGeometry(DrawingContext drawingContext,
            Polygon triangle, Rect bounds)
        {
            // Create a stream geometry for the triangle
            StreamGeometry geometry = new StreamGeometry();
            using (StreamGeometryContext streamGeoContext = geometry.Open())
            {
                streamGeoContext.BeginFigure(triangle.Points[0], true, true);
                streamGeoContext.PolyLineTo(new List<Point>(triangle.Points), true, true);
            }

            // Apply translation to position the triangle correctly
            TransformGroup transformGroup = new TransformGroup();
            transformGroup.Children.Add(new TranslateTransform(-bounds.X, -bounds.Y));

            geometry.Transform = transformGroup;
            geometry.Freeze();

            // Draw the triangle with the same properties as the original
            drawingContext.DrawGeometry(triangle.Fill, new Pen(triangle.Stroke,
                triangle.StrokeThickness), geometry);
        }

        private void triangleCbx_Checked(object sender, RoutedEventArgs e)
        {
            circleChx.IsChecked = false;
            rectangleChx.IsChecked = false;
        }

        private void circleCbx_Checked(object sender, RoutedEventArgs e)
        {
            triangleChx.IsChecked = false;
            rectangleChx.IsChecked = false;
        }

        private void rectangleChx_Checked(object sender, RoutedEventArgs e)
        {
            circleChx.IsChecked = false;
            triangleChx.IsChecked = false;
        }
    }
}

 

posted @ 2025-09-27 21:54  FredGrit  阅读(25)  评论(0)    收藏  举报