如何在命令函数调用中避免全局变量

时间:2013-09-03 15:39:38

标签: python tkinter global

我仍在研究围绕两个行星移动的代码,并展示它们之间的引力。我试图通过显示两个允许选择你想要移动的行星的按钮来使它更容易使用。然后,您可以单击画布,所选行星将移动到您单击的位置。

该程序有效,但我想知道是否有更好的方法来编写它然后使用全局语句使用chngBchngO函数。 我仍然无法相信在Python中,当将其分配给按钮的command参数时,您将被迫使用不带参数的函数。

基本上我想知道是否可以编写类似command = (a=1)的内容 (我知道这不起作用,但你明白了。) 此外,可能还有另一种方法,而不是必须使用变量来知道选择了哪个行星(最后按下了哪个按钮)。

我使用Python 3。

from tkinter import *
import math

x, y = 135, 135
a = 0

def gravitation (obj1,obj2):#showing gravitational force between planets 
    a, b, c, d = can.coords (obj1)
    e, f, g, h = can.coords (obj2)
    dist = math.sqrt ((((a+c)/2)-((e+g)/2))**2+(((b+d)/2)-((f+h)/2))**2)
    if dist != 0:
        grav = 6.67384/dist
    else:
        grav = "Infinite"
    str(grav)
    return grav

def chngB ():#Telling Blue planet is selected
    global a
    a = 1

def chngO ():#Telling Orange planet is selected
    global a
    a = 0

def updt ():#Updating gravitation label
    lbl.configure (text = gravitation(oval1, oval2)) 


def moveBlue (event):#Placing blue planet where mouse click on canv
    coo = [event.x-15, event.y-15, event.x+15, event.y+15]
    can.coords(oval1, *coo)
    updt()

def moveOrange (event):#Placing orange planet where mouse click on canv
    coo = [event.x-15, event.y-15, event.x+15, event.y+15]
    can.coords(oval2, *coo)
    updt()

def choice (event):#Function binded to can, move the selected planet (blue = 1, prange = 0)
    if a == 0:
        moveOrange(event)
    else :
        moveBlue(event)

##########MAIN############

wind = Tk() # Window and canvas
wind.title ("Move Da Ball")
can = Canvas (wind, width = 300, height = 300, bg = "light blue")
can.grid(row=0, column=0, sticky =W, padx = 5, pady = 5, rowspan =3)
can.bind ("<Button-1>", choice)
Button(wind, text = 'Quit', command=wind.destroy).grid(row=2, column=1, sticky =W, padx = 5, pady = 5)

oval1 = can.create_oval(x,y,x+30,y+30,width=2,fill='blue') #Planet 1 moving etc
buttonBlue = Button(wind, text = 'Blue Planet', command = chngB)
buttonBlue.grid(row=1, column=1, sticky =W, padx = 5, pady = 5)

oval2 = can.create_oval(x+50,y+50,x+80,y+80,width=2,fill='orange') #Planet 2 moving etc
buttonOrange = Button(wind, text = 'Orange Planet', command = chngO)
buttonOrange.grid(row=0, column=1, sticky =W, padx = 5, pady = 5)

lbl = Label(wind, bg = 'white')#label
lbl.grid(row=4, column=1, sticky =W, padx = 5, pady = 5, columnspan = 3)
gravitation (oval1, oval2)

wind.mainloop()

2 个答案:

答案 0 :(得分:1)

不幸的是,你不能拥有一个带有语句(赋值)的lambda表达式。 但是您可以轻松地只使用一个setter函数返回一个可以传递给Button构造函数的闭包。以下是创建和使用闭包的示例:

a = 0

def set_a (v):
    def closure ():
        global a
        a = v
    return closure

command = set_a(42)
command()
print a    # prints 42

command = set_a(17)
command()
print a    # prints 17

答案 1 :(得分:1)

通常,如果您想要一个按钮在N个值之一之间切换变量,您将使用一组radiobuttons。当您使用单选按钮时,您可以将其与变量关联,这样无论何时单击按钮,都会自动选择变量。

例如:

planet = IntVar()
planet.set(0)

buttonBlue = Radiobutton(wind, text="Blue Planet", variable=planet, value=1)
buttonOrange = Radiobutton(wind, text="Orange Planet", variable=planet, value=0)
...
def choice (event):#Function binded to can, move the selected planet (blue = 1, prange = 0)
    if planet.get() == 0:
        moveOrange(event)
    else :
        moveBlue(event)

如果您真的想使用常规按钮,则可以使用单个回调而不是两个回调来执行此操作,然后使用lambdafunctools.partial传递新值。

例如:

buttonBlue = Button(wind, text = 'Blue Planet', command = lambda: change(1))
buttonOrange = Button(wind, text = 'Blue Planet', command = lambda: change(0))
def change(newValue):
    global a
    a = newValue