Seite 1 von 2

UndoManager mit Tkinter-GUI

Verfasst: Mittwoch 9. September 2015, 03:12
von sedi
Hallo zusammen,

bin auf der Suche nach einen UndoManager für Tkinter - als Ausangsbasis könnte ja man den UndoManager von @Rekrul im Beitrag http://www.python-forum.de/viewtopic.ph ... 37#p283437 verwenden:

Code: Alles auswählen

    class Command:
        def undo(self): pass
        def redo(self): pass
     
    class UndoManager:
        def __init__(self, appmenu):
            """
            :param appmenu: {tkinter menu object} 
            """
            self.menu = appmenu.bearbeiten
            self.undos = []
            self.redos = []

        def check_menu(self):
            """Menueintraege 'Undo' und 'Redo' (bzw. 'Rückgängig' und
            'Wiederholen') bearbeiten, so dass die Einträge 
            Informationen erhalten, was rückgängig gemacht bzw. 
            wiederholt wird. Zudem natürlich den Callback auf die neue
            Aktion umsetzen.
            """
            # TODO: aber wie???
            self.menu.entryconfig(???)
        
        def undo(self):
            command = self.undos.pop()
            command.undo()
            self.redos.append(command)
            
            self.check_menu()

        def redo(self):
            command = self.redos.pop()
            command.redo()
            self.undos.append(command)
            
            self.check_menu()

        def execute(self, command):
            command.redo()
            self.undos.append(command)
            self.redos = []
            
            self.check_menu()
Insbesondere interessiert mich dabei, wie man dabei automatisiert die GUI verändern kann

Re: UndoManager mit Tkinter-GUI

Verfasst: Mittwoch 9. September 2015, 09:53
von BlackJack
@sedi: Dazu müsste man `Command` noch einen Text mitgeben können der die Aktion beschreibt und dann kannst Du diesen Text jeweils in den Menüpunkt einfügen.

Re: UndoManager mit Tkinter-GUI

Verfasst: Mittwoch 9. September 2015, 11:11
von Alfons Mittelmeyer
sedi hat geschrieben:Insbesondere interessiert mich dabei, wie man dabei automatisiert die GUI verändern kann
GUI verändern, habe ich gelöst. Ganz einfach ist rückgängig: wenn Du etwa widgets hast, dafür gibt es widget.destroy(). Allerdings, wenn Du alle widgets in einem Container, etwa einem Frame löschen willst, dann musst Du Dir eine Funktion schreiben, die alle childs löscht.

Wenn Du aber die abgeleiteten widgets nimmst aus meinem Modul spazieren.py: http://www.python-forum.de/viewtopic.php?f=18&t=36838
Dann kannst Du die Widgets in einem Container mit deleteAllWidgets löschen:

Code: Alles auswählen

def deleteAllWidgets(containerWidget):
	dictionary=containerWidget.Dictionary.elements
	elementlist = []
	values=dictionary.values()	

	for e in values:
		for x in e:
			elementlist.append(x)

	dictionary.clear()

	for x in elementlist: x.destroy()
Und wenn Du etwas hinzufügen willst, dann lade einfach ein Script nach. Mit rauslöschen und nachladen kannst Die die GUI beliebig verändern.

Wenn Du automatisiert etwas tun willst, dann kannst Du für Aktionen Rückgängig Aktionen registrieren. Ich habe einen Aktionsproxy, der für Messages Aktionen aufruft. Den habe ich jetzt um einen zusätzlichen Parameter erweitert, das könnte etwa der Rückgängig Callback sein. Da könnte man dann eine zusätzliche rückgängig Funktion implementieren, die dann den Rückgängig Callback aufruft.

Oder man nimmt denselben Callback und ruft ihn mit einem Rückgängig Flag auf, eventuell verbunden mit Callback oder Callbacks löschen.

Und man kann alle Callbacks wieder löschen.

Re: UndoManager mit Tkinter-GUI

