WPF實現點選穿透以及線擦的實時虛線
阿新 • • 發佈:2018-12-12
裡面的功能有:改變畫筆大小、改變畫筆顏色、改變橡皮擦的大小,線擦的區域擦除,修改滑鼠圖示以及點選穿透。 XAML:
<Window x:Class="WpfApplication2.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:WpfApplication2" mc:Ignorable="d" Loaded="Window_Loaded" Title="MainWindow" Height="350" Width="525" WindowStyle="None" AllowsTransparency="True" Background="Transparent"> <Grid x:Name="grid"> <InkCanvas x:Name="inkCanvas" Width="525" Height="350" MouseMove="MouseMove_Click" MouseLeftButtonDown="InkCanvas_MouseLeftButtonDown" MouseLeftButtonUp="InkCanvas_MouseLeftButtonUp"> <InkCanvas.Background> <SolidColorBrush Color="White" Opacity="0.01"></SolidColorBrush> </InkCanvas.Background> </InkCanvas> <Canvas Width="60" HorizontalAlignment="Right"> <RadioButton Click="RadioButton_Click0" Tag="5" Width="30" Height="20" Canvas.Top="20">5</RadioButton> <RadioButton Click="RadioButton_Click0" Tag="10" Width="30" Height="20" Canvas.Top="40">10</RadioButton> <RadioButton Click="RadioButton_Click0" Tag="15" Width="30" Height="20" Canvas.Top="60">15</RadioButton> <RadioButton Click="RadioButton_Click1" Tag="紅" Width="30" Height="20" Canvas.Top="100">紅</RadioButton> <RadioButton Click="RadioButton_Click1" Tag="綠" Width="30" Height="20" Canvas.Top="120">綠</RadioButton> <RadioButton Click="RadioButton_Click1" Tag="藍" Width="30" Height="20" Canvas.Top="140">藍</RadioButton> <RadioButton Click="RadioButton_Click" Tag="A" Width="55" Height="20" Canvas.Top="180">書寫</RadioButton> <RadioButton Click="RadioButton_Click" Tag="B" Width="55" Height="20" Canvas.Top="200">點擦小</RadioButton> <RadioButton Click="RadioButton_Click" Tag="C" Width="55" Height="20" Canvas.Top="220">點擦中</RadioButton> <RadioButton Click="RadioButton_Click" Tag="D" Width="55" Height="20" Canvas.Top="240">點擦大</RadioButton> <RadioButton Click="RadioButton_Click" Tag="E" Width="55" Height="20" Canvas.Top="260">線擦</RadioButton> <RadioButton Click="RadioButton_Click" Tag="F" Width="55" Height="20" Canvas.Top="280">清空</RadioButton> <RadioButton Click="RadioButton_Click" Tag="G" Width="55" Height="20" Canvas.Top="300">操作</RadioButton> </Canvas> </Grid> </Window>
cs:
using Microsoft.Win32.SafeHandles; using System; using System.Collections.Generic; using System.Drawing; using System.IO; using System.Runtime.InteropServices; using System.Security.Permissions; using System.Windows; using System.Windows.Controls; using System.Windows.Ink; using System.Windows.Input; using System.Windows.Interop; using System.Windows.Media; namespace WpfApplication2 { /// <summary> /// MainWindow.xaml 的互動邏輯 /// </summary> public partial class MainWindow : Window { DrawingAttributes drawingAttributes;//畫筆 System.Windows.Media.Brush bg;//儲存點選穿透前的Brush bool isEraseByPoint = false;//是否選擇橡皮擦 bool isEraseByPointStart = false;//是否開始使用橡皮擦功能 System.Windows.Point mousePoint;//滑鼠位置 double sizeX;//橡皮擦大小 bool isEraseByStroke = false; bool isEraseByStrokeStart = false; //------線擦----------- List<System.Windows.Point> pointList = new List<System.Windows.Point>(); StrokeCollection scTemp1 = new StrokeCollection(); List<System.Windows.Point> xcPoint = new List<System.Windows.Point>(); //--------------------- public MainWindow() { InitializeComponent(); drawingAttributes = new DrawingAttributes(); inkCanvas.DefaultDrawingAttributes = drawingAttributes; drawingAttributes.Color = Colors.Red;//設定畫筆顏色 drawingAttributes.Width = 5; drawingAttributes.Height = 5; drawingAttributes.FitToCurve = true;//曲線平滑 bg = inkCanvas.Background; sizeX = 5; inkCanvas.AddHandler(InkCanvas.MouseLeftButtonDownEvent, new MouseButtonEventHandler(this.InkCanvas_MouseLeftButtonDown), true); Topmost = true;//在除錯的時候需要註釋該行才可以檢視變數的值 } private void RadioButton_Click0(object sender, RoutedEventArgs e) { inkCanvas.UseCustomCursor = false; inkCanvas.Background = bg; isEraseByPoint = false; isEraseByStroke = false; inkCanvas.EditingMode = InkCanvasEditingMode.Ink;//書寫 if (Convert.ToString(((System.Windows.Controls.RadioButton)sender).Tag) == "5") { drawingAttributes.Width = 5; drawingAttributes.Height = 5; } if (Convert.ToString(((System.Windows.Controls.RadioButton)sender).Tag) == "10") { drawingAttributes.Width = 10; drawingAttributes.Height = 10; } if (Convert.ToString(((System.Windows.Controls.RadioButton)sender).Tag) == "15") { drawingAttributes.Width = 15; drawingAttributes.Height = 15; } } private void RadioButton_Click1(object sender, RoutedEventArgs e) { inkCanvas.UseCustomCursor = false; inkCanvas.Background = bg; isEraseByPoint = false; isEraseByStroke = false; inkCanvas.EditingMode = InkCanvasEditingMode.Ink;//書寫 if (Convert.ToString(((System.Windows.Controls.RadioButton)sender).Tag) == "紅") { drawingAttributes.Color = Colors.Red; } if (Convert.ToString(((System.Windows.Controls.RadioButton)sender).Tag) == "綠") { drawingAttributes.Color = Colors.Green; } if (Convert.ToString(((System.Windows.Controls.RadioButton)sender).Tag) == "藍") { drawingAttributes.Color = Colors.Blue; } } private void RadioButton_Click(object sender, RoutedEventArgs e) { inkCanvas.UseCustomCursor = false; inkCanvas.Background = bg; isEraseByPoint = false; isEraseByStroke = false; if (Convert.ToString(((System.Windows.Controls.RadioButton)sender).Tag) == "A") { inkCanvas.EditingMode = InkCanvasEditingMode.Ink; } if (Convert.ToString(((System.Windows.Controls.RadioButton)sender).Tag) == "B") { //方法一: isEraseByPoint = true; inkCanvas.EditingMode = InkCanvasEditingMode.None; sizeX = 5; inkCanvas.UseCustomCursor = true;//允許修改滑鼠圖示 inkCanvas.Cursor = CreateCursor("Image/xpc.ico", 8, 8);//設定滑鼠圖示 //方法二: //inkCanvas.EditingMode = InkCanvasEditingMode.EraseByPoint; //inkCanvas.EraserShape = new RectangleStylusShape(20, 20);//改變橡皮擦大小 } if (Convert.ToString(((System.Windows.Controls.RadioButton)sender).Tag) == "C") { isEraseByPoint = true; inkCanvas.EditingMode = InkCanvasEditingMode.None; sizeX = 10; inkCanvas.UseCustomCursor = true; inkCanvas.Cursor = CreateCursor("Image/xpc.ico", 14, 14); } if (Convert.ToString(((System.Windows.Controls.RadioButton)sender).Tag) == "D") { isEraseByPoint = true; inkCanvas.EditingMode = InkCanvasEditingMode.None; sizeX = 15; inkCanvas.UseCustomCursor = true; inkCanvas.Cursor = CreateCursor("Image/xpc.ico", 20, 20); } if (Convert.ToString(((System.Windows.Controls.RadioButton)sender).Tag) == "E") { inkCanvas.EditingMode = InkCanvasEditingMode.None; isEraseByStroke = true; inkCanvas.UseCustomCursor = true; inkCanvas.Cursor = CreateCursor("Image/Eraser.ico", 25, 25); } if (Convert.ToString(((System.Windows.Controls.RadioButton)sender).Tag) == "F") { inkCanvas.Strokes.Clear(); } if (Convert.ToString(((System.Windows.Controls.RadioButton)sender).Tag) == "G") { inkCanvas.Background = null; } } private void Window_Loaded(object sender, RoutedEventArgs e) { //設定全屏 this.WindowState = System.Windows.WindowState.Maximized; this.WindowStyle = System.Windows.WindowStyle.None; inkCanvas.Width = System.Windows.SystemParameters.PrimaryScreenWidth; inkCanvas.Height = System.Windows.SystemParameters.PrimaryScreenHeight; } //滑鼠單擊左鍵事件 private void InkCanvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { if (isEraseByPoint) { isEraseByPointStart = true; } if (isEraseByStroke) { xcPoint.Clear(); pointList.Clear(); useNum = 0; isEraseByStrokeStart = true; mousePoint = Mouse.GetPosition(e.Source as FrameworkElement); pointList.Add(mousePoint); xcPoint.Add(mousePoint); } } //滑鼠鬆開左鍵事件 private void InkCanvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { if (isEraseByPointStart) { isEraseByPointStart = false; } if (isEraseByStrokeStart) { isEraseByStrokeStart = false; #region StrokeCollection sc1 = inkCanvas.Strokes.HitTest(pointList, 1); inkCanvas.Strokes.Remove(sc1); try { scTemp1.Clear(); foreach (Stroke stroke in inkCanvas.Strokes) { for (int i = 0; i < pointList.Count; i++) { if (stroke.HitTest(pointList[i])) { scTemp1.Add(stroke); break; } } } if (scTemp1.Count != 0) { inkCanvas.Strokes.Remove(scTemp1); } } catch { } #endregion } } double ABlength; int useNum = 0; System.Windows.Point pInsert = new System.Windows.Point(); private void MouseMove_Click(object sender, System.Windows.Input.MouseEventArgs e) { if (isEraseByPointStart) { mousePoint = Mouse.GetPosition(e.Source as FrameworkElement);//獲取滑鼠的位置 try { foreach (Stroke stroke in inkCanvas.Strokes) { if (stroke.HitTest(mousePoint)) { Rect rect = new Rect((mousePoint.X - sizeX / 2), (mousePoint.Y - sizeX / 2), sizeX, sizeX);//繪製矩形橡皮擦 StrokeCollection eraseResults = stroke.GetEraseResult(rect); inkCanvas.Strokes.Replace(stroke, eraseResults); } } } catch { } } if (isEraseByStrokeStart) { mousePoint = Mouse.GetPosition(e.Source as FrameworkElement); pointList.Add(mousePoint); ABlength = Math.Sqrt(Math.Pow(mousePoint.X - xcPoint[xcPoint.Count - 1].X, 2) + Math.Pow(mousePoint.Y - xcPoint[xcPoint.Count - 1].Y, 2));//算出兩點的距離 if (ABlength >= 5 && ABlength <= 6) { xcPoint.Add(mousePoint); if (xcPoint.Count >= 2) { if (useNum < xcPoint.Count - 1) { List<System.Windows.Point> p = new List<System.Windows.Point>(); p.Add(xcPoint[useNum]); useNum++; p.Add(xcPoint[useNum]); useNum++; StylusPointCollection point = new StylusPointCollection(p); Stroke stroke = new Stroke(point); stroke.DrawingAttributes.Color = Colors.BlueViolet; inkCanvas.Strokes.Add(stroke); } } } else if (ABlength > 6) { pInsert = new System.Windows.Point(mousePoint.X - ((mousePoint.X - xcPoint[xcPoint.Count - 1].X) / 2), mousePoint.Y - ((mousePoint.Y - xcPoint[xcPoint.Count - 1].Y) / 2)); xcPoint.Add(pInsert); xcPoint.Add(mousePoint); if (xcPoint.Count >= 2) { if (useNum < xcPoint.Count - 1) { List<System.Windows.Point> p = new List<System.Windows.Point>(); p.Add(xcPoint[useNum]); useNum++; p.Add(xcPoint[useNum]); useNum++; StylusPointCollection point = new StylusPointCollection(p); Stroke stroke = new Stroke(point); stroke.DrawingAttributes.Color = Colors.BlueViolet; inkCanvas.Strokes.Add(stroke); } } } } } #region 建立滑鼠圖示 public static System.Windows.Input.Cursor CreateCursor(String filePath, int xHotSpot = 0, int yHotSpot = 0) { System.Windows.Input.Cursor ret = null; if (string.IsNullOrWhiteSpace(filePath) || Directory.Exists(filePath) || !File.Exists(filePath)) { return ret; } //首先嚐試通過預設方法建立 if (filePath.EndsWith(".ani") || filePath.EndsWith(".cur")) { try { ret = new System.Windows.Input.Cursor(filePath); } catch (Exception) { ret = null; } } //如果檔案不是正確的.ani或.cur檔案,則嘗試通過BitMap建立 if (ret == null) { Bitmap bmp = null; try { bmp = new Bitmap(Bitmap.FromFile(filePath), new System.Drawing.Size(xHotSpot, xHotSpot)); if (bmp != null) { ret = CreateCursor(bmp, bmp.Width / 2, bmp.Height / 2); } } catch (Exception) { ret = null; } } return ret; } public static System.Windows.Input.Cursor CreateCursor(Bitmap bm, int xHotSpot = 0, int yHotSpot = 0) { System.Windows.Input.Cursor ret = null; if (bm == null) { return ret; } try { ret = InternalCreateCursor(bm, (uint)xHotSpot, (uint)yHotSpot); } catch (Exception) { ret = null; } return ret; } protected static System.Windows.Input.Cursor InternalCreateCursor(Bitmap bitmap, uint xHotSpot, uint yHotSpot) { var iconInfo = new NativeMethods.IconInfo(); NativeMethods.GetIconInfo(bitmap.GetHicon(), ref iconInfo); iconInfo.xHotspot = xHotSpot;//焦點x軸座標 iconInfo.yHotspot = yHotSpot;//焦點y軸座標 iconInfo.fIcon = false;//設定滑鼠 SafeIconHandle cursorHandle = NativeMethods.CreateIconIndirect(ref iconInfo); return CursorInteropHelper.Create(cursorHandle); } protected static class NativeMethods { public struct IconInfo { public bool fIcon; public uint xHotspot; public uint yHotspot; public IntPtr hbmMask; public IntPtr hbmColor; } [DllImport("user32.dll")] public static extern SafeIconHandle CreateIconIndirect(ref IconInfo icon); [DllImport("user32.dll")] public static extern bool DestroyIcon(IntPtr hIcon); [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool GetIconInfo(IntPtr hIcon, ref IconInfo pIconInfo); } [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)] protected class SafeIconHandle : SafeHandleZeroOrMinusOneIsInvalid { public SafeIconHandle() : base(true) { } /// <summary> /// 釋放資源 /// </summary> protected override bool ReleaseHandle() { return NativeMethods.DestroyIcon(handle); } } #endregion } }