VC,netでRedo機能の追加

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら

VC,netでRedo機能の追加

#1

投稿記事 by » 16年前

度々、質問失礼します。
以前ここの方に回答いただきテキストボックスのUNDO機能の実装ができました。
それから色々やってみたのですがREDO機能ができないです。
Stack型を2種類作って~みたいにやるらしいのですが
どなたか教えてはいただけないでしょうか?

ttp://d.hatena.ne.jp/Youchan/20081111/1226388917
ttp://www.sunny-grove.net/articles/undoable.html

バグ

Re:VC,netでRedo機能の追加

#2

投稿記事 by バグ » 16年前

後入れ先出しのStackでは難しいでしょうね。
単純な配列かListで管理すべきでしょう。

Re:VC,netでRedo機能の追加

#3

投稿記事 by » 16年前

>>バグs
Stackではできないのでしょうか?
また配列でやる場合にはどのようにすればよいでしょうか?

バグ

Re:VC,netでRedo機能の追加

#4

投稿記事 by バグ » 16年前

すみません、前言撤回。
UNDO用のStackとREDO用のStackを2つ用意すればいけますね。
しかも、かなり簡単に。

REDO用のStackへTextBoxのTextを格納してから、UNDOの処理を行えばいいだけでしたね。
Stackの動きは下記を参照ください。


※UNDO用Stackの動き
TextBox    UNDO用Stack
A
AB         A
ABC        AB, A
ABCD       ABC, AB, A
ABCDE      ABCD, ABC, AB, A



※UNDO操作を行った場合のStackの動き
TextBox    UNDO用Stack         REDO用Stack
ABCDE      ABCD, ABC, AB, A
ABCD       ABC, AB, A          ABCDE 
ABC        AB, A               ABCD, ABCDE
AB         A                   ABC, ABCD, ABCDE
A                              AB, ABC, ABCD, ABCDE

バグ

Re:VC,netでRedo機能の追加

#5

投稿記事 by バグ » 16年前

追記
※REDO操作を行った場合のStackの動き
TextBox    UNDO用Stack         REDO用Stack
A                              AB, ABC, ABCD, ABCDE
AB         A                   ABC, ABCD, ABCDE
ABC        AB, A               ABCD, ABCDE 
ABCD       ABC, AB, A          ABCDE
ABCDE      ABCD, ABC, AB, A

Re:VC,netでRedo機能の追加

#6

投稿記事 by » 16年前

>>バグs
原理は理解したのですが書き方がわかりません><
PopとPushがあるらしいのですがイマイチ理解できないです。

バグ

Re:VC,netでRedo機能の追加

#7

投稿記事 by バグ » 16年前

方法が分からないならまだしも、書き方が分からないなら、入門サイトなりで文法を勉強するしかないのではないかと…。原理は理解したという事ですから、方法は分かっているようですしね。

このスレの冒頭であなたが載せてあるソースは以前私が書いたものですが、かなり細かくコメントを載せてあります。じっくり解読してみてください。そのコメントの内容以上に言える事はないです。UNDOとほとんど同じ方法でREDOも実装できます。

それから、Pushは要素の追加、Popは要素の取り出しです。

Stackでは必ず『後入れ先出し』となりますので、最後にPushで追加された要素がPopで取り出されます。そして、Popで取り出した要素はStackから削除されます。

ちなみにPeekというのもあります。PeekはStackから取り出さずに先頭要素を参照できます。

Re:VC,netでRedo機能の追加

#8

投稿記事 by » 16年前

>>バグさん
理解したというより、どんなことをしているのかと
言うことしかわかっておりません。

どうかサンプルソースをかいてはいただけないでしょうか?

バグ

Re:VC,netでRedo機能の追加

#9

投稿記事 by バグ » 16年前

どんな事をしているかが分かっているならば、書けると思いますよ?(^_^;)

考え方は既に書き込みましたし、書き方はUndoTextBoxのソースがそのままサンプルになると思います。

ここから先は、数学なんかでいう応用問題みたいなものですね。

自分が必要とする機能は、自分で考えて実装するようにしないと、いつもそのものズバリなサンプルが落ちているとは限りませんから…

今回は、ほぼ要求に近いサンプルがある事ですし、いきなり答えを求めずにそこから発展させる努力位はしてください。

そのうえでの、具体的に的を絞っての質問(こういう風に考えて、こう実装してみましたが、こう動くと思うのに、こういう風に動きます。どうしてでしょうか?…みたいな質問)なら、御答えできるかもしれません。

