在子函数中定义python全局变量

时间:2015-07-14 16:08:31

标签: python python-2.7 tkinter global-variables

我有一个Tkinter gui,用复选框打开一个单独的gui。在这个单独的窗口中,我需要引用复选框的状态,但是我收到以下错误:

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Python27\lib\lib-tk\Tkinter.py", line 1470, in __call__
    return self.func(*args)
  File "C:\@ Batch\LMS Python Script\tester3.pyw", line 23, in var_states
    print("FX: %d, FY: %d, FZ: %d, MX: %d, MY: %d, MZ: %d" % (FX_1.get(), FY_1.get(), FZ_1.get(),MX_1.get(), MY_1.get(), MZ_1.get()))
NameError: global name 'FX_1' is not defined

是否可以从子函数定义和引用全局变量?

这是我的代码:

from Tkinter import *
import Tkinter
import tempfile

root = Tkinter.Tk()
root.title("Generate APDL")
root.geometry("200x225")

Lbl1 = Label(root, text="How many interface points?")
Lbl1.pack(side=TOP,padx=5,pady=5)
Entry1 = Entry(root, bd =1)
Entry1.pack(side=TOP,padx=5,pady=5)

def NewWindow():

    IPoints=int(Entry1.get())
    NumPoints=IPoints+1

    master = Tkinter.Toplevel()
    master.title("Select Unit Load Components")

    def var_states():
        print("FX: %d, FY: %d, FZ: %d, MX: %d, MY: %d, MZ: %d" % (FX_1.get(), FY_1.get(), FZ_1.get(),MX_1.get(), MY_1.get(), MZ_1.get()))

    def CloseWindow():
        master.destroy()

    for i in xrange(1,NumPoints):

        Label(master, text="PT_%d: " % i).grid(row=i,column=0, sticky=W)
        exec('global FX_' + str(i)) in globals(), locals()
        Checkbutton(master, text="FX", variable='FX_%d' % i).grid(row=i,column=2, sticky=W)
        exec('global FY_' + str(i)) in globals(), locals()
        Checkbutton(master, text="FY", variable='FY_%d' % i).grid(row=i,column=3, sticky=W)
        exec('global FZ_' + str(i)) in globals(), locals()
        Checkbutton(master, text="FZ", variable='FZ_%d' % i).grid(row=i,column=4, sticky=W)
        exec('global MX_' + str(i)) in globals(), locals()
        Checkbutton(master, text="MX", variable='MX_%d' % i).grid(row=i,column=5, sticky=W)
        exec('global MY_' + str(i)) in globals(), locals()
        Checkbutton(master, text="MY", variable='MY_%d' % i).grid(row=i,column=6, sticky=W)
        exec('global MZ_' + str(i)) in globals(), locals()
        Checkbutton(master, text="MZ", variable='MZ_%d' % i).grid(row=i,column=7, sticky=W)


    Label(master, text=" ").grid(row=99,column=0, sticky=W)
    Bttn1=Button(master, text='Generate APDL Snippet', command=var_states).grid(row=100,column=0, sticky=W)
    Label(master, text=" ").grid(row=101,column=0, sticky=W)
    Bttn2=Button(master, text='Close Window', command=CloseWindow)
    Bttn2.grid(row=102,column=0, sticky=W)

Bttn1 = Tkinter.Button(root, text ="Open New Window", command = NewWindow)
Bttn1.pack(side = TOP,padx=10,pady=5)

root.mainloop()

2 个答案:

答案 0 :(得分:1)

你试图用global拉扯的这个小黑客是我以前从未见过的东西 - 感谢原创性:-),但我不建议你继续沿着这条道路前进,因为要让它发挥作用是一件非常大的痛苦(如果它甚至可能),并且在长期维护中会更加痛苦。

永远不要害怕。 更好的方式!通常在这种情况下,我建议使用class。通过课程,您可以随身携带self所需的所有状态。这是您的代码的缩写版本:

