2017-12-29 20 views
0

내 프로그램 단편에서 2 개의 필드와 3 개의 버튼이있는 파이썬 창을 만듭니다. 왼쪽 두 개의 버튼은 몇 가지 작업을 수행해야하지만 대신 오류가 발생합니다 :python AttributeError : NoneType에는 속성이 없습니다.

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' 

왜 딕셔너리 항목 F [0] (GuiFile.py 라인 9에서 생성) 텍스트로 인식되지 않는() 클래스는 속성입니다 textField (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

여기에는 많은 문제가 있습니다. 클래스와 인스턴스의 차이점, 클래스 속성과 인스턴스 속성의 차이점을 이해해야합니다. –

답변

1

당신이 ButtonClass().make_button() (또는 FieldTextClass.make_field()), 파이썬은의 값을 반환 할 함수, 아니요 the instan 클래스의 ce. 이 함수는 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)) 

참고 : self 이미 자체 프레임이기 때문에, (self.top 예) 이런 식으로 일을 할 때, 당신은 __init__ 내부에 별도의 프레임을 만들 필요가 없습니다 .

+0

좋습니다. 그것은 작동합니다. 그러나 Frame .__ init __ (부모)를 사용하면이 줄에 오류가 발생합니다. AttributeError : 'NoneType'객체에 'widgetName'속성이 없습니다. 내가 뭘 놓치고 있니? – Mike

+0

@Mike : 죄송합니다. 매개 변수를'Frame .__ init__'에 두지 않았습니다. 답변을 업데이트했습니다. –

+0

Thx Bryan, 지금은 정상적으로 작동합니다! – Mike