开宗明义,最近几天在学习tkinter,开发界面,中间参考过很多代码,在借鉴别人代码时,遇到了这样的错误:
_tkinter.TclError: cannot use geometry manager pack inside . which already has slaves managed by grid
这个错误的意思是:不能在内部使用pack进行布局,因为这个‘子控件’已经通过grid管理了
这是一个比较常见的错误,如果混用grid和pack进行布局的话就会报错,
在我的代码中出现的错误不是这个提示的错误,毕竟提示就是提示,不是完全准确。
在我的代码中使用到了Frame,这是一个容器,可以用来承载放置其他GUI元素:
在构建tkinter界面过程中,首先需要实例化Tk
root=tkinter.TK()
在我的代码中也用到了Frame
在构建一个Frame时需要引入其父控件root,通过:
class TestFrame(Frame): # 继承Frame类
def __init__(self, master=None):
Frame.__init__(self, master)
self.root = master # 定义内部变量root
self.itemName = StringVar()
self.createPage()
其中的master在实例化时传入的参数即为以上定义的主窗口root
然后我在该Frame中生成了一个Label控件
def createPage(self):
#Label(self, text='4G测试').pack()
#如果self改成self.root就不可以,因为label是frame的内容,不是root的内容
netLabel = Label(self.root, text='显示框', font=('Arial', 12)).grid(row=0, column=0, padx=2, pady=2, sticky='w')
self.shellSpace = Text(self, wrap=WORD, width=70, height=15)
此时就报出了文章开头所说的错误:
因为这个Label是在Frame下建的,是该Frame的子控件,不是root的子控件,需要使用self,这个self指的是这个继承了Frame的类的实例。
然后就涉及到一个写法失误造成的错误:
以下贴出了整个类:
class TcpFrame(Frame): # 继承Frame类
def __init__(self, master=None):
Frame.__init__(self, master)
self.root = master # 定义内部变量root
self.createPage()
def createPage(self):
frameConfig = Frame(self)
frameConfig.grid(row=1, column=0)
labelConfig = Label(frameConfig, text='网络配置', font=('Arial', 12), bg='green').grid(row=1, column=1, padx=2,pady=2, sticky='w')
labelProtocol = Label(frameConfig, text='(1)协议类型', font=('Arial', 12), bg='red').grid(row=2, column=1, padx=2,pady=2, sticky='w')
protocol = StringVar(value='TCP')
entryConfig = Entry(frameConfig, textvariable=protocol).grid(row=3, column=1, padx=2, pady=2, sticky='w')
labelAddress = Label(frameConfig, text='(2)IP地址', font=('Arial', 12), bg='red').grid(row=4, column=1, padx=2,pady=2, sticky='w')
ip = StringVar(value='192.168.1.100')
entryAddress = Entry(frameConfig, textvariable=ip).grid(row=5, column=1, padx=2, pady=2, sticky='w')
labelPort = Label(frameConfig, text='(3)端口号', font=('Arial', 12), bg='red').grid(row=6, column=1, padx=2,pady=2, sticky='w')
port = StringVar(value=8080)
entryPort = Entry(frameConfig, textvariable=port).grid(row=7, column=1, padx=2, pady=2, sticky='w')
buttonOpen = Button(frameConfig, text='打开', command=self.start).grid(row=8, column=1, padx=2, pady=2, sticky='e')
spaceBlank = Text(frameConfig, wrap=WORD, width=20, height=15).grid(row=9, column=1, padx=2, pady=2, sticky='w')
frameData = Frame(self)
frameData.grid(row=1, column=1)
labelLog = Label(frameData, text='数据日志', font=('Arial', 12)).grid(row=1, column=1, padx=2, pady=2, sticky='w')
logText = Text(frameData, wrap=WORD, width=60, height=20).grid(row=2, column=1, padx=2, pady=2, sticky='w')
labelTran = Label(frameData, text='发送数据', font=('Arial', 12)).grid(row=3, column=1, padx=2, pady=2, sticky='w')
tranText = Text(frameData, wrap=WORD, width=60, height=5).grid(row=4, column=1, padx=2, pady=2, sticky='w')
def start(self):
pass
class NetworkFrame(Frame): # 继承Frame类
def __init__(self, master=None):
Frame.__init__(self, master)
self.root = master # 定义内部变量root
self.createPage()
def createPage(self):
#Label(self, text='4G测试').pack()
#如果self改成self.root就不可以,因为label是frame的内容,不是root的内容
netLabel = Label(self, text='显示框', font=('Arial', 12)).grid(row=0, column=0, padx=2, pady=2, sticky='w')
self.shellSpace = Text(self, wrap=WORD, width=70, height=15)
self.shellSpace.grid(row=1, column=0, padx=2, pady=2, sticky='w')
sendButton = Button(self, text='发送', font=('Arial', 12), command=self.printCommand).grid(row=2, column=0, padx=2,pady=2, sticky='e')
shellCommand = StringVar()
shellCommand.set(('ping www.baidu.com', '/my-demo/gcc-linaro-5.3-arm/quectel-CM &'))
self.shellList = Listbox(self, listvariable=shellCommand, width=70, height=15)
self.shellList.grid(row=3, column=0, padx=2, pady=2, sticky='w')
def printCommand(self):
print(type(self.shellList))
value = self.shellList.get(self.shellList.curselection())
self.shellSpace.insert(END, value)
self.shellSpace.insert(END, '\n')
以上代码为正确写法,此时的‘self.shellList’的类型是
<class ‘tkinter.Listbox’>
<class ‘tkinter.Listbox’>
然而当时为了图方便,也是对知识一知半解的,就图省事,将
self.shellList = Listbox(self, listvariable=shellCommand, width=70, height=15)
self.shellList.grid(row=3, column=0, padx=2, pady=2, sticky='w')
写成了
self.shellList = Listbox(self, listvariable=shellCommand, width=70, height=15).grid(row=3, column=0, padx=2, pady=2, sticky='w')
这样在布局时是没有问题的,但是这样操作并未把 Listbox(self, listvariable=shellCommand, width=70, height=15)类赋值给self.shellList,所以在方法:printCommand中调用的时候就会报错:
value = self.shellList.get(self.shellList.curselection())
AttributeError: 'NoneType' object has no attribute 'get'
此时打印self.shellList的类型也会是NoneType,
完毕。