class NewWindowFactory(object):
    def var_states(self):
        print 'FX_1', self.FX_1.get()
    def NewWindow(self):
        for i in xrange(1,NumPoints):
            label = Label(master, text="PT_%d: " % i)
            label.grid(row=i,column=0, sticky=W)
            setattr(self, 'FX_' + str(i), label)
        Button(master, text='Generate APDL Snippet', command=self.var_states).grid(row=100,column=0, sticky=W)

用法看起来像这样:

factory = NewWindowFactory()
Bttn1 = Tkinter.Button(root, text="Open New Window", command = factory.NewWindow)
Bttn1.pack(side = TOP,padx=10,pady=5)

另请注意,只要您有一系列变量Foo1Foo2Foo3 ...,您通常会想要开始考虑使用不同的数据结构(在这种情况下) ,您可能实际上需要一个复选框列表而不是10个复选框变量)。有关更深入的解释,请参阅Keep data out of your variable names,Ned Batchelder的优秀文章。

精明的读者可能会注意到将整个应用程序转换为类可以获得好处(您可以在__init__中设置初始UI)。我肯定会推荐这种方法,但我没有写出来让这个建议尽可能简单。

答案 1 :(得分:0)

我能够获得原始代码。我不得不在错误的位置进行全局声明......我还必须首先在主循环中定义变量。我知道有更优雅的方法可以做到这一点,但它确实有效。

    for i in xrange(1,100):
        exec('var1_' + str(i) + ' = Tkinter.IntVar()')
        exec('var2_' + str(i) + ' = Tkinter.IntVar()')
        exec('var3_' + str(i) + ' = Tkinter.IntVar()')
        exec('var4_' + str(i) + ' = Tkinter.IntVar()')
        exec('var5_' + str(i) + ' = Tkinter.IntVar()')
        exec('var6_' + str(i) + ' = Tkinter.IntVar()')

    def NewWindow():
        IPoints=int(Entry1.get())
        NumPoints=IPoints+1
        MaxComp=IPoints*6

        master = Tkinter.Toplevel()
        master.title("Select Unit Load Components")

        Label(master, text="Interface Points        ").grid(row=0,column=0, sticky=W)
        Label(master, text="FX").grid(row=0,column=1, sticky=W)
        Label(master, text="FY").grid(row=0,column=2, sticky=W)
        Label(master, text="FZ").grid(row=0,column=3, sticky=W)
        Label(master, text="MX").grid(row=0,column=4, sticky=W)
        Label(master, text="MY").grid(row=0,column=5, sticky=W)
        Label(master, text="MZ").grid(row=0,column=6, sticky=W)

        def var_states():
            exec('global var1_' + str(i)) in globals(), locals()
            exec('global var2_' + str(i)) in globals(), locals()
            exec('global var3_' + str(i)) in globals(), locals()
            exec('global var4_' + str(i)) in globals(), locals()
            exec('global var5_' + str(i)) in globals(), locals()
            exec('global var6_' + str(i)) in globals(), locals()

            print("FX: %d, FY: %d, FZ: %d, MX: %d, MY: %d, MZ: %d" % (var1_15.get(), var2_15.get(), var3_15.get(),var4_15.get(), var5_15.get(), var6_15.get()))

        for i in xrange(1,NumPoints):
            Label(master, text="PT_%d: " % i).grid(row=i,column=0, sticky=W)
            exec('Checkbutton(master, text="  ", variable=var1_' + str(i) + ').grid(row=i,column=1, sticky=W)') in globals(), locals()
            exec('Checkbutton(master, text="  ", variable=var2_' + str(i) + ').grid(row=i,column=2, sticky=W)') in globals(), locals()
            exec('Checkbutton(master, text="  ", variable=var3_' + str(i) + ').grid(row=i,column=3, sticky=W)') in globals(), locals()
            exec('Checkbutton(master, text="  ", variable=var4_' + str(i) + ').grid(row=i,column=4, sticky=W)') in globals(), locals()
            exec('Checkbutton(master, text="  ", variable=var5_' + str(i) + ').grid(row=i,column=5, sticky=W)') in globals(), locals()
            exec('Checkbutton(master, text="  ", variable=var6_' + str(i) + ').grid(row=i,column=6, sticky=W)') in globals(), locals()


        Button(master, text='Show', command=var_states).grid(row=100, sticky=W, pady=4)