Verfasst: Mittwoch 9. September 2015, 11:44
von sedi
OK - also klar ist dass man dem Command eine Information über sein Vorhaben mitgeben muss, damit die Einträge 'Rückgängig' und 'Wiederholen' Zusatzinformationen ausgeben können. Aber warum muss ich deshalb alle Widgets löschen @Alfons Mittelmeyer?

Ich habe heute schon etwas rumprobiert und scheitere noch am Tkinter-Menü. Laut einigen Foren/Doku werden Menüeinträge mit der Methode ``menu.entryconfig(position, **kwargs)`` geändert, indem man in den ``kwargs`` die Eigenschaft, die man zu ändern gedenkt, einträgt - ich will den Label ändern, also sähe das bei mir beispielsweise für den UNDO-Befehl so aus:

Code: Alles auswählen

menu.entryconfig(position, label="Rückgängig ({}).format(undocmd.info))
Nur ist die Position ja nicht in jeder Anwendung die gleiche!

Hier aber meine Vorstellung/Wunsch: Könnte man nicht eine Methode programmieren - unten ``change_entry`` genannt - die nur durch die Angabe eines Rumpftextes einen Eintrag im Menü Bearbeiten findet und das Label neu setzt? So wie man ``fnmatch.fnmatch(pattern, text)`` benutzt - das wäre dann sehr komfortabel :)

Code: Alles auswählen

class Command:
    def __init__(self, *args, **kwargs):
        self.info = ""
    def undo(self):
        pass
    def redo(self):
        pass

class UndoManager:
    def __init__(self, appmenu):
        """
       :param appmenu: {tkinter menu object}
       """
        self.menu = appmenu.bearbeiten
        self.undos = []
        self.redos = []

    def check_menu(self):
        # hole Eintraege aus dem Menü, deren Label
        # sich aendern soll.
        #
        # ? Sehr praktisch waere es wie im nachfolgenden
        # ? Beispiel, wenn man einen Menueeintrag nur
        # ? dadurch aendern kann, wenn man nur einen
        # ? Teil seines Labels kennt. Genau diese fiktive
        # ? Methode ``change_entry`` waere sehr praktisch
        #
        if self.undos:
            undo = self.undos[-1]
            self.menu.change_entry("Rückgängig*", undo.info)
        if self.redos:
            redo = self.redos[-1]
            self.menu.change_entry("Wiederholen*", redo.info)
    
    ###
    # Hier folgt noch weiterer Code des UndoManagers ...

Re: UndoManager mit Tkinter-GUI

Verfasst: Mittwoch 9. September 2015, 11:57
von Alfons Mittelmeyer
Sorry, ich hatte gedacht, Du willst die GUI ändern und ganze GUI Teile rauslöschen und durch neue GUI Teile ersetzen. Ober offensichtlich, willst Du nur etwas ändern.

Also eine Lösung für Deine Vorstellung: mache eine Funktion, mit den Parametern alter_text, neuer_text, neuer_callback,
Die sucht dann das menü nach alter_text ab, löscht den alten callback, nimmt den neuer_callback auf und ändert den text auf 'neuer_text_

Re: UndoManager mit Tkinter-GUI

Verfasst: Mittwoch 9. September 2015, 11:59
von BlackJack
@sedi: Nach Texten in der GUI zu suchen die man da selber mal hingeschrieben hat ist keine gute Idee. Das wird spätestens dann zum Problem wenn jemand den Text ändert und vergisst das der an einer anderen Stelle im Programm eine besondere Bedeutung hat, oder wenn man die Anwendung mehrsprachig machen möchte und die Texte damit nicht mehr fest sind.

Du müsstest Dir die Positionen merken, also zum Beispiel dem Undomanager das Menüobjekt und die Positionen der beiden Menüpunkte beim erstellen übergeben.

Oder Du nimmst ein vernünftiges GUI-Rahmenwerk. Qt hat so eine Undo/Redo-Verwaltung beispielsweise schon dabei. :-)

Re: UndoManager mit Tkinter-GUI

