Seit 2002 Diskussionen rund um die Programmiersprache Python
https://www.python-forum.de/
Also sorry, ob jemand den Stack benutzen will oder Variablen ist Sache des Programmieres. Das kann jeder, der etwas programmieren will, selber entscheiden.Sirius3 hat geschrieben:Die Kommentare zu Deinen globalen Variablen lassen schlimmes erahnen. Ich kann mir ungefähr vorstellen, wie komplex es ist, die Stacks jeweils richtig zu füllen und wieder abzuräumen. Da die Variablen aber global sind, ist es so gut wie unmöglich, diesen komplexen Code annähernd vollständig zu testen. Ohne Tests ist es nur Glück, wenn das Programm anscheinend funktioniert. Du siehst also, Deine Designentscheidung zieht viele ungünstige Konsequenzen nach sich.
Code: Alles auswählen
def execute(self):
ObjectStack.append(self)
self.evcode.execute()
ObjectStack.pop()
Ja, Jens ist eine gute Idee. Aber zuvor würde ich gerne beim Gui Creator auch einen schönen Code haben.jens hat geschrieben:@Alfons Mittelmeyer: Was hältst du davon einfach mal die sourcen von DynTkInter auf github zu packen, statt immer nur davon zu reden?!?
btw. einen GUI Designer für TkInter hätte ich schon gern. Weil bei komplexeren grid Geschichten, mir die Sache zu unübersichtlich wird.
Code: Alles auswählen
function(*args1,me,event.*args2)
Code: Alles auswählen
from tkinter import *
# selected widget similar as in DynTkInter
SelectedWidget = None
def this():
global SelectedWidget
return SelectedWidget
# universal GuiCallback Class for GuiCallbacks and GuiEventCallbacks for functions with variable number of parameters
class GuiCallback:
def __init__(self,widget,function,parameters=()):
self.widget = widget
self.function=function
self.parameters = parameters
def execute(self,event=None):
self.function(self.widget,event,*self.parameters)
# GuiCallBack Functions for command and events
def commandCallBack(widget,function,parameters=()):
cmd = GuiCallback(widget,function,parameters)
widget.config(command=cmd.execute)
def eventCallBack(widget,eventkey,function,parameters=()):
cmd = GuiCallback(widget,function,parameters)
widget.bind(eventkey,cmd.execute)
# ================ Example from DynTkInter GuiCreator =======================
root = Tk()
root.title("GUI Callback Function")
master=LabelFrame(text="Place Layout")
master.pack(anchor='nw')
Label(master,text="x",padx='3').grid(column='1',row='0')
Label(master,text="y",padx='3').grid(column='1',row='1')
SpinboxX = Spinbox(master,increment='10.0',width='4',to='2000.0')
SpinboxX.grid(column='2',row='0')
SpinboxY = Spinbox(master,increment='10.0',width='4',to='2000.0')
SpinboxY.grid(column='2',row='1')
# ============ This is now the universal Callbackfunction =================
# Parameters me and event are required. The following parameter may be chosen free.
# These parameters are set, when the callbacks are defined (CallBack Functions commandCallBack, eventCallBack)
def function(me,event,xEntry,yEntry):
this().place(x=xEntry.get(),y=yEntry.get())
commandCallBack(SpinboxX,function,(SpinboxX,SpinboxY))
eventCallBack(SpinboxX,'<Return>',function,(SpinboxX,SpinboxY))
commandCallBack(SpinboxY,function,[SpinboxX,SpinboxY])
eventCallBack(SpinboxY,'<Return>',function,[SpinboxX,SpinboxY])
master = LabelFrame(text="PlaceArea",height='400',width='400')
master.pack()
SelectedWidget=Button(master,text="Let me move")
this().place(y='0',x='0')
root.mainloop()
Code: Alles auswählen
# for Return key or mouse klick: get active selection from the listbox, hide the listbox, set the layout and insert the text in the Entry for showing
VAR["LISTBOXCLICK_Return"] = EvDataCmd("""
Data().execute() # getactive entry or nearest to mouse click
Par()[2].unbind("<Return>")
Par()[2].unbind("<Button-1>")
Par()[2].unlayout()
Par()[0].setconfig(Par()[1][0],top())
Par()[3].delete(0,END)
Par()[3].insert(0,pop())
""",EvCmd("push(Par()[2].get(ACTIVE))"))
VAR["LISTBOXCLICK_Mouse"] = EvDataCmd(VAR["LISTBOXCLICK_Return"],EvCmd("push(Par()[2].get(Par()[2].nearest(Event().y)))"))
Code: Alles auswählen
function(*args1,me,event.*args2)
Code: Alles auswählen
function(*itertools.chain(args1, (me, event), args2))
+1Sirius3 hat geschrieben:Zu jeder Regel gibt es Ausnahmen. Die müssen aber gründlich überlegt und begründet sein.
- eingerückt wird immer mit 4 Leerzeichen pro Ebene
- Namen von Variablen und Funktionen werden klein geschrieben, von Klassen groß, von Konstanten komplett in Großbuchstaben.
- Werte betreten eine Funktion als Argumente und verlassen sie als Rückgabewerte. Globale Variablen sind zu vermeiden.
- Sterchenimporte werden nicht benutzt
- eval, exec, compile, etc. werden nicht benutzt
- auf Modulebene stehen außer Konstanten- und Klassen und Funktionsdefinitionen kein Code
Sirius3 hat geschrieben: Eingeht in den aktuellen Python-Versionen noch nicht. Solch ein Konstrukt verwendest Du aber in Deinem gezeigten Code auch nicht. Die allgemeinste Lösung würde übrigens so aussehen:Code: Alles auswählen
function(*args1,me,event.*args2)
Dann ist es egal welchen Typ args1 und args2 haben.Code: Alles auswählen
function(*itertools.chain(args1, (me, event), args2))
Code: Alles auswählen
VAR["LISTBOXCLICK_Mouse"] = EvDataCmd(VAR["LISTBOXCLICK_Return"],EvCmd("push(Par()[2].get(Par()[2].nearest(Event().y)))"))
Code: Alles auswählen
def function(par1,par2,par3,defPar1=DefValue1,defPar2=DefValue2)
Code: Alles auswählen
def myfunction(defPar1,defPar2,par1,par2,par3): usw
MyFunction = Function(myfunction,(defValue1,defValue2))
MyFunction.call(val1,val2,val3)
Code: Alles auswählen
MyFunctionNew = Function(MyFunction,(defValueNew1,defValueNew2))
Code: Alles auswählen
# statt MyFunction.call(val1,val2,val3)
MyFunction.par(val1,val2,val3)
# und später
MyFunction.execute()
Code: Alles auswählen
# mit tuple
MyFunction = Function(myfunction,(defValue1,defValue2))
# oder ohne tuple
MyFunction = Function(myfunction,defValue1,defValue2)
Code: Alles auswählen
# Funktionsobjekt ohne meself und ohne fixvalues
MyFunction=Function(myfunction)
# Funktionsobjekt mit fixvalues und ohne meself
MyFunction=Function(myfunction,[value1.value2])
#oder
MyFunction=Function(myfunction,(value1.value2))
# Funktionsobjekt mit fixvalues und mit meself
MyFunction=Function(myfunction,[value1.value2],True)
#oder
MyFunction=Function(myfunction,(value1.value2),True)
# Funktionsobjekt ohne fixvalues und mit meself
MyFunction=Function(myfunction,None,True)
# oder
MyFunction=Function(myfunction,(),True)
# oder
MyFunction=Function(myfunction,[],True)
Code: Alles auswählen
# So wird ein Funktionsobjekt aufgerufen:
MyFunction.call(par1,par2,par3)
# So werden lediglich die Parameter geladen:
MyFunction.par(par1,par2,par3)
#Der Aufruf kann dann später mit MyFunction.execute() erfolgen
Kann Dir leider kein einfaches Beispiel posten, denn so eine Klasse braucht man erst, wenn es nicht mehr einfach ist. Wenn etwa eine Rückruffunktion selber dynamisch Widgets installiert und dazu Rückruffunktionen über die Parameter zur Verfügung hat.Sirius3 hat geschrieben:Ich habe keine Ahnung für was Funktionsobjekte sind, für was man Widget-Parameter oder Rückrufparameter braucht, oder wer was aufruft.
Kannst Du ein lauffähiges Beispiel posten, das wenigstens Teile Deiner Ideen demonstriert. Deine Vorgehensweise ist so weit weg von jeglichem Standard, dass es ohne konkreten Code wirklich schwierig ist, Dir zu sagen, wo Dein Denkfehler ist.
Code: Alles auswählen
class DynAction:
def __init__(self,widget,cmd,data=None):
self.widget = widget
self.data = data
self.msgdata = None
if type(cmd) is str: self.evcode = EvCmd(cmd)
else: self.evcode = cmd
def receive(self,msgdata = None):
self.msgdata = msgdata
ObjectStack.append(self)
self.evcode.execute()
ObjectStack.pop()
Code: Alles auswählen
import types
class DynAction:
def __init__(self,widget,cmd,data=None):
self.widget = widget
self.data = data
self.msgdata = None
self.isfunction = False
if type(cmd) is types.TypeFunction:
self.isfunction = True
self.evcode = cmd
elif type(cmd) is str: self.evcode = EvCmd(cmd)
else: self.evcode = cmd
def receive(self,msgdata = None):
self.msgdata = msgdata
if self.isfunction:
if self.data == None: self.evcode(msgdata,self.widget)
else: self.evcode(msgdata,self.widget,*self.data)
else:
ObjectStack.append(self)
self.evcode.execute()
ObjectStack.pop()
Code: Alles auswählen
class DynAction:
def __init__(self, widget, cmd, data=()):
self.widget = widget
self.data = data
self.evcode = cmd
def receive(self, msgdata=None):
self.evcode(msgdata, self.widget, *self.data)
Code: Alles auswählen
def receive(self, msgdata=None):
self.msgdata = msgdata
self.evcode(self)
Code: Alles auswählen
from copy import copy
class Callback:
def __init__(self,function,parameters=None,widget=None,wishEvent=False,wishSelf = False):
self.widget = widget
self.event = None
self.parameters = []
if type(parameters) is tuple:
for e in parameters: self.parameters.append(e)
elif type(parameters) is list: self.parameters = parameters
elif parameters != None: print("Error: Callback parameters have to be tuples or lists")
self.wishEvent = wishEvent
self.wishSelf = wishSelf
self.function = function
self.mydata = None # may be used for many purposes. Accessible via self
# for execution later =======
def execute(self):
par = []
if self.widget != None: par = [self.widget]
if self.wishEvent: par.append(self.event)
if self.wishSelf: par.append(self)
par += self.parameters
return self.function(*par)
def setEvent(self,event = None):
self.event = event
return self.execute
# for execution immediate =======
def receive(self,event = None): return self.setEvent(event)()
# for using the Callback as funcion =======
def call(self,*args): return self.function(*args) # a function cannot be copied, but a Callback can. Using different mydata, the functions can behave different.
# Tests =========================================================================
# we need the parameters, if we want to use the same function for different widgets
def function(par1=1,par2=2,par3=3,fix="Fix"): print (par1,par2,par3,fix)
MyCallback = Callback(function)
MyCallback.receive()
MyCallback = Callback(function,("val1","val2","val3"))
MyCallback.receive()
# now with widget
def function(mewidget,par1=1,par2=2,par3=3,fix="Fix"): print (mewidget,par1,par2,par3,fix)
MyCallback = Callback(function,None,"Widget")
MyCallback.receive()
MyCallback = Callback(function,("val1","val2","val3"),"Widget")
MyCallback.receive()
# now with event
def function(mewidget, event, par1=1,par2=2,par3=3,fix="Fix"): print (mewidget,event,par1,par2,par3,fix)
MyCallback = Callback(function,None,"Widget",True)
MyCallback.receive("'Hello Event'")
def function(event, par1=1,par2=2,par3=3,fix="Fix"): print (event,par1,par2,par3,fix)
MyCallback = Callback(function,("val1","val2","val3"),None,True)
MyCallback.receive("'Hello Event'")
# now with self
def function(mewidget, event, meself, par1=1,par2=2,par3=3,fix="Fix"):
print (mewidget,event,par1,par2,par3,fix)
print("These are my parameters: ", meself.parameters)
MyCallback = Callback(function,("val1","val2","val3"),"Widget",True,True)
MyCallback.receive("'Hello Event'")
# now call and copy and mydata
def function(meself): meself.mydata()
MyCallback1 = Callback(function,None,None,False,True)
MyCallback1.mydata = lambda: print("I am Callback 1")
MyCallback2 = copy(MyCallback1)
MyCallback2.mydata = lambda: print("I am Callback 2")
MyCallback1.call(MyCallback1)
MyCallback2.call(MyCallback2)
Code: Alles auswählen
# now with event
def function(mewidget, event, par1=1,par2=2,par3=3,fix="Fix"): print (mewidget,event,par1,par2,par3,fix)
MyCallback = Callback(function,None,"Widget",True)
MyCallback.receive("'Hello Event'")
Code: Alles auswählen
def function(mewidget, event, par1=1,par2=2,par3=3,fix="Fix"): print (mewidget,event,par1,par2,par3,fix)
MyCallback = lambda event=None: function("Widget", event)
MyCallback("Hello Event")
Ja sieht auf den ersten Blick so aus. Sagen wir die Funktionalität ist fast dieselbe. Muss überlegen, was flexibler ist und was den Anforderungen genügt.Sirius3 hat geschrieben:Du siehst, Callback wurde einfach durch lambda ersetzt, die Funktionalität ist die selbe.Code: Alles auswählen
def function(mewidget, event, par1=1,par2=2,par3=3,fix="Fix"): print (mewidget,event,par1,par2,par3,fix) MyCallback = lambda event=None: function("Widget", event) MyCallback("Hello Event")
Hab nachgedacht. Läßt sich ganz bestimmt mit lambda machen. Die Frage ist nur, wie sähe das aus? Hier das Beispiel:Sirius3 hat geschrieben:Du siehst, Callback wurde einfach durch lambda ersetzt, die Funktionalität ist die selbe.Code: Alles auswählen
def function(mewidget, event, par1=1,par2=2,par3=3,fix="Fix"): print (mewidget,event,par1,par2,par3,fix) MyCallback = lambda event=None: function("Widget", event) MyCallback("Hello Event")
Code: Alles auswählen
# Alter Code ==================================================================
# for some layout options we offer a selection by listbox
VAR["LISTSELECTION"] = EvDataCmd("""
Button(text="?").rcgrid(0,2) # create a help button for showing the listbox
evcommand(Data(),(Msg(),top(),widget("Listbox"),widget("Entry")))
""",VAR["ListBoxHelpButton"])
VAR.pop("ListBoxHelpButton",None)
# So stelle ich mir den neuen Code vor ============================================================
def function(selectedElement,configoption,ListBoxHelpButtonCallbackFunction=VAR["ListBoxHelpButton"]):
Button(text="?").rcgrid(0,2) # create a help button for showing the listbox
evcommand(ListBoxHelpButtonCallbackFunction,(selectedElement,configoption,widget("Listbox"),widget("Entry")))
VAR.pop("ListBoxHelpButton",None)
VAR["LISTSELECTION"] = function
# Dazu soll nach meiner Vorstellung definiert sein ==================================================
# Aus DynTkInter widget class
def evcommand(self,function,parameters=None): self.config(command=lambda cmd=Callback(function,parameters,self).execute : send('execute_function',cmd))
# und dazu
def evcommand(evcmd,data=None): this().evcommand(evcmd,data)
Code: Alles auswählen
evcommand(ListBoxHelpButtonCallbackFunction,(selectedElement,configoption,widget("Listbox"),widget("Entry")))