頑張って♪(・ω・)ノ

バグ

Re:VC,netでRedo機能の追加

#10

投稿記事 by バグ » 16年前

分かり易い方法で書いてみました。
UNDO回数が無制限(メモリの許す限り)バージョンです。
回数制限したければ適当に修正してください。
#pragma once

public ref class UndoTextBox : public System::Windows::Forms::TextBox
{
private:
	System::Collections::Generic::Stack<System::String^> m_redoStack;
	System::Collections::Generic::Stack<System::String^> m_undoStack;
	bool m_change;

public:
	UndoTextBox(void)
	{
		InitializeComponent();

		// メンバの初期化
		init();
	}

	UndoTextBox(System::ComponentModel::IContainer ^container)
	{
		container->Add(this);
		InitializeComponent();

		// メンバの初期化
		init();
	}

protected:
	~UndoTextBox()
	{
		if (components)
		{
			delete components;
		}
	}

	virtual void OnTextChanged(System::EventArgs^ e) override
	{
		// フラグがtrueの場合は…
		if (this->m_change == true)
		{
			// UNDOかREDOによってTEXTが変化したので、フラグをfalseにするだけで何もしない
			this->m_change = false;
		}
		else
		{
			// REDO用Stackの中身を削除する
			this->m_redoStack.Clear();

			// UNDO用Stackへ最新のTEXTを挿入する
			this->m_undoStack.Push(this->Text);
		}
		TextBox::OnTextChanged(e);
	}

	virtual void OnKeyDown(System::Windows::Forms::KeyEventArgs^ e) override
	{
		if (e->Control == true)
		{
			switch (e->KeyCode)
			{
			case System::Windows::Forms::Keys::A:
				// 全選択
				SelectAll();
				return;
			case System::Windows::Forms::Keys::Z:
				// UNDO処理
				undo();
				return;		
			case System::Windows::Forms::Keys::Y:
				// REDO処理
				redo();
				return;
			}
		}
		TextBox::OnKeyDown(e);
	}

private:
	/// <sammary>
	/// メンバの初期化
	/// <sammary>
	void init(void)
	{
		// Stackの中身を削除する
		this->m_redoStack.Clear();
		this->m_undoStack.Clear();

		// UNDO用Stackの最初の要素として、空文字を挿入しておく
		this->m_undoStack.Push(System::String::Empty);

		// フラグをfalseで初期化
		this->m_change = false;
	}

	/// <sammary>
	/// UNDO
	/// <sammary>
	void undo(void)
	{
		// UNDO用のStackが空っぽでなければ…
		if (this->m_undoStack.Count > 0)
		{
			// Stackの先頭要素がTextBox内のTEXTと同じの場合は…
			if (this->m_undoStack.Peek() == this->Text)
			{
				// 一度だけ空読みして先頭要素を削除する
				this->m_undoStack.Pop();
			}

			// UNDOによってTEXTが変化するのでフラグをTRUEにする
			this->m_change = true;

			// TextBox内のTEXTをREDO用Stackの先頭へ挿入する
			this->m_redoStack.Push(this->Text);

			// UNDO用のStackの先頭要素をTextBox内のTEXTへコピーする
			this->Text = this->m_undoStack.Pop();
		}
	}

	/// <sammary>
	/// REDO
	/// <sammary>
	void redo(void)
	{
		// REDO用のStackが空っぽでなければ…
		if (this->m_redoStack.Count > 0)
		{
			// REDOによってTEXTが変化するのでフラグをTRUEにする
			this->m_change = true;

			// TextBox内のTEXTをUNDO用Stackの先頭へ挿入する
			this->m_undoStack.Push(this->Text);

			// REDO用のStackの先頭要素をTextBox内のTEXTへコピーする
			this->Text = this->m_redoStack.Pop();
		}
	}

private:
	System::ComponentModel::Container ^components;

#pragma region Windows Form Designer generated code
	void InitializeComponent(void)
	{
		components = gcnew System::ComponentModel::Container();
	}
#pragma endregion
};

Re:VC,netでRedo機能の追加

#11

投稿記事 by » 16年前

>>バグs
サンプルをありがとうございます。
丸投げではおっしゃる通り力になりませんのでこれを基に別のやり方でやってみます。
ご回答ありがとうございました。

Re:VC,netでRedo機能の追加