Verfasst: Mittwoch 9. September 2015, 12:07
von Alfons Mittelmeyer
Ach so, Menüeinträge haben doch eine id oder so? Hab mich damit noch nicht befasst, dann registriere unter einem Namen diese id. und dann brauchst Du nicht suchen, sondern kannst direkt darauf zugreifen.

Also, ich habe eine Methode in einer Klasse: do_receive(owner,msgid,receive,optional_parameter)

Damit werden Callbacks für Namen registriert.

owner - kann None sein. Wenn Du etwas anderes angibst, kannst Du alle Callbacks für diesen owner auf einmal löschen.
msgid - ist eine Kennung für die Aktion. Da kannst Du etwa einen Text nehmen, der für Dich sinnmässig deinen Menüeintrag bedeutet.
receive - ist Deine Callback Funktion
optional_parameter - da könntest Du etwas nehmen, womit Du auf Deinen Menüeintrag zugreifen kannst - könnte auch zusätzlich eine undo und redo liste enthalten

Dann gibt es eine Methode: send(msgid,msgdata=None)

Hier gibst Du die Message ID an und einen Datenparameter für Deine Callback Funktion - könnte True sein für redo und False für undo
Oder auch fünf verschiedene Werte, etwa:
- ('action',)
. ('undo',)
- ('redo',)
- ('replace',new_msgid,new_text,new_callback)
- ('remove',)

Der Aufruf der Callback Funktion, wenn Du send aufrufst, erfolgt dann in diesem Fall durch dieses System so: callback((optional_parameter,(msgid,msgdata)))
Das müßte doch reichen, oder?

Und mit undo_receive(owner,msgid,receive) wirfst Du Callbackfunktionen wieder heraus. Damit sie auch ganz weg sind, nur temporär definieren und mit einziger Referenz durch die Registrierung. Das geht aber nur mit compile und eval - und dabei von einem File nachladen, wenn sie nicht permanent im Speicher sein sollen.

Alle callback Funktionen für einen owner wirfts Du raus mit: undo_receiveAll(owner)

Ach so, musst Du Dir überlegen, ob Du eine undo redo Liste pro Menüeintrag brauchst, oder nur insgesamt. Und in die Listen für insgesamt kannst Du dann statt callbacks Message Ids eintragen. Das wären dann sozusagen Event Stacks. Und wenn Aktionen nicht mehr zur Verfügung stehen und die Callbacks nicht mehr registriert sind, dann passiert mit diesen nicht mehr registrierten events auch nichts mehr, wenn sie noch in der undo oder redo liste stehen. Also besteht Crash Sicherheit bei nicht mehr verfügbaren Aktionen.

Re: UndoManager mit Tkinter-GUI

Verfasst: Mittwoch 9. September 2015, 14:03
von sedi
Also @Alfons Mittelmeyer das klingt mir sehr nach einem Signal-Framework und das betrifft die Callbacks, um die geht es mir aber nicht.

@BlackJack:
- Dein Vorschlag ist wahrscheinlich der praktibelste. Allerdings sehe ich nicht, warum man/irgendwer die Einträge ändern sollte. Das soll ja im Rahmen des UndoManagers geleistet werden. Man soll das ja dann eben nicht irgendwo per Hand ändern. Die beiden Einträge Undo/Redo im Bearbeiten Menü sind sozusagen dann tabu.
- Zur Frage der anderen Sprache wäre dann klar, dass man die Zeile

Code: Alles auswählen

self.menu.change_entry("Rückgängig*", undo.info)
angleichen muss, beispielsweise in:

Code: Alles auswählen

self.menu.change_entry(i18["Rückgängig"] + "*", undo.info)
Ich habe jetzt selbst kein Gefühl dafür, ob es denn überhaupt ein Szenario gibt, in welchem sich die Positionen ändern, aber unmöglich erscheint es mir nicht. Wie ändert man denn eigentlich die Position eines Menüeintrags in Tkinter?

Re: UndoManager mit Tkinter-GUI

