python AttributeError:NoneType没有属性

时间:2017-12-29 10:18:01

标签: python tkinter attributeerror nonetype

在我的程序片段中,我创建了一个包含2个字段和3个按钮的python窗口。左侧的两个按钮应该执行一些操作,但会抛出错误:

Exception in Tkinter callback
Traceback (most recent call last):
  File "/usr/lib64/python3.4/tkinter/__init__.py", line 1538, in __call__
    return self.func(*args)
  File ".../GuiFile.py", line 11, in <lambda>
    self.F[2] = ButtonClass().make_button(stacked="left",buttontext= "Action button", buttoncommand = lambda: cf.mainButtons.doButtonAction1(self))
  File ".../ClassFile.py", line 11, in doButtonAction1
    print(gf.StartGui.F[0].textField.get("1.0","end-1c"))
AttributeError: 'NoneType' object has no attribute 'textField'

为什么dict项F [0](在GuiFile.py的第9行中创建)没有被识别为具有textField属性的Text()类(在GuiFile.py的第43行中定义)?

MainProgramFile.py

#!/usr/bin/env python3

import sys
import ClassFile
import GuiFile as gf

if __name__== '__main__': 
    gf.StartGui().mainloop()

GuiFile.py

import sys
from tkinter import *
import ClassFile as cf

class StartGui(Frame):
    F = {}
    def __init__(self,parent=None):
        Frame.__init__(self, parent)
        self.F[0] = FieldTextClass().make_field(labeltext="Label of field 1", fieldtext="veld 1", fieldheight=90) 
        self.F[1] = FieldTextClass().make_field(labeltext="Label of field 2", fieldtext="veld 2")
        self.F[2] = ButtonClass().make_button(stacked="left",buttontext= "Action button", buttoncommand = lambda: cf.mainButtons.doButtonAction1(self))
        self.F[3] = ButtonClass().make_button(stacked="left", buttontext= "Exchange button", buttoncommand = lambda: cf.mainButtons.doButtonSwitchValues(self))
        self.F[4] = ButtonClass().make_button(stacked="right",buttontext= "Quit button",buttoncommand = lambda: cf.mainButtons.doButtonQuit(self))
        self.pack(expand=True, fill=BOTH, anchor="nw", side=LEFT)
        #for i in range(self.F.__len__()): print(self.F[i].__class__,self.F[i].objectType)


class ButtonClass (Frame, Button):
    objectType = "button"

    def make_button(self, parent=None, stacked="horizontal", buttontext="Button", buttonwidth=120, buttonheight=32, buttoncommand=""):
        self.buttonwidth=buttonwidth
        self.buttonheight=buttonheight
        self.buttontext=buttontext
        self.buttoncommand=buttoncommand

        if stacked=="vertical": 
            BUTTONSTACK = TOP 
        elif stacked=="right": 
            BUTTONSTACK = RIGHT 
        elif stacked=="horizontal" or stacked=="left": 
            BUTTONSTACK = LEFT
        else:
            BUTTONSTACK = LEFT 

        self.top = Frame(parent, height=self.buttonheight, width=self.buttonwidth)
        self.top.pack_propagate(False)
        self.top.pack(side=BUTTONSTACK)       
        button = Button(self.top, text=self.buttontext, command=self.buttoncommand,height=self.buttonheight, width=self.buttonwidth)
        button.pack(fill=BOTH)

class FieldTextClass(Frame,Text,Label):
    textField = None
    objectType = "inputField" 

    def make_field(self, parent=None,  labeltext="Empty", fieldtext="Empty", fieldwidth=600, fieldheight=20, labelwidth=120, labelheight=20):
        self.fieldheight=fieldheight
        self.fieldwidth=fieldwidth
        self.fieldtext=fieldtext
        self.labeltext=labeltext
        self.labelheight=labelheight
        self.labelwidth=labelwidth
        self.top = Frame(parent)

        #create the label, whith the text shifted left/top in a separate Frame
        labelFrame = Frame(self.top, height = self.labelheight,width=self.labelwidth)
        label = Label(labelFrame, text=self.labeltext, fg="black", anchor="nw") 
        label.pack(expand=True, fill=BOTH, anchor="nw", side=LEFT)
        labelFrame.pack_propagate(False) 
        labelFrame.pack(side=LEFT,  anchor="nw")

        #create the text field, packed in a separate Frame
        fieldFrame = Frame(self.top, height = self.fieldheight,width=self.fieldwidth)
        self.textField = Text(fieldFrame, fg="black",bg="white")
        self.textField.insert(INSERT,self.fieldtext)
        self.textField.pack(expand=True, fill=BOTH, side=LEFT)
        fieldFrame.pack_propagate(False)
        fieldFrame.pack(side=LEFT)

        self.top.pack(side=TOP)

ClassFile.py

import sys 
from tkinter import *
import GuiFile as gf

class mainButtons():
    def doButtonQuit(self):
        print("Quitting test via ClassFile")
        self.quit()

    def doButtonAction1(self):
        print(gf.StartGui.F[0].textField.get("1.0","end-1c"))
        print(gf.StartGui.F[1].textField.get("1.0","end-1c"))
        gf.StartGui.F[0].textField.delete("1.0","end") 
        gf.StartGui.F[0].textField.insert(INSERT, "New text")

    def doButtonSwitchValues(self):
        tmp0=gf.StartGui.F[0].textField.get("1.0","end-1c")
        tmp1=gf.StartGui.F[1].textField.get("1.0","end-1c")
        gf.StartGui.F[0].textField.delete("1.0","end") 
        gf.StartGui.F[0].textField.insert(INSERT, tmp1)
        gf.StartGui.F[1].textField.delete("1.0","end") 
        gf.StartGui.F[1].textField.insert(INSERT, tmp0)

1 个答案:

答案 0 :(得分:1)

执行ButtonClass().make_button()(或FieldTextClass.make_field())时,python将返回函数的值,不是类的实例。该函数返回None,因此字典元素为None

您使用自定义类的方式非常奇怪。而不是创建特殊函数,将该代码放在__init__中,并像使用任何其他类一样使用该类。

例如:

class ButtonClass (Frame):
    def __init__(self, parent=None, stacked="horizontal",
                 buttontext="Button", buttonwidth=120, buttonheight=32,
                 buttoncommand=""):
        Frame.__init__(self, parent)
        self.buttonwidth=buttonwidth
        ...

...
self.F[2] = ButtonClass(stacked="left",buttontext= "Action button", buttoncommand = lambda: cf.mainButtons.doButtonAction1(self))

注意:这样做时,您不必在__init__内创建单独的框架(即:self.top),因为self本身已经是框架。