Änderungen Rückgängig machen



  • Jeder konnt doch diese Undo/Redo-Funktionen die heute doch fast alle Anwendungen anbieten.
    Ich dachte mir man könnte das ja so machen (code kommt gleich), aber das Redo musst ich erstmal draußen lassen, dazu hätt ich wieder nen Undo für das Redo auf den Stack pushen müssen und dann hätt ich beide Klassen nicht mehr in eine Datei schreiben können.

    So hier mal der Code

    struct UndoOperation
    {
    	virtual bool apply()
    	{
    		return false;
    	}
    	virtual ~UndoOperation()
    	{
    	}
    };
    
    struct UndoStack
    {
    	void pushUndoOperation( UndoOperation* operation )
    	{
    		mUndoStack.push( operation );
    	}
    
    	void undoOneStep()
    	{
    		mUndoStack.top()->apply(); //undo
    		mUndoStack.pop();
    	}
    
    	stack< UndoOperation* > mUndoStack;
    };
    
    UndoStack g_UndoStack;
    
    struct DataContainer
    {
    	struct UndoInsert : UndoOperation
    	{
    		UndoInsert( DataContainer& target )
    			: target( target )
    		{
    		}
    
    		virtual bool apply()
    		{
    			target.myData.pop_back();
    			return true;
    		}
    
    		DataContainer& target;
    	};
    
    	void insertData( int dat )
    	{
    		myData.push_back( dat );
    		g_UndoStack.pushUndoOperation( new UndoInsert( *this ) );
    	}
    	vector< int > myData;
    };
    
    int main()
    {
    	DataContainer cont;
    
    	for( int i = 0; i < 10; ++i )
    	{
    		cont.insertData( i );
    		cout << cont.myData[ cont.myData.size()-1 ] << "\n";
    		if( i%2 == 0 )
    		{
    			cout << "undoing operation...\n";
    			g_UndoStack.undoOneStep();
    			for( int i = 0; i < cont.myData.size(); ++i )
    				cout << "\t" << cont.myData[ i ] << endl;
    		}
    	}
    }
    

    Das ganze funktioniert soweit ja auch ganz gut, nur muss man für jeden Vorgang eben ne Klasse schreiben bzw. nen Funktor um etwas rückgängig zu machen, was auf Dauer doch recht aufwändig wird und dann fehlt immernoch das Redo.

    Was mir da noch als Alternative aus anderen Anwendungen einfällt (zb. die Photoshop history) wäre folgendes:
    Man hat nen Stack auf dem alle Änderungen gespeichert werden und einen Zeiger in diesen wo man gerade steht, jetzt kann man einfach vorwärts und damit ein Undo aufheben (=> Redo) und rückwärts um etwas ungeschehen zu machen.
    Dann müsste aber jede Operation sich selbst auch rückgängig machen können, sonst müsst man ja jedes mal bei 0 starten und alle Operationen bis zu diesem Punkt wieder durchführen.
    Ideen gehen mir gerade viele durch den Kopf aber nach etwas überlegen zeigen viele auch schon wieder schwächen und vor allem sieht man viele Probleme ja auch nicht an einem einfachen Beispiel wie oben. Ich denke da zum Beispiel an CAD Anwendungen wenn man mal eben zwei Objekte vereint oder sonst was komplexeres damit macht.

    So jetzt hab ich viel geschrieben aber noch keine Frage gestellt und die lautet:
    Wie wird so nen Undo/Redo denn in den großen Anwendungen gemacht?



  • Afaik mit dem Command pattern glaube ich. Auf jeden Fall wars irgendein Design Pattern 🙂



  • Jetzt wo du das Command-Pattern erwähnst dämmert mir da was, zumindest habe ich schonmal davon gehört (und ich meine in diesem Zusammenhang).

    Das Forum hat aber auch nachgelassen, da kommt man mal mit nem interressanten Thema und dann geht das einfach unter in den ganzen langweiligen 0815 Threads. Sowas hätt es früher nicht gegeben 😞


Anmelden zum Antworten