Verfasst: Mittwoch 9. September 2015, 14:11
von Alfons Mittelmeyer
sedi hat geschrieben:Also @Alfons Mittelmeyer das klingt mir sehr nach einem Signal-Framework und das betrifft die Callbacks, um die geht es mir aber nicht.
BlackJack hatte etwas von anderen Sprachen geschrieben. Und für diesen Fall hätte man statt Namen von Menüeinträgen Signalnamen nehmen können - und die Signale hätten den Zugriff auf die Menüeinträge gehabt. Wenn aber die Einträge feststehen und man das nicht übersetzen will sondern suchen kann, dann erübrigt sich das Signalframework wohl. Außerdem ginge das auch einfacher mit einem Übersetzungsdictionary oder einem Menu Entry ID Dictionary - dann müßtest Du auch nicht suchen.

Re: UndoManager mit Tkinter-GUI

Verfasst: Mittwoch 9. September 2015, 14:19
von BlackJack
@sedi: Man kann Einträge davor löschen und neue einfügen. Es ist halt blöd das Menüeinträge in `Tkinter` keine Objekte sind auf die man eine Referenz halten könnte, womit dann egal wäre an welcher Stelle die im Menü stehen.

Re: UndoManager mit Tkinter-GUI

Verfasst: Mittwoch 9. September 2015, 14:30
von Alfons Mittelmeyer
Naja, einen Index bekommt man schon, denn man sich merken kann. Wenn man einen Eintrag löscht und an dieselbe Stelle den neuen einfügt, bleibt die Reihenfolge erhalten. Wenn man die Reihenfolge ändert, kann man eine Liste mit Kennungen dazu implementieren und die parallel zu insert und delete updaten und darin dann nach IDs suchen und den Index erhalten.

Wenn man keine Objekte hat, dann macht man sich eben welche.

Das wären dann die Menu Entry Widgets: “command”, “cascade” (submenu), “checkbutton”, “radiobutton”, or “separator” und die haben dann ein insert-add Layout.
Und die destroy Methode ist dann delete. Und remove ist dann delete mit merken.

Re: UndoManager mit Tkinter-GUI

Verfasst: Mittwoch 9. September 2015, 15:20
von sedi
Alfons Mittelmeyer hat geschrieben:Wenn man keine Objekte hat, dann macht man sich eben welche.

Das wären dann die Menu Entry Widgets: “command”, “cascade” (submenu), “checkbutton”, “radiobutton”, or “separator” und die haben dann ein insert-add Layout.
Und die destroy Methode ist dann delete. Und remove ist dann delete mit merken.
Also eine Erweiterung des eigentlichen Tkinter! Klingt gut und aufwändig.

Wäre das ein umsetzbarer Ansatz:

Code: Alles auswählen

# PYTHON 3.X
import tkinter as tk
 
class _MenuElement(object):
    """abstrakte Klasse"""
    def __init__(self, **atts):
        """
       :param atts: alle in Tkinter erlaubten Eigenschaften:
                             label, command, ...
       """
        self.atts = atts
 
# Typen: 'cascade', 'checkbutton', 'command', 'radiobutton', or 'separator'
#  (infohost.nmt.edu/tcc/help/pubs/tkinter/web/menu.html)
 
class Command(_MenuElement):
    pass
class Checkbutton(_MenuElement):
    pass
class Radiobutton(_MenuElement):
    pass
class Separator(_MenuElement):
    pass
class Cascade(_MenuElement):
    pass
 
 
class Menu(tk.Menu):
    def __init__(self, master, label, cnf=(), **kw):
        tk.Menu.__init__(self, master, cnf=cnf, **kw)
        self.entries = []
 
    def add(self, element):
        """Ueberschreiben der add-Methode, da ja jetzt nur noch
        Instanzen von Klassen ankommen, die von ``_MenuElement``
        abgeleitet wurden.
        """
        self.insert(len(self.entries), element)
 
    def insert(self, pos, element):
        """ auch ueberschreiben """
        if not isinstance(element, _MenuElement):
            raise ValueError(...)
 
        self.entries.insert(pos, element)
        tkintertyp = str(element.__class__.__name__).lower()
        tk.Menu.insert(self, pos, tkintertyp, **element.atts)