#12

投稿記事 by » 16年前

if (this->m_redoStack.Count > 0)と書いているのに起動してからすぐに
Ctrl+ZをやるとUndoのスタックがEmptyとエラーが出てしまいます。
またUndo、Redo時にカーソルの位置が0番目になってしまうのですが前回の位置にと直せないでしょうか?

// カーソル操作
this->TextBox1.Focus()
this->TextBox1.Select(番目, 0)

でできるとわかったのですがどこに移動させればいいのかということと
このソースで作ったテキストボックスだと強制的に0番目にカーソルがあってしまいます。
#pragma once

public ref class UndoTextBox : public System::Windows::Forms::TextBox
{
private:
	System::Collections::Generic::Stack<System::String^> m_redoStack;
	System::Collections::Generic::Stack<System::String^> m_undoStack;
	bool m_change;

public:
	UndoTextBox(void)
	{
		InitializeComponent();

		// メンバの初期化
		init();
	}

	UndoTextBox(System::ComponentModel::IContainer ^container)
	{
		container->Add(this);
		InitializeComponent();

		// メンバの初期化
		init();
	}

protected:
	~UndoTextBox()
	{
		if (components)
		{
			delete components;
		}
	}

	virtual void OnTextChanged(System::EventArgs^ e) override
	{
		// フラグがtrueの場合は…
		if (this->m_change == true)
		{
			// UNDOかREDOによってTEXTが変化したので、フラグをfalseにするだけで何もしない
			this->m_change = false;
		}
		else
		{
			// REDO用Stackの中身を削除する
			this->m_redoStack.Clear();

			// UNDO用Stackへ最新のTEXTを挿入する
			this->m_undoStack.Push(this->Text);
		}
		TextBox::OnTextChanged(e);
	}

	virtual void OnKeyDown(System::Windows::Forms::KeyEventArgs^ e) override
	{
		if (e->Control == true)
		{
			switch (e->KeyCode)
			{
			case System::Windows::Forms::Keys::A:
				// 全選択
				SelectAll();
				return;
			case System::Windows::Forms::Keys::Z:
				// UNDO処理				
				undo();
				return;		
			case System::Windows::Forms::Keys::Y:
				// REDO処理
				redo();
				return;
			}
		}
		TextBox::OnKeyDown(e);
	}

private:
	/// <sammary>
	/// メンバの初期化
	/// <sammary>
	void init(void)
	{
		// Stackの中身を削除する
		this->m_redoStack.Clear();
		this->m_undoStack.Clear();

		// UNDO用Stackの最初の要素として、空文字を挿入しておく
		this->m_undoStack.Push(System::String::Empty);

		// フラグをfalseで初期化
		this->m_change = false;
	}

	/// <sammary>
	/// UNDO
	/// <sammary>
	void undo(void)
	{
		// UNDO用のStackが空っぽでなければ…
		if (this->m_undoStack.Count > 0)
		{
			// Stackの先頭要素がTextBox内のTEXTと同じの場合は…
			if (this->m_undoStack.Peek() == this->Text)
			{
				// 一度だけ空読みして先頭要素を削除する
				this->m_undoStack.Pop();
			}

			// UNDOによってTEXTが変化するのでフラグをTRUEにする
			this->m_change = true;

			// TextBox内のTEXTをREDO用Stackの先頭へ挿入する
			this->m_redoStack.Push(this->Text);

			// UNDO用のStackの先頭要素をTextBox内のTEXTへコピーする
			this->Text = this->m_undoStack.Pop();
		}
	}

	/// <sammary>
	/// REDO
	/// <sammary>
	void redo(void)
	{
		// REDO用のStackが空っぽでなければ…
		if (this->m_redoStack.Count > 0)
		{
			// REDOによってTEXTが変化するのでフラグをTRUEにする
			this->m_change = true;

			// TextBox内のTEXTをUNDO用Stackの先頭へ挿入する
			this->m_undoStack.Push(this->Text);

			// REDO用のStackの先頭要素をTextBox内のTEXTへコピーする
			this->Text = this->m_redoStack.Pop();
		}
	}

private:
	System::ComponentModel::Container ^components;

#pragma region Windows Form Designer generated code
	void InitializeComponent(void)
	{
		components = gcnew System::ComponentModel::Container();
	}
#pragma endregion
};
if (this->m_redoStack.Count > 0)

閉鎖

“C言語何でも質問掲示板” へ戻る