BlackJack hat geschrieben:
Gegen Code in Zeichenketten ist einzuwenden dass das nur ganz schlecht skaliert. Denn schon in der nächsten Ebene, wenn man in diesem Code in einer Zeichenkette wieder eine Zeichenkette mit Code haben möchte, wird das unhandlich und bei einer dritten Ebene unbenutzbar. Es geht hier nicht um Geschwindigkeit, sondern dass man bei zur Laufzeit kompiliertem Code in Zeichenketten offenbar mit der Ausdruckstärke der Sprache nicht zufrieden ist, oder damit nicht vernünftig umgehen kann. Und gerade Python ist dynamisch genug das man nur sehr selten auf solche Krücken zurückgreifen muss. Code-Fragmente aus Zeichenketten zu compilieren die über das ganze Programm verteilt sind, ist auch etwas anderes als ``import`` zu verwenden.
Da hast Du natürlich recht. Wenn man einen String beginnt mit """
dann geht in der nächsten Ebene noch \"\"\"
Wenn man allerdings darin ein \n braucht, das geht dann nicht. man kann natürlich sich dann daraus noch mit einer Funtion behelfen, etwa + nl() +
die dann ein newline zurückgibt.
Und ein über 200 Zeilen langer Programmstring schaut auch nicht gut aus. Statt so langer Strings sollte ich lieber von einer Quelldatei importieren.
Danke, für den Tip. Das betrifft drei Module meines GuiCreators, nämlich die Änderung der config options, der layout options pack_info, grid_info oder place_info und der Navigation in der GUI
Andere Module sind aber sehr übersichtlich, denn man hat eine klare Trennung von GUI und Code. Der GUI Teil umfasst die Kreation des Widgets und das Layout, wie etwa in meinem Pack Modul:
Code: Alles auswählen
Button('RIGHT',text="""RIGHT""",pady='2',padx='1',bg='green')
Button('BOTTOM',text="""BOTTOM""",pady='2',padx='1',bg='green')
Button('TOP',text="""TOP""",pady='2',padx='1',bg='green')
Label('Label',width='1')
Label('PackTitle',text="""pack""",fg='blue')
Button('LEFT',text="""LEFT""",pady='2',padx='1',bg='green')
widget('PackTitle').pack(side='left')
widget('Label').pack(side='left')
widget('TOP').pack(side='left')
widget('LEFT').pack(side='left')
widget('RIGHT').pack(side='left')
widget('BOTTOM').pack(side='left')
Das ist vom GuiCreator generierter Code. Die Reihenfolge der Label und Button Commands ist zufällig, da sie aus dem Verzeichnis Dictionary kommt.
Allerdings spielt bei einem Pack Layout die Reihenfolge eine wichtige Rolle. Deshalb wird aus einer Packing Liste am Ende die richtige Pack Reihenfolge generiert.
Übersichlich ist das aber deshalb weil hier GUI und Code unvermischt sind. Der Code Teil schließt sich dann an:
Code: Alles auswählen
### CODE ===================================================
# the buttons do a pack with parameter side = top, left, bottom or right
# and send a 'BASE_LAYOUT_CHANGED', which contains the current packed widget reference and the layout before
push(EvCmd("""
send('BASE_LAYOUT_PLACE_MOUSEOFF')
push(this().Layout)
pack(side=Par())
send('BASE_LAYOUT_CHANGED',(this(),pop()))
"""))
widget("TOP").evcommand(top(),TOP)
widget("LEFT").evcommand(top(),LEFT)
widget("RIGHT").evcommand(top(),RIGHT)
widget("BOTTOM").evcommand(pop(),BOTTOM)
# ---- Receivers for message 'BASE_LAYOUT_REFRESH' ------------------------------------------------
# if the current user widget has a PACKLAYOUT, the background of Label 'PackTitle' shall be shown yellow, otherwise normal
registerReceiver('BASE_LAYOUT_REFRESH',"""
if Msg().Layout == PACKLAYOUT: Par()[0].configure(bg="yellow")
else: Par()[0].configure(bg=Par()[1])
""",(widget("PackTitle"),widget("PackTitle").getconfig("bg")))
# if there is already a GRIDLAYOUT in the container of the current user widget, the container LabelFrame 'PackFrame' will be hidden (unlayout),
# and otherwise shown
registerReceiver('BASE_LAYOUT_REFRESH',"send('HIDELAYOUT_PackOrGrid',(Msg(),GRIDLAYOUT,Par()))",container())
### ========================================================
Wichtig ist dabei der Beginn des CODE Teils mit ### CODE und das Ende mit ###
Daran erkennt der GuiCreator, dass es der Code Teil ist und speichert ihn beim Hereinladen als String im Container ab. Nach Modifizierund der GUI kann dann das ganze Programm inklusive Code wieder gespreichert werden. Oder der Code kann auch zur Laufzeit modifiziert und getestet werden.
Hier in diesem Beispiel wird der String compilert und dann zur Variablenvermeidung auf einen Stack gepusht. Denn er wird für alle 4 Buttons gebraucht. Den Button Kommandos kann man nämlich entweder Strings oder compilierten Code übergeben.
Was der Code macht:
send('BASE_LAYOUT_PLACE_MOUSEOFF')
Das Widget, das gepackt werden soll, könnte zuerst ein Placelayout gehabt haben. Beim Placelayout könnten Mouseevents mit dem Widget verbuden sein, sodass man es mit der Maus bewegen kann.
Wenn es aber gepackt wird und dann bei mouse move seine yx Koordinaten verändern will, gäbe es einen Crash. Daher die Message, solche Mouse events bitteschön wieder herauszunehmem. Darum kümmert sich dann das Place Layout Modul.
push(this().Layout)
Hier wird die Kennzeichnung des alten Layouts gesichert.
pack(side=Par())
Hier wird der Pack vorgenommen. Die Seite kommt dabei aus dem Parameter, der bei der Definition der Buttoncommands übergeben wird.
send('BASE_LAYOUT_CHANGED',(this(),pop()))
Hier wird gesendet, dass sich das Layout geändert hat. Als Parameter wird übergeben, das widget und die Kennung des vorherigen Layouts.
Je nachdem, wie das zuvor war, müssen nämlich andere Module benachrichtigt werden. War es vorher auch ein Packlayout, muss nichts geschehen, war es ein anderes Layout, mussen die anderen Layout Basis Module benachrichtigt werden. Durch gelben Hintergrund des Titels zeigen die nämlich an, welches Layout das selektierte widget hat. Zu benachrichtigen ist dann auch das Layout Options Modul, dass es jetzt ein pack_info zeigen muss.
Hatte das Widget vorher kein Layout, dann ist auch das Navigationsmodul zu verständigen, denn dieses zeigt die Namen von widgets, die kein Layout haben in kursiv.
Darauf folgen dann die Buttonkommandos mit Übergabe des Parameters, welche Seite. Denn man kann auch einen Parameter mit übergeben und wenn es mehrere sein sollen, nimmt man ein tuple.
Als nächstes wird ein Receiver für die Message BASE_LAYOUT_REFRESH installiert.
Wenn ein selektiertes widget ein Packlayout hat, soll der Titel des Pack Moduls gelben Hintergrund haben, ansonsten nicht.
Und dann kommt noch ein zweiter Receiver für dieselbe message. Hier sendet dann das Packmodul, dass es versteckt werden soll, wenn bereits ein GRIDLAYOUT im container des widgets vorliegt.
Bei pack und grid gäbe es sonst einen Systemabsturz
War das jetzt etwa sehr unübersichtlich? Sicher ist dieser Code äußerst ungewohnt. Aber unübersichtlich würde ich nicht unbedingt denken.