Re: UndoManager mit Tkinter-GUI

Verfasst: Mittwoch 9. September 2015, 15:40
von BlackJack
@sedi: Die vorletzte Zeile würde ich in die `_MenuItem`-Klasse packen. Vielleicht sogar als `__str__()`-Methode.

Re: UndoManager mit Tkinter-GUI

Verfasst: Mittwoch 9. September 2015, 16:33
von Alfons Mittelmeyer
@sedi ich hatte mir das mehr so vorgestellt:

a = MenuCommand(parent,label="Menutext")
a.add()

und evtl später, wenn es nicht gleich war

a['command'] = lambda: print("Hello")

und auch möglich:

a.remove()

und später wieder:

a.insert() # natürlich an selbe Posiition, wenn ohne index Angabe, falls die noch existiert - sonst hinten dran

Oder besser so etwas wie?

a.menu()
a.menu(index)
a.menu('end')

Sozusagen ein menu layout manager - wie sonst pack, place oder grid

aber wie würde dann a.menu_info() aussehen?

Re: UndoManager mit Tkinter-GUI

Verfasst: Mittwoch 9. September 2015, 16:43
von sedi
@Alfons Mittelmeyer:
Wenn die Tkinterelemente Objekte/Instanzen sind und man will diesen Objekten erlauben Menüfunktionalität auszuführen ``add``, ``remove``, ``insert``, dann benötigen Sie einen Verweis auf ihr Menü, denn in Tkinter werden diees Funktionen **nur** vom Menü ausgeführt.

vllt:

Code: Alles auswählen

# PYTHON 3.X
import tkinter as tk
     
class _MenuElement(object):
    """abstrakte Klasse"""
    def __init__(self, menu, **atts):
        """
        :param atts: alle in Tkinter erlaubten Eigenschaften:
                            label, command, ...
        """
        self.menu = menu
        self.atts = atts
 
    def add(self):
        self.menu.add(...)
    def remove(self):
        self.menu.delete(...)
    def insert(self, pos):
        self.menu.insert(...)

# Typen: 'cascade', 'checkbutton', 'command', 'radiobutton', or 'separator'
#  (infohost.nmt.edu/tcc/help/pubs/tkinter/web/menu.html)
 
class Command(_MenuElement):
    pass
class Checkbutton(_MenuElement):
    pass
class Radiobutton(_MenuElement):
    pass
class Separator(_MenuElement):
    pass
class Cascade(_MenuElement):
    pass

Re: UndoManager mit Tkinter-GUI

Verfasst: Mittwoch 9. September 2015, 16:46
von Alfons Mittelmeyer
@sedi hier ist doch der Verweis auf das Menü mit dem parent: a = MenuCommand(parent,label="Menutext")

Allerdings wäre das etwas aufwändig, wenn wir auch remove zulassen. Denn dann müssten wir alle config options etwa für checkbuttons merken und die auch im removed zustand ändern lassen.
Man kann es ja am Anfang mal ohne den removed Zustand machen. Dann muss man eben gleich das Menüwidget positionieren und lassen, wo es ist - löschen darf man es natürlich.

Also:

a = MenuCommand(parent,label="Menutext").add()
oder
a = MenuCommand(parent,label="Menutext").insert(x)

Ich werde bei mir aber doch alles implementieren. Dann haben wir eine Gleichbehandlung aller widgets. Und ich brauche das sowieso auch für Stellvertreter Widgets.
Wie es bei Panes für PanedWindows aussieht, muss ich mir auch noch ansehen.

Re: UndoManager mit Tkinter-GUI

Verfasst: Mittwoch 9. September 2015, 17:41
von sedi
Ich habe jetzt mal die Tkintererweiterung ohne die Menüfunktionalität der ``_MenuElement`` - Objekte gemacht:

Code: Alles auswählen

# PYTHON 3.X
import tkinter as tk

