如何为受.get()影响的tkinter Entry组件应用grid网格布局
'str' object has no attribute 'grid' 是因为你对Entry组件的调用逻辑完全错位:
inp = Entry(root).get()
这行代码的执行顺序是:创建Entry组件→立刻调用组件的get()方法读取当前文本值(此时窗口还未渲染,输入框是空的,返回空字符串"")→把这个空字符串赋值给inp。也就是说inp根本不是Entry组件,是个普通字符串,自然没有.grid()布局方法,调用就直接报错。
不解决这些的话,就算把grid的报错消了,程序也跑不通:
- 取输入内容的时机完全错误:不能在创建Entry的时候就提前把值读出来存着,这时候用户根本还没输入任何内容,要等用户点提交按钮触发回调时,再实时读取输入框的内容
- 全局定义的
truth是普通Python字符串,不能直接传给Label的textvariable参数——这个参数要求必须传入tkinter自带的可变变量对象(比如StringVar) - 原来的回调函数里给
us、uss、truth赋值的话,会被Python判定为函数内部的局部变量,外部根本读取不到赋值后的结果
拆分Entry的创建和取值操作:先单独保存Entry组件对象,给组件本身调用
.grid()做布局,不要在创建阶段就调用.get()
替换原来的错误写法:# 错误写法:创建即取值,把字符串赋值给inp inp = Entry(root).get() inp.grid(row = 3, column = 5)改成:
# 正确写法:先存组件本身 inp_entry = Entry(root) # 给组件本身调用布局方法 inp_entry.grid(row = 3, column = 5)替换普通字符串为tkinter绑定变量:把原来用来做结果展示的
truth变量换成StringVar类型,才能和Label的textvariable参数适配
替换原来的全局变量定义:# 错误:普通字符串无法绑定界面 truth = "" us = "" uss = ""改成:
# 正确:tkinter专用的可变字符串变量 truth = StringVar()修改回调函数的取值逻辑:在按钮触发时,再通过之前保存的Entry组件对象调用
.get()实时读入用户输入,处理完结果后给绑定的StringVar赋值,界面会自动同步更新
替换原来的callback函数:# 原来的callback逻辑 def callback(): us = inp[:inp.index("@")] uss = inp[inp.index("@")+1:] truth = us, " is username, and ", uss, "is domain" print(truth)改成:
def callback(): # 实时读取输入框当前的内容 inp_content = inp_entry.get() # 拆分邮箱的逻辑 at_pos = inp_content.index("@") uname = inp_content[:at_pos] domain = inp_content[at_pos+1:] # 给绑定到Label的变量赋值,界面会自动刷新 truth.set(f"{uname} is username, and {domain} is domain") print(truth.get())
import tkinter as tk from tkinter import * root = Tk() # 初始化界面绑定的可变变量 truth = StringVar() s = Label(root, text = ".") s.grid(row = 1, column = 1) wel = Label(root, text = "whats your email") wel.grid(row = 1, column = 5) # 正确初始化Entry组件,单独做布局 inp_entry = Entry(root) inp_entry.grid(row = 3, column = 5) def callback(): inp_content = inp_entry.get() at_pos = inp_content.index("@") uname = inp_content[:at_pos] domain = inp_content[at_pos+1:] truth.set(f"{uname} is username, and {domain} is domain") print(truth.get()) sub = Button(root, text = "submit", command = callback) sub.grid(row = 5, column = 5) # 正确绑定StringVar到Label final = Label(root, textvariable = truth) final.grid(row = 5, column = 6) root.mainloop()
注意:只要记住一个原则——
.grid()、.pack()、.place()这些布局方法,永远是组件对象本身才能调用的,只要调用这些方法的变量不是你创建的那个组件,就一定会报'xxx' object has no attribute 'grid'的错。而.get()方法是组件的取值方法,调用之后返回的是字符串值,不是组件本身,绝对不能把这个返回值存下来之后再当组件用。
内容的提问来源于stack exchange,提问作者Evan Hall

