質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

Q&A

解決済

1回答

4796閲覧

C# wpf InkCanvasで四角、丸を描写後に消しゴムで消したい

kkjiji

総合スコア40

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

2グッド

1クリップ

投稿2021/12/08 13:57

前提・実現したいこと

C# wpfにてペイントソフトを作ろうと思っています。
実現したいことはCanvasあるいはInkCanvas等を使って四角、丸を書いたあとに消しゴムで一部だけを消せるようにしたいです。
背景画像をセットしてその上にペイントしていくので、白塗りはNGです。

現在、InkCanvas上にRectangle、Ellipseで図形を作ったあと、InkCanvas.Children.AddでInkCanvas上に図形を書くところまでできています。

発生している問題・エラーメッセージ

上記のRectangle、EllipseをInkCanvasEditingMode.EraseByPointで消せるようにしたいと考えているのですが可能なのでしょうか?
可能であれば、どのようにすればいいか教えて下さい。
別の方法でも構いませんので、なにかいい案がある方はぜひお力添えお願いします。

補足情報(FW/ツールのバージョンなど)

・Visual Studio2019

TN8001, kkokuke👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答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}

アプリ画像
参考
InkCanvas | HIROs.NET Blog


C# wpfにてペイントソフトを作ろうと思っています。

InkCanvasは手書き・ジェスチャ認識等すごい機能もあるんですが、あくまでペン用であって例えば塗りつぶし機能はありません。
ペイントソフトに向いているかというと微妙な気もします。

「じゃあどうすりゃいいの?」ってことですが、わたしはこの手のものは全く興味がないので他の方を参考にしてください^^;
Search · wpf paint application


コメントで言及したChildrenに入れたコントロールが、(何もしなくても)移動・リサイズできちゃうの図
アプリ画像

投稿2021/12/08 22:11

編集2024/11/13 22:13
TN8001

総合スコア9862

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kkjiji

2021/12/09 08:25

ご回答ありがとうございました。 いろいろを試しましたが、難しそうでした。 参考のURLにも消しゴムが実装されているプログラムはなかったです。 もう少し考えてみようと思います。 ご親切にありがとうございました。
TN8001

2021/12/09 08:29

ええと回答コードで四角・楕円についてはできているのですが、内容が難しすぎたってことでしょうか? とりあえず提示コードですべてですので、試していただきたいのですが。。
TN8001

2021/12/09 08:36 編集

こちらはkkjijiさん向けではなく、実行してみた閲覧者向けです。 「押せないよ」は正確ではありませんでした。 InkCanvasEditingModeがNoneのときと、Selectで選択中のときは押せますね^^; 特にSelectでコントロールも移動・リサイズできちゃうのはすごいです! 選択中は押せないようになって(ラバーバンドが選択範囲を覆って)いれば完璧なのに、何で押せちゃうんですかね?w それさえどうにかなればこういったこと(コントロールの自由な移動・リサイズ)をしたい人は結構いるようなので、ベストソリューションになるのに(一切Inkしないっていう^^; InkCanvasSelectionAdornerを1行変えるだけなんだが、どうにかならんかな~??
kkjiji

2021/12/09 09:18

すみません。質問に不足がありました。 確かにTN8001のコードで四角、丸の線は消せるようになるのですが、 やりたいことは塗りつぶした後に消したかったんです。 そこを悩んでました。 あと、昨日からこのサイトに登録して使い方が分かっていないのですが、「一切lnkしないって」ってどういうことですかね? 「ベストアンサーにする」を押せば大丈夫ですか? 知らないことばかりですみません。
kkjiji

2021/12/09 09:44

いきなり呼び捨てにしてました。 失礼しました。
TN8001

2021/12/09 09:46 編集

> やりたいことは塗りつぶした後に消したかったんです。 塗りつぶした四角(Fill)ということですね? ペン用なので塗りつぶしに関しては無力ですね(むりやり中をペンで塗りつぶすとかも原理的には可能でしょうが^^; 個人的にはInkCanvasをあきらめて、独自に作ったほうがまだ簡単そうな気はします(GitHubは中身は見ていませんが、23個もあって一つも消しゴムないですか?) > 「ベストアンサーにする」を押せば大丈夫ですか? 解決できたら一番役に立ったと思う回答を、ベストアンサーに選んでください。 解決していないのに安易にベストアンサーは付けないでください(解決済みの質問はあまり読まれなくなってしまいます) もしもご自分で解決(あるいは代替え案)等で、一応解決という場合は自分で回答しそれをベストアンサーしても結構です。 しばらくたっても他に回答がつかず解決の見込みがない場合は、「いったん閉めます」として解決済みにしてもいいと思います。 > 「一切lnkしないって」 は閲覧者向けのコメントですが [リサイズハンドルをAdornerで実装する - CoMoの日記](https://como-2.hatenadiary.org/entry/20110428/1303996288 こういう感じのことをしたいって人がたまに居るんです。 ちゃんとやろうとすると結構面倒なんですが、CanvasのかわりにInkCanvasに変えるだけで移動リサイズ機能が付いてくることを初めて知ったのでちょっと興奮してしまいました^^; インク機能(ペン)は使わせずに、InkCanvasEditingMode.None・Selectだけで使用することを「一切lnkしない」と表現しました。
TN8001

2021/12/09 11:40

> (むりやり中をペンで塗りつぶすとかも原理的には可能でしょうが^^; を四角だけ超雑に実装しました。 数学が壊滅的にできないので、楕円はわからなかったですw
kkjiji

2021/12/10 08:24

ご親切に本当にありがとうございました。 selectモードで回転があれば、なお良かったなーとか勝手に持っている次第です笑 円は中心座標から外に向かってfor文回せば、いけそうな気もしますね。 行き詰まっていたのに兆しが見えてきました。 また、質問した際はお答えいただけると幸いです。
TN8001

2021/12/10 08:42 編集

> 円は中心座標から外に向かってfor文回せば、いけそうな気もしますね。 それだと円の大きさによって、角度のステップ数を変えないといけないのでちょっと面倒です。 四角と同じようにスライスしていく方針で何とか書けました(誰かコメントしてくれるかな?と思いましたが、誰も教えてくれそうにないので頑張って考えました^^; クリックで選択すると中身と縁が分かれてしまい、汚くなるのが難点です(これに気が付いてから思いましたが、だんだん小さくしていくのがよさそうですね)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問