ページ 1 / 1
VC,netでRedo機能の追加
Posted: 2009年8月16日(日) 17:41
by 餅
度々、質問失礼します。
以前ここの方に回答いただきテキストボックスのUNDO機能の実装ができました。
それから色々やってみたのですがREDO機能ができないです。
Stack型を2種類作って~みたいにやるらしいのですが
どなたか教えてはいただけないでしょうか?
ttp://d.hatena.ne.jp/Youchan/20081111/1226388917
ttp://www.sunny-grove.net/articles/undoable.html
Re:VC,netでRedo機能の追加
Posted: 2009年8月16日(日) 18:00
by バグ
後入れ先出しのStackでは難しいでしょうね。
単純な配列かListで管理すべきでしょう。
Re:VC,netでRedo機能の追加
Posted: 2009年8月16日(日) 18:39
by 餅
>>バグs
Stackではできないのでしょうか?
また配列でやる場合にはどのようにすればよいでしょうか?
Re:VC,netでRedo機能の追加
Posted: 2009年8月16日(日) 18:59
by バグ
すみません、前言撤回。
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機能の追加
Posted: 2009年8月16日(日) 19:02
by バグ
追記
※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機能の追加
Posted: 2009年8月16日(日) 19:05
by 餅
>>バグs
原理は理解したのですが書き方がわかりません><
PopとPushがあるらしいのですがイマイチ理解できないです。
Re:VC,netでRedo機能の追加
Posted: 2009年8月16日(日) 19:20
by バグ
方法が分からないならまだしも、書き方が分からないなら、入門サイトなりで文法を勉強するしかないのではないかと…。原理は理解したという事ですから、方法は分かっているようですしね。
このスレの冒頭であなたが載せてあるソースは以前私が書いたものですが、かなり細かくコメントを載せてあります。じっくり解読してみてください。そのコメントの内容以上に言える事はないです。UNDOとほとんど同じ方法でREDOも実装できます。
それから、Pushは要素の追加、Popは要素の取り出しです。
Stackでは必ず『後入れ先出し』となりますので、最後にPushで追加された要素がPopで取り出されます。そして、Popで取り出した要素はStackから削除されます。
ちなみにPeekというのもあります。PeekはStackから取り出さずに先頭要素を参照できます。
Re:VC,netでRedo機能の追加
Posted: 2009年8月16日(日) 22:07
by 餅
>>バグさん
理解したというより、どんなことをしているのかと
言うことしかわかっておりません。
どうかサンプルソースをかいてはいただけないでしょうか?
Re:VC,netでRedo機能の追加
Posted: 2009年8月17日(月) 04:02
by バグ
どんな事をしているかが分かっているならば、書けると思いますよ?(^_^;)
考え方は既に書き込みましたし、書き方はUndoTextBoxのソースがそのままサンプルになると思います。
ここから先は、数学なんかでいう応用問題みたいなものですね。
自分が必要とする機能は、自分で考えて実装するようにしないと、いつもそのものズバリなサンプルが落ちているとは限りませんから…
今回は、ほぼ要求に近いサンプルがある事ですし、いきなり答えを求めずにそこから発展させる努力位はしてください。
そのうえでの、具体的に的を絞っての質問(こういう風に考えて、こう実装してみましたが、こう動くと思うのに、こういう風に動きます。どうしてでしょうか?…みたいな質問)なら、御答えできるかもしれません。
頑張って♪(・ω・)ノ
Re:VC,netでRedo機能の追加
Posted: 2009年8月17日(月) 17:36
by バグ
分かり易い方法で書いてみました。
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機能の追加
Posted: 2009年8月17日(月) 20:59
by 餅
>>バグs
サンプルをありがとうございます。
丸投げではおっしゃる通り力になりませんのでこれを基に別のやり方でやってみます。
ご回答ありがとうございました。
Re:VC,netでRedo機能の追加
Posted: 2009年9月09日(水) 23:04
by 餅
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)