← |
2024年11月 |
→ |
日 |
月 |
火 |
水 |
木 |
金 |
土 |
|
|
|
|
|
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
|
26 |
27 |
28 |
29 |
30 |
|
※続きがあります→翌日の記事
InkCanvasにアンドゥ機能が欲しくて、帰宅後に習作で作ってみた。
ちなみに、InkCanvasは線を描くとStrokesに線が追加されるので、 線を消す方向のアンドゥは、それを操作するだけで結構簡単。
一方で、消しゴム的に消去すると、既存の線が分裂して、 Strokesに再登録されるので、前述の方法だと破綻してしまう。 そのため、消しゴムモードを交えてのアンドゥが結構やっかいっぽい。
そこで、線が追加されたときのイベントと、 消しゴムで分断されたときのイベントを使って、 線分を力業で保存してアンドゥを実装してみた。
コアの部分のコードはこんな:
public class UndoInkCanvas : InkCanvas { /// <summary> /// アンドゥバッファ /// </summary> private List<System.Windows.Ink.StrokeCollection> UndoBufferList = new List<System.Windows.Ink.StrokeCollection>(); /// <summary> /// 直前が描画だったか、消しゴムだったかの列挙体 /// </summary> private enum LAST_STROKE_TYPE { STROKE, ERASER }; /// <summary> /// 直前が描画だったか、消しゴムだったかの判断をするためのフラグ /// </summary> private LAST_STROKE_TYPE LastStrokeType = LAST_STROKE_TYPE.STROKE; /// <summary> /// 静的コンストラクタ /// </summary> static UndoInkCanvas() { DefaultStyleKeyProperty.OverrideMetadata(typeof(UndoInkCanvas), new FrameworkPropertyMetadata(typeof(UndoInkCanvas))); } /// <summary> /// 通常のコンストラクタ /// </summary> public UndoInkCanvas() { this.StrokeCollected += new InkCanvasStrokeCollectedEventHandler(UndoInkCanvas_StrokeCollected); this.StrokeErased += new RoutedEventHandler(UndoInkCanvas_StrokeErased); } /// <summary> /// キャンバスのストロークを全消去します。 /// </summary> public void ClearCanvas() { this.UndoBufferList.Clear(); this.Strokes.Clear(); } /// <summary> /// ストロークの取り消し /// </summary> public void UndoStroke() { if (this.UndoBufferList.Count() > 1) { //直前の描画結果を破棄 this.UndoBufferList.RemoveAt(this.UndoBufferList.Count() - 1); //直前の描画前の状態を復活 this.Strokes.Clear(); foreach (var stroke in this.UndoBufferList.Last()) { this.Strokes.Add(stroke); } } else { //Undoリストが無いので、全部消去 this.UndoBufferList.Clear(); this.Strokes.Clear(); } } /// <summary> /// ストロークが追加されたイベント /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void UndoInkCanvas_StrokeCollected(object sender, InkCanvasStrokeCollectedEventArgs e) { this.UndoBufferList.Add(this.Strokes.Clone()); LastStrokeType = LAST_STROKE_TYPE.STROKE; } /// <summary> /// 消しゴムが実行されたイベント /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void UndoInkCanvas_StrokeErased(object sender, RoutedEventArgs e) { if (LastStrokeType == LAST_STROKE_TYPE.STROKE) { //直前が描画ならば、履歴の追加 this.UndoBufferList.Add(this.Strokes.Clone()); } else { //削除イベントが連続しているので、直前の描画結果を更新 if (this.UndoBufferList.Count() > 0) { this.UndoBufferList[this.UndoBufferList.Count() - 1] = this.Strokes.Clone(); } } LastStrokeType = LAST_STROKE_TYPE.ERASER; } } かなりエレファント。
もう少しエレガントな方法はないかなぁ・・・
とくに、消しゴムで何回も消しても1回のアンドゥで元に戻るのを、何とかしたいなぁ。
StylusUpイベントとかでやると出来るとは思うケド、 MouseUpやTouchUpでもやらないといけなくて、 もっとエレファントなコードになるだろうし・・・
※続きがあります→翌日の記事
|
00:24, Wednesday, Jan 26, 2011 ¦ 固定リンク
¦ 携帯
■コメント
■コメントを書く
※コメントの受け付けは終了しました
|
|