前提・実現したいこと
C# wpfにてペイントソフトを作ろうと思っています。
実現したいことはCanvasあるいはInkCanvas等を使って四角、丸を書いたあとに消しゴムで一部だけを消せるようにしたいです。
背景画像をセットしてその上にペイントしていくので、白塗りはNGです。
現在、InkCanvas上にRectangle、Ellipseで図形を作ったあと、InkCanvas.Children.AddでInkCanvas上に図形を書くところまでできています。
発生している問題・エラーメッセージ
上記のRectangle、EllipseをInkCanvasEditingMode.EraseByPointで消せるようにしたいと考えているのですが可能なのでしょうか?
可能であれば、どのようにすればいいか教えて下さい。
別の方法でも構いませんので、なにかいい案がある方はぜひお力添えお願いします。
補足情報(FW/ツールのバージョンなど)
・Visual Studio2019
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答1件
0
ベストアンサー
Rectangle、EllipseをInkCanvasEditingMode.EraseByPointで消せるようにしたいと考えているのですが可能なのでしょうか?
EditingMode
を変えるだけなんですから、やってみればいいんでは?(10秒で試せると思うのですが)
出来たらスゲーなと思いつつ試してみましたが、案の定できませんでした。。。
Children
に入れたものはあくまで背景?(というかInkの後ろ側に描画するだけ)であって、ストロークには含まれません。
InkCanvas.Strokes プロパティ (System.Windows.Controls) | Microsoft Docs
別の方法でも構いませんので、なにかいい案がある方はぜひお力添えお願いします。
どうにかしてStroke
を作るしかなさそうですね。
ググって出てきたのを参考にざっと作ってみました。
ペン・消しゴム・四角・楕円・選択・ジェスチャ(四角・楕円のみ)モードがあります。
xml
1<Window 2 x:Class="Questions372920.MainWindow" 3 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 4 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 5 xmlns:local="clr-namespace:Questions372920" 6 Width="800" 7 Height="450"> 8 <DockPanel> 9 <UniformGrid HorizontalAlignment="Left" DockPanel.Dock="Top" Rows="1"> 10 <UniformGrid.Resources> 11 <Style BasedOn="{StaticResource {x:Type ToggleButton}}" TargetType="RadioButton"> 12 <EventSetter Event="Checked" Handler="RadioButton_Checked" /> 13 </Style> 14 </UniformGrid.Resources> 15 <RadioButton Content="{x:Static local:MyInkMode.Pen}" IsChecked="True" /> 16 <RadioButton Content="{x:Static local:MyInkMode.Rect}" /> 17 <RadioButton Content="{x:Static local:MyInkMode.Ellipse}" /> 18 <RadioButton Content="{x:Static local:MyInkMode.Gesture}" /> 19 <RadioButton Content="{x:Static local:MyInkMode.Select}" /> 20 <RadioButton Content="{x:Static local:MyInkMode.Erase}" /> 21 </UniformGrid> 22 23 <Grid> 24 <InkCanvas 25 Name="inkCanvas" 26 Background="WhiteSmoke" 27 EditingMode="Ink" 28 Gesture="InkCanvas_Gesture" 29 MouseLeftButtonDown="InkCanvas_MouseLeftButtonDown" 30 MouseLeftButtonUp="InkCanvas_MouseLeftButtonUp" 31 MouseMove="InkCanvas_MouseMove"> 32 <Rectangle 33 Width="50" 34 Height="50" 35 InkCanvas.Left="50" 36 InkCanvas.Top="50" 37 Stroke="Red" /> 38 <Button Content="押せないよ" InkCanvas.Left="50" InkCanvas.Top="10" /> 39 <TextBlock InkCanvas.Left="50" InkCanvas.Top="110" Text="↑消せないよ" /> 40 </InkCanvas> 41 42 <!-- 四角・楕円ツール使用中の仮表示 本来はAdornerなんかでやるべきだが本題でないので手抜き --> 43 <Canvas Background="{x:Null}" ClipToBounds="True"> 44 <Ellipse 45 x:Name="tmpEllipse" 46 Fill="Red" 47 Stroke="Black" 48 StrokeThickness="2" /> 49 <Rectangle 50 x:Name="tmpRect" 51 Fill="Red" 52 Stroke="Black" 53 StrokeThickness="2" /> 54 </Canvas> 55 </Grid> 56 </DockPanel> 57</Window>
cs
1using System; 2using System.Collections.Generic; 3using System.Windows; 4using System.Windows.Controls; 5using System.Windows.Ink; 6using System.Windows.Input; 7using System.Windows.Media; 8using System.Windows.Shapes; 9 10 11namespace Questions372920 12{ 13 public enum MyInkMode { Pen, Rect, Ellipse, Gesture, Select, Erase, }; 14 15 public partial class MainWindow : Window 16 { 17 private Point startPoint; 18 private bool isDragging; 19 private MyInkMode mode; 20 21 public MainWindow() => InitializeComponent(); 22 23 private void RadioButton_Checked(object sender, RoutedEventArgs e) 24 { 25 if (sender is RadioButton rb && rb.Content is MyInkMode m) 26 { 27 mode = m; 28 if (inkCanvas == null) return; 29 30 switch (mode) 31 { 32 case MyInkMode.Pen: inkCanvas.EditingMode = InkCanvasEditingMode.Ink; break; 33 case MyInkMode.Rect: 34 case MyInkMode.Ellipse: 35 inkCanvas.EditingMode = InkCanvasEditingMode.None; 36 break; 37 case MyInkMode.Gesture: inkCanvas.EditingMode = InkCanvasEditingMode.GestureOnly; break; 38 case MyInkMode.Select: inkCanvas.EditingMode = InkCanvasEditingMode.Select; break; 39 case MyInkMode.Erase: inkCanvas.EditingMode = InkCanvasEditingMode.EraseByPoint; break; 40 } 41 } 42 } 43 44 private void InkCanvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) 45 { 46 if (mode != MyInkMode.Rect && mode != MyInkMode.Ellipse) return; 47 48 isDragging = true; 49 startPoint = e.GetPosition(inkCanvas); 50 inkCanvas.CaptureMouse(); 51 } 52 53 private void InkCanvas_MouseMove(object sender, MouseEventArgs e) 54 { 55 if (!isDragging) return; 56 57 Shape shape; 58 switch (mode) 59 { 60 case MyInkMode.Rect: shape = tmpRect; break; 61 case MyInkMode.Ellipse: shape = tmpEllipse; break; 62 default: return; 63 } 64 65 var r = new Rect(startPoint, e.GetPosition(inkCanvas)); 66 r.Inflate(1, 1); 67 68 Canvas.SetLeft(shape, r.X); 69 Canvas.SetTop(shape, r.Y); 70 shape.Width = r.Width; 71 shape.Height = r.Height; 72 } 73 74 private void InkCanvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) 75 { 76 if (mode != MyInkMode.Rect && mode != MyInkMode.Ellipse) return; 77 78 inkCanvas.ReleaseMouseCapture(); 79 isDragging = false; 80 81 var r = new Rect(startPoint, e.GetPosition(inkCanvas)); 82 switch (mode) 83 { 84 case MyInkMode.Rect: 85 AddRect(r.TopLeft, r.BottomRight); 86 tmpRect.Width = tmpRect.Height = 0; 87 break; 88 case MyInkMode.Ellipse: 89 AddEllipse(r.TopLeft, r.BottomRight); 90 tmpEllipse.Width = tmpEllipse.Height = 0; 91 break; 92 default: return; 93 } 94 } 95 96 private void InkCanvas_Gesture(object sender, InkCanvasGestureEventArgs e) 97 { 98 var result = e.GetGestureRecognitionResults()[0]; 99 if (result.RecognitionConfidence != RecognitionConfidence.Strong) return; 100 101 var r = e.Strokes.GetBounds(); 102 switch (result.ApplicationGesture) 103 { 104 case ApplicationGesture.Square: AddRect(r.TopLeft, r.BottomRight); break; 105 case ApplicationGesture.Circle: AddEllipse(r.TopLeft, r.BottomRight); break; 106 } 107 } 108 109 private void AddRect(Point start, Point end) 110 { 111 var n = new List<Point>(); 112 for (var i = start.Y; i < end.Y; i += 2) // えらい雑w 113 { 114 n.Add(new Point(start.X, i)); 115 n.Add(new Point(end.X, i)); 116 } 117 if (0 < n.Count) 118 { 119 var s = new Stroke(new StylusPointCollection(n)); 120 s.DrawingAttributes.Color = Colors.Red; 121 inkCanvas.Strokes.Add(s); 122 } 123 124 var points = new Point[] 125 { 126 new Point(start.X, start.Y), 127 new Point(start.X, end.Y), 128 new Point(end.X, end.Y), 129 new Point(end.X, start.Y), 130 new Point(start.X, start.Y), 131 }; 132 133 var stroke = new Stroke(new StylusPointCollection(points)); 134 inkCanvas.Strokes.Add(stroke); 135 } 136 137 private void AddEllipse(Point start, Point end) 138 { 139 var a = (end.X - start.X) / 2; 140 var b = (end.Y - start.Y) / 2; 141 var offset = (Vector)((end - start) / 2 + start); 142 143 var n = new List<Point>(); 144 for (var x = -a; x < a; x += 2) // さらに雑w 145 { 146 var y = b * Math.Sqrt(Math.Pow(a, 2) - Math.Pow(x, 2)) / a; 147 n.Add(new Point(x, -y) + offset); 148 n.Add(new Point(x, y) + offset); 149 } 150 if (0 < n.Count) 151 { 152 var s = new Stroke(new StylusPointCollection(n)); 153 s.DrawingAttributes.Color = Colors.Red; 154 inkCanvas.Strokes.Add(s); 155 } 156 157 var points = new List<Point>(); 158 for (var i = 0; i <= 360; i += 5) 159 { 160 var x = a * Math.Cos(i / 180d * Math.PI); 161 var y = b * Math.Sin(i / 180d * Math.PI); 162 points.Add(new Point(x, y) + offset); 163 } 164 165 var stroke = new Stroke(new StylusPointCollection(points)); 166 stroke.DrawingAttributes.FitToCurve = true; 167 inkCanvas.Strokes.Add(stroke); 168 } 169 } 170}
C# wpfにてペイントソフトを作ろうと思っています。
InkCanvas
は手書き・ジェスチャ認識等すごい機能もあるんですが、あくまでペン用であって例えば塗りつぶし機能はありません。
ペイントソフトに向いているかというと微妙な気もします。
「じゃあどうすりゃいいの?」ってことですが、わたしはこの手のものは全く興味がないので他の方を参考にしてください^^;
Search · wpf paint application
投稿2021/12/08 22:11
編集2024/11/13 22:13総合スコア9862
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/12/09 08:25
2021/12/09 08:29
2021/12/09 08:36 編集
2021/12/09 09:18
2021/12/09 09:44
2021/12/09 09:46 編集
2021/12/09 11:40
2021/12/10 08:24
2021/12/10 08:42 編集