Seite 1 von 1

Dictionary mit Zurück-Funktion

Verfasst: Samstag 22. Juli 2023, 09:51
von Fire Spike
Hallo Leute

Ich habe für eine GUI ein Dict um Daten zu speichern:

Code: Alles auswählen

{"0": "irgendwas", "1": "irgendwas"}
Dieses wird fortlaufend durch den Benutzerinteraktionen geändert.
Ich möchte nun gerne eine Zurück-Funktion, welche den letzten Schritt rückgängig macht.
Natürlich könnte ich das Dict einfach nach jeder Änderung in eine Liste reinstecken, aber da das Dict gross werden kann ist das nicht die beste Option.
Eher würde ich versuchen die einzelnen Schritte zu speichern, so dass sie Rückgängig gemacht werden können.
Was eignet sich da als Lösung?

Re: Dictionary mit Zurück-Funktion

Verfasst: Samstag 22. Juli 2023, 10:03
von ThomasL
Ein LiFO Stack deiner Aktionen?

Re: Dictionary mit Zurück-Funktion

Verfasst: Samstag 22. Juli 2023, 10:07
von Fire Spike
Eher nicht die Aktionen. Mehr so etwas wie Diff.

Re: Dictionary mit Zurück-Funktion

Verfasst: Samstag 22. Juli 2023, 10:25
von snafu

Re: Dictionary mit Zurück-Funktion

Verfasst: Samstag 22. Juli 2023, 10:31
von Fire Spike
Sieht interessant aus. Schaue ich mir mal an :)

Re: Dictionary mit Zurück-Funktion

Verfasst: Samstag 22. Juli 2023, 10:36
von pillmuncher
ChainMap ais der Standard Lib könnte man verwenden, aber dann ändert sich die Lookup-Zeit von O(1) auf O(n).

Ich würdre vermutlich sowas machen:

Code: Alles auswählen

class UndoDict(dict):

    _sentinel = object()

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._undostack = []

    def __setitem__(self, key, value):
        self._undostack.append((key, self.get(key, self._sentinel)))
        super()[key] = value

    def undo(self):
        if self._undostack:
            key, value = self._undostack.pop()
            if value is self._sentinel:
                del self[key]
            else:
                super()[key] = value
Ungetestet.

Re: Dictionary mit Zurück-Funktion

Verfasst: Samstag 22. Juli 2023, 10:39
von __blackjack__
@Fire Spike: Eine Allgemeine Lösung baut üblicherweise doch auf den Aktionen auf. Wobei man beide Richtungen speichert, wenn nicht nur Undo, sondern auch Redo funktionieren soll.

Manche GUI-Rahmenwerke haben da auch schon ein Gerüst für. Qt beispielsweise hat QUndoStack & Co.

Re: Dictionary mit Zurück-Funktion

Verfasst: Samstag 22. Juli 2023, 14:11
von narpfel
Oder vielleicht auch eine persistente Datenstruktur wie `PMap` aus `pyrsistent`.

Re: Dictionary mit Zurück-Funktion

Verfasst: Mittwoch 26. Juli 2023, 03:25
von snafu
Fire Spike hat geschrieben: Samstag 22. Juli 2023, 10:31 Sieht interessant aus. Schaue ich mir mal an :)
Und, schon weiter gekommen?

Anscheinend kann eine Benutzer-Aktion auch aus der Änderung von mehreren Einträgen im Dict bestehen, verstehe ich das richtig? Nur aus Interesse: Wie wird so eine Aktion denn abgeschlossen? Gibt es einen speziellen Button dafür? Oder einfach, sobald der Benutzer eine Eingabe mit Return abgeschlossen hat? Lässt sich das wirklich auf einzelne Einträge wie bei einer Konfiguration herunterbrechen oder muss man sich diese Aktionen etwas abstrakter innerhalb der GUI vorstellen?

Handelt es sich dabei um mehrere Wörterbücher oder um ein globales Dict? Sind die Schlüssel immer gleichbleibend bzw. fest vorgegeben, sodass es sich also auf die Änderungen der zugehörigen Werte beschränkt? Oder können auch neue Schlüssel vom Benutzer im Dict angelegt werden?

