度々、質問失礼します。
以前ここの方に回答いただきテキストボックスのUNDO機能の実装ができました。
それから色々やってみたのですがREDO機能ができないです。
Stack型を2種類作って~みたいにやるらしいのですが
どなたか教えてはいただけないでしょうか?
ttp://d.hatena.ne.jp/Youchan/20081111/1226388917
ttp://www.sunny-grove.net/articles/undoable.html
VC,netでRedo機能の追加
Re:VC,netでRedo機能の追加
すみません、前言撤回。
UNDO用のStackとREDO用のStackを2つ用意すればいけますね。
しかも、かなり簡単に。
REDO用のStackへTextBoxのTextを格納してから、UNDOの処理を行えばいいだけでしたね。
Stackの動きは下記を参照ください。
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機能の追加
追記
※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機能の追加
方法が分からないならまだしも、書き方が分からないなら、入門サイトなりで文法を勉強するしかないのではないかと…。原理は理解したという事ですから、方法は分かっているようですしね。
このスレの冒頭であなたが載せてあるソースは以前私が書いたものですが、かなり細かくコメントを載せてあります。じっくり解読してみてください。そのコメントの内容以上に言える事はないです。UNDOとほとんど同じ方法でREDOも実装できます。
それから、Pushは要素の追加、Popは要素の取り出しです。
Stackでは必ず『後入れ先出し』となりますので、最後にPushで追加された要素がPopで取り出されます。そして、Popで取り出した要素はStackから削除されます。
ちなみにPeekというのもあります。PeekはStackから取り出さずに先頭要素を参照できます。
このスレの冒頭であなたが載せてあるソースは以前私が書いたものですが、かなり細かくコメントを載せてあります。じっくり解読してみてください。そのコメントの内容以上に言える事はないです。UNDOとほとんど同じ方法でREDOも実装できます。
それから、Pushは要素の追加、Popは要素の取り出しです。
Stackでは必ず『後入れ先出し』となりますので、最後にPushで追加された要素がPopで取り出されます。そして、Popで取り出した要素はStackから削除されます。
ちなみにPeekというのもあります。PeekはStackから取り出さずに先頭要素を参照できます。
Re:VC,netでRedo機能の追加
>>バグさん
理解したというより、どんなことをしているのかと
言うことしかわかっておりません。
どうかサンプルソースをかいてはいただけないでしょうか?
理解したというより、どんなことをしているのかと
言うことしかわかっておりません。
どうかサンプルソースをかいてはいただけないでしょうか?
Re:VC,netでRedo機能の追加
どんな事をしているかが分かっているならば、書けると思いますよ?(^_^;)
考え方は既に書き込みましたし、書き方はUndoTextBoxのソースがそのままサンプルになると思います。
ここから先は、数学なんかでいう応用問題みたいなものですね。
自分が必要とする機能は、自分で考えて実装するようにしないと、いつもそのものズバリなサンプルが落ちているとは限りませんから…
今回は、ほぼ要求に近いサンプルがある事ですし、いきなり答えを求めずにそこから発展させる努力位はしてください。
そのうえでの、具体的に的を絞っての質問(こういう風に考えて、こう実装してみましたが、こう動くと思うのに、こういう風に動きます。どうしてでしょうか?…みたいな質問)なら、御答えできるかもしれません。
頑張って♪(・ω・)ノ
考え方は既に書き込みましたし、書き方はUndoTextBoxのソースがそのままサンプルになると思います。
ここから先は、数学なんかでいう応用問題みたいなものですね。
自分が必要とする機能は、自分で考えて実装するようにしないと、いつもそのものズバリなサンプルが落ちているとは限りませんから…
今回は、ほぼ要求に近いサンプルがある事ですし、いきなり答えを求めずにそこから発展させる努力位はしてください。
そのうえでの、具体的に的を絞っての質問(こういう風に考えて、こう実装してみましたが、こう動くと思うのに、こういう風に動きます。どうしてでしょうか?…みたいな質問)なら、御答えできるかもしれません。
頑張って♪(・ω・)ノ
Re:VC,netでRedo機能の追加
分かり易い方法で書いてみました。
UNDO回数が無制限(メモリの許す限り)バージョンです。
回数制限したければ適当に修正してください。
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機能の追加
>>バグs
サンプルをありがとうございます。
丸投げではおっしゃる通り力になりませんのでこれを基に別のやり方でやってみます。
ご回答ありがとうございました。
サンプルをありがとうございます。
丸投げではおっしゃる通り力になりませんのでこれを基に別のやり方でやってみます。
ご回答ありがとうございました。
Re:VC,netでRedo機能の追加
if (this->m_redoStack.Count > 0)と書いているのに起動してからすぐに
Ctrl+ZをやるとUndoのスタックがEmptyとエラーが出てしまいます。
またUndo、Redo時にカーソルの位置が0番目になってしまうのですが前回の位置にと直せないでしょうか?
// カーソル操作
this->TextBox1.Focus()
this->TextBox1.Select(番目, 0)
でできるとわかったのですがどこに移動させればいいのかということと
このソースで作ったテキストボックスだと強制的に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)