class _MenuElement(object):
    """abstrakte Klasse"""
    def __init__(self, menuobject, **atts):
        """
        :param menu: {menu object}
        :param atts: alle in Tkinter erlaubten Eigenschaften:
                             label, command, ...
       """
        self.menu = menuobject
        self._atts = atts
        self.label = ""

        for a in atts:
            self.__dict__[a] = atts[a]

    def __str__(self):
        return self.__class__.__name__.lower()

    @property
    def atts(self):
        return self._atts

    @property
    def pos(self):
        return self.menu.entries.index(self)


# Typen: 'cascade', 'checkbutton', 'command', 'radiobutton', or 'separator'
#  (infohost.nmt.edu/tcc/help/pubs/tkinter/web/menu.html)


class Command(_MenuElement):
    pass
class Checkbutton(_MenuElement):
    pass
class Radiobutton(_MenuElement):
    pass
class Separator(_MenuElement):
    pass
class Cascade(_MenuElement):
    pass


class Menu(tk.Menu):
    def __init__(self, master, label, **kw):
        if "tearoff" not in kw: kw["tearoff"] = 0
        tk.Menu.__init__(self, master, **kw)

        self.label = label
        self.entries = []

    def add(self, element):
        """Ueberschreiben der add-Methode, da ja jetzt nur noch
        Instanzen von Klassen ankommen, die von ``_MenuElement``
        abgeleitet wurden.
        """
        self.insert(len(self.entries), element)

    def insert(self, pos, element):
        if not isinstance(element, _MenuElement):
            raise ValueError(...)

        self.entries.insert(pos, element)
        tk.Menu.insert(self, pos, str(element), **element.atts)

    # adds ueberschreiben

    def add_cascade(self, **kw):
        self.add(Cascade(self, **kw))
        
    def add_checkbutton(self, **kw):
        self.add(Checkbutton(self, **kw))
        
    def add_command(self, **kw):
        self.add(Command(self, **kw))
        
    def add_radiobutton(self, **kw):
        self.add(Radiobutton(self, **kw))
        
    def add_separator(self, **kw):
        self.add(Separator(self, **kw))
    
    # inserts ueberschreiben
    
    def insert_cascade(self, index, **kw):
        self.insert(index, Cascade(self, **kw))
    
    def insert_checkbutton(self, index, **kw):
        self.insert(index, Checkbutton(self, **kw))
        
    def insert_command(self, index, **kw):
        self.insert(index, Command(self, **kw))
    
    def insert_radiobutton(self, index, **kw):
        self.insert(index, Radiobutton(self, **kw))
    
    def insert_separator(self, index, **kw):
        self.insert(index, Separator(self, **kw))

    # delete ueberschreiben

    def delete(self, index1, index2=None):
        last = index1
        if index2 is not None:
            last = index2

        for i in range(index1, last+1):
            del self.entries[i]

        tk.Menu.delete(self, index1, last)


class RootMenu(Menu):
    def __init__(self, master, **kw):
        Menu.__init__(self, master, "ROOT", **kw)
Es fehlt jetzt noch Tkintermanipulationen in die ``_MenuElement`` - Objekte zu übernehmen...

@Alfons Mittelmeyer: stimmt
@sedi hier ist doch der Verweis auf das Menü mit dem parent: a = MenuCommand(parent,label="Menutext")

Re: UndoManager mit Tkinter-GUI

Verfasst: Mittwoch 9. September 2015, 18:20
von Alfons Mittelmeyer
@sedi Da fehlt noch etwas:

Code: Alles auswählen

   def add_checkbutton(self, **kw):
        self.add(Checkbutton(self, **kw))
Da musst Du noch tk.Menu.add_checkbutton(self,...) aufrufen
Wenn Du nur überschreibst, dann hast Du ja nichts

Re: UndoManager mit Tkinter-GUI

Verfasst: Mittwoch 9. September 2015, 18:24
von sedi
So nach ein paar ersten Tests scheint der Tkinter-Wrapper zu funktionieren:

Code: Alles auswählen

# PYTHON 3.X
import tkinter as tk