Das sind viele Fragen, aber sie würden unser Verständnis für dein Vorhaben erhöhen. Man kann dir dann wahrscheinlich eine bessere Lösung vorschlagen...

Re: Dictionary mit Zurück-Funktion

Verfasst: Mittwoch 26. Juli 2023, 12:45
von Fire Spike
Grundsätzlich ist dieses Dict dafür da, um Daten einer QGraphicsScene zu speichern. Ich habe ein kleines Zeichnungsprogramm geschrieben. Jedes Objekt (Linien, Bilder usw.) wird mit einer ID als Key in das Dictionary eingetragen. Diese ID bleibt dann auch. Die Value ist dann nochmals ein Dictionary, in dem dann die Eigenschaften stehen. Grundsätzlich können solche Objekte bearbeitet, hinzugefügt oder alle zusammen gelöscht werden. Die Aktionen (Linien zeichnen usw.) bearbeiten immer direkt das Dictionary. Dieses Dictionary wird dann als JSON gespeichert. Das Dictionary ist unabhängig von der GUI. Die Zeichnung kann also von dem Dict geladen aber nicht als Dict gespeichert werden. Die Aktionen ändern also immer das Dict und die GUI.
Hilft dir das?
Testen konnte ich noch nichts, da ich gerade in den Ferien bin.

Re: Dictionary mit Zurück-Funktion

Verfasst: Mittwoch 26. Juli 2023, 12:54
von __deets__
Das klingt gut und schlecht gleichzeitig ;) Die Idee, auf die du da gekommen bist, ist an sich erstmal gut. Das wuerde man als Modellbezeichnen, also eine reine Datenrepraesentation von dem, was dein Programm eigentlich darstellt. Und dann durch einen View wird das Modell dargestellt. Soweit, so gut. Das kann dann auch gespeichert und geladen werden, will man ja auch.

Die Sache mit den IDs, die dann die Schluessel dict sind, da wird's sketchy. Da du deine Operationen immer in einer definierten Reihenfolge abarbeiten musst, ist die richtige Datenstruktur eine Liste. Von der kannst du fuer UNDO dann ein Element abknapsen, und dann das ganze neu rendern. Oder aber, und das wird im Zweifel effizienter: du speicherst die Informationen, die du brauchst, wie zB Zeiger/Referenze auf die eigentlichen QGraphicsScene-Objekte, die erzeugt wurden, und wenn UNDO kommt, entfernst du die, statt alles neu zu malen. Das waere dann das eher klassiche Command-Pattern fuer Undo, weil es zu jedem Kommando (Linie malen) ein UNDO-Kommando (Linie loeschen) gibt.

Re: Dictionary mit Zurück-Funktion

Verfasst: Mittwoch 26. Juli 2023, 14:45
von __blackjack__
Hatte ich schon erwähnt das Qt für Undo/Redo schon Klassen bereitstellt!?

Re: Dictionary mit Zurück-Funktion

Verfasst: Mittwoch 26. Juli 2023, 16:54
von Fire Spike
Ja hast du. Hatte es mir aber noch nicht angeschaut.

Re: Dictionary mit Zurück-Funktion

Verfasst: Mittwoch 26. Juli 2023, 18:44
von snafu
Fire Spike hat geschrieben: Mittwoch 26. Juli 2023, 16:54 Hatte es mir aber noch nicht angeschaut.
Mach das mal ruhig. Hier ist ein Beispiel von Qt's Undo Framework, was ähnlich wie in deinem Fall mit gezeichneten Formen umgehen kann:

https://doc.qt.io/qt-6/qtwidgets-tools- ... ample.html

Möglichweise kannst du damit jede Menge Code einsparen, weil du die Objekte nicht mehr in Python-Dicts abbilden müsstest. Zudem lässt sich damit leicht eine Liste der letzten Schritte erstellen. Somit kann der Anwender auch mehrere Schritte in einem Rutsch zurück gehen. Ist natürlich auch alles mit Python-Boardmitteln umsetzbar, aber eben aufwändiger und potenziell fehleranfälliger. Nur das Undo-Framework dürfte eine gewisse Einarbeitung erfordern...