C++Commandモードで簡単にUndo&Redo機能を実現
21874 ワード
変換元:https://www.cnblogs.com/TianFang/archive/2013/05/19/3086820.html多くのGUIプログラムでは、ユーザーにとって非常に友好的な「取り消し&やり直し」機能が提供されています.この機能をC#で実現する方法を簡単に紹介します.
Undo&Redo機能を実装する基本モデルは、次のようにステップごとにコマンドオブジェクトとして保存される取り消し機能付きコマンドモードです.
ここでDo関数実行機能,Undo関数ロールバック機能.これによりコマンドを実体化し,コマンドオブジェクトを保存し,取り消しが必要な場合はUndo関数,やり直し時はDo関数を実行すればよい.
この基本的な考え方があれば、以下は実現の詳細です.は2つのStackを申請してコマンドオブジェクトを保存する:UndoStackとRedoStack コマンドを実行する場合は、コマンドをCommandオブジェクトにシーケンス化し、Doメソッドを実行し、UndoStackに格納し、RedoStack をクリアする.コマンドを取り消すと、UndoStackからコマンドを取り出し、Undoメソッドを実行し、RedoStack に格納する.やり直しコマンドの場合は、RedoStackからコマンドを取り出すDoメソッドを実行し、UndoStack に格納する.
シンプルな実装:
Undo&Redo機能を実装する基本モデルは、次のようにステップごとにコマンドオブジェクトとして保存される取り消し機能付きコマンドモードです.
interface Icommand
{
void Do();
void Undo();
}
ここでDo関数実行機能,Undo関数ロールバック機能.これによりコマンドを実体化し,コマンドオブジェクトを保存し,取り消しが必要な場合はUndo関数,やり直し時はDo関数を実行すればよい.
この基本的な考え方があれば、以下は実現の詳細です.
シンプルな実装:
#ifndef _COMMAND_HPP
#define _COMMAND_HPP
#include
#include
#include
class Command
{
public:
Command(){}
virtual ~Command(){}
virtual void Execute() = 0;
};
class InputCommand : public Command
{
public:
InputCommand( const std::string &input )
{
mInput = input;
}
~InputCommand()
{}
void Execute()
{
printf( "current string: %s
", mInput.c_str() );
}
private:
std::string mInput;
};
class Commander
{
public:
Commander( Command *pCmd )
{
//
mUndo.push( pCmd );
}
~Commander()
{
while( false == mUndo.empty() )
{
delete mUndo.top();
mUndo.pop();
}
while( false == mRedo.empty() )
{
delete mRedo.top();
mRedo.pop();
}
}
void ExecuteCommand( Command *pCmd )
{
pCmd->Execute();
mUndo.push( pCmd );
}
void Undo()
{
if( mUndo.size() < 2 )
{
//
printf( "undo failed.
" );
return;
}
printf( "undo:
" );
//
auto pCmd = mUndo.top();
//
mRedo.push( pCmd );
//
mUndo.pop();
//
pCmd = mUndo.top();
pCmd->Execute();
}
void Redo()
{
if( mRedo.empty() )
{
//
printf( "redo failed.
" );
return;
}
printf( "redo:
" );
auto pCmd = mRedo.top();
pCmd->Execute();
mRedo.pop();
mUndo.push( pCmd );
}
private:
std::stack< Command* > mUndo;
std::stack< Command* > mRedo;
};
#endif
#include "Command.hpp"
// , undo redo
// undo redo
// , : undo redo
// , undo redo redo
// , redo
int main()
{
// ,
Commander *p = new Commander( new InputCommand( "[empty]" ) );
// 1234
p->ExecuteCommand( new InputCommand( "1234" ) );
// 567
p->ExecuteCommand( new InputCommand( "567" ) );
// xxx
p->ExecuteCommand( new InputCommand( "xxx" ) );
// undo 567
p->Undo();
// undo 1234
p->Undo();
//undo insert 1234
p->ExecuteCommand( new InputCommand( "insert" ) );
// undo 1234
p->Undo();
// undo [empty]
p->Undo();
// undo
p->Undo();
// redo 1234
p->Redo();
// redo insert
p->Redo();
// redo 567
p->Redo();
//redo insert again 567
p->ExecuteCommand( new InputCommand( "insert again" ) );
// undo 567
p->Undo();
// redo insert again
p->Redo();
// redo xxx
p->Redo();
// redo
p->Redo();
delete p;
return 0;
}