class _MenuElement(object):
    """abstrakte Klasse"""
    def __init__(self, menuobject, **atts):
        """
        :param menu: {menu object}
        :param atts: alle in Tkinter erlaubten Eigenschaften:
                             label, command, ...
       """
        self._atts = {}
        self.menu = menuobject
        self.label = ""
        self.atts = atts

    def __str__(self):
        return self.__class__.__name__.lower()

    @property
    def pos(self):
        return self.menu.entries.index(self)

    @property
    def atts(self):
        return self._atts

    @atts.setter
    def atts(self, atts):
        self._atts.update(atts)
        self.__dict__.update(atts)


# Typen: 'cascade', 'checkbutton', 'command', 'radiobutton', or 'separator'
#  (infohost.nmt.edu/tcc/help/pubs/tkinter/web/menu.html)


class Command(_MenuElement):
    pass
class Checkbutton(_MenuElement):
    pass
class Radiobutton(_MenuElement):
    pass
class Separator(_MenuElement):
    pass
class Cascade(_MenuElement):
    pass


Entries = dict([(str(e).capitalize(), e) for e in
                [Command, Checkbutton, Radiobutton, Separator, Cascade]])


class Menu(tk.Menu):
    def __init__(self, master, label, **kw):
        if "tearoff" not in kw: kw["tearoff"] = 0
        tk.Menu.__init__(self, master, **kw)

        self.label = label
        self.entries = []

    def add(self, element):
        """Ueberschreiben der add-Methode, da ja jetzt nur noch
        Instanzen von Klassen ankommen, die von ``_MenuElement``
        abgeleitet wurden.
        """
        self.insert(len(self.entries), element)

    def insert(self, pos, element):
        if not isinstance(element, _MenuElement):
            err = "one of '{}' expected! ".format(list(Entries.keys()))
            err += "got {} instead".format(str(element).capitalize())
            raise ValueError(err)

        self.entries.insert(pos, element)
        tk.Menu.insert(self, pos, str(element), **element.atts)

    # adds ueberschreiben

    def add_cascade(self, **kw):
        self.add(Cascade(self, **kw))
        
    def add_checkbutton(self, **kw):
        self.add(Checkbutton(self, **kw))
        
    def add_command(self, **kw):
        self.add(Command(self, **kw))
        
    def add_radiobutton(self, **kw):
        self.add(Radiobutton(self, **kw))
        
    def add_separator(self, **kw):
        self.add(Separator(self, **kw))
    
    # inserts ueberschreiben
    
    def insert_cascade(self, index, **kw):
        self.insert(index, Cascade(self, **kw))
    
    def insert_checkbutton(self, index, **kw):
        self.insert(index, Checkbutton(self, **kw))
        
    def insert_command(self, index, **kw):
        self.insert(index, Command(self, **kw))
    
    def insert_radiobutton(self, index, **kw):
        self.insert(index, Radiobutton(self, **kw))
    
    def insert_separator(self, index, **kw):
        self.insert(index, Separator(self, **kw))

    # delete ueberschreiben

    def delete(self, index1, index2=None):
        last = index1
        if index2 is not None:
            last = index2

        for i in range(index1, last+1):
            del self.entries[i]

        tk.Menu.delete(self, index1, last)

    def entryconfigure(self, index, **kw):
        entry = self.entries[index]
        entry.atts = kw
        tk.Menu.entryconfigure(self, index, **kw)


class RootMenu(Menu):
    def __init__(self, master, **kw):
        Menu.__init__(self, master, "ROOT", **kw)
Was sagt ihr dazu?
und vor allen Dingen: Wie verbindet man das jetzt mit dem UndoManager?

Re: UndoManager mit Tkinter-GUI

Verfasst: Mittwoch 9. September 2015, 18:40
von Alfons Mittelmeyer
@sedi bitte noch meinen vorigen post beachten und dann solltest Du erläutern, welche Aktionen rückgängig gemacht und wiederholt werden sollen. Wohl nicht nur Klicks im Menü?

Und undo und redo haben fast gar nichts mit Deinem Menü zu tun, nur dass das vom Menü mit den Menüpunkten 'undo' und 'redo' aufgerufen wird.