Python tkinter/ctkinter无法从输入控件取值创建Student对象
问题:Tkinter/CustomTkinter无法获取控件输入值,创建Student实例失败
我用Tkinter和CustomTkinter开发学生信息录入GUI,想获取CTkEntry、DateEntry等控件的输入值来创建Student类实例,但点击「Create Student Record」按钮后,获取的不是输入值而是控件对象标识,导致Student对象无法正确填充数据。
Student类代码
class Student: def __init__(self, firstName=None, lastName=None, dateOfBirth=None, age=None, schoolName=None, schoolId=None, addressLine=None, city=None, zip=None, language=None): self.firstName = firstName self.lastName = lastName self.dateOfBirth = dateOfBirth self.age = age self.schoolName = schoolName self.schoolId = schoolId self.addressLine = addressLine self.city = city self.zip = zip self.language = language
原GUI代码
import sys import tkinter import customtkinter as ctk import self from tkcalendar import * from datetime import date, datetime from Student import * # Theme set-up ctk.set_appearance_mode("dark") ctk.set_default_color_theme("dark-blue") # GUI set-up mainMenu = ctk.CTk() mainMenu.title("GUI Application") mainMenu.geometry("800x500") # Frame set-up mainMenuFrame = ctk.CTkFrame(master=mainMenu) mainMenuFrame.pack(pady=20, padx=60, fill="both", expand=True) ageSelection = tkinter.StringVar() #Functions def exitProgram(): sys.exit() def getAge(today, dob, student): print(today) print(dob) dob_result = str(dob) dob_data = dob_result.split("-") year = int(dob_data[0]) month = int(dob_data[1]) day = int(dob_data[2]) print(year) print(month) print(day) age = (today - date(year, month, day)).days age = age / 365 print(age) age = round(age) ageSelection = round(age) print(round(age)) def createStudentRecord(firstName, lastName, dob, schoolName, schoolId, addressLine, city, zip, language): s1 = Student(firstName, lastName,dob,schoolName,schoolId,addressLine, city, zip, language) print(firstName) print(lastName) print(dob) print(schoolId) print(addressLine) print(city) print(zip) print(language) def loadStudentInfoView(): # Remove main menu frame mainMenuFrame.pack_forget() studentInfoFrame = ctk.CTkFrame(master=mainMenu) studentInfoFrame.grid(row=0, column=0) # Student Info set-up #First & Last Name firstNameLabel = ctk.CTkLabel(master=studentInfoFrame, text="First Name", font=('Calibri',20)) firstNameLabel.grid(row=0, column=0) firstNameText = ctk.CTkEntry(master=studentInfoFrame, height=30, width=150) firstNameText.grid(row=1, column=0, padx=20) firstName = str(firstNameText.get()) lastNameLabel = ctk.CTkLabel(master=studentInfoFrame, text="Last Name", font=('Calibri', 20)) lastNameLabel.grid(row=0, column=1) lastNameText = ctk.CTkEntry(master=studentInfoFrame, height=30, width=150) lastNameText.grid(row=1, column=1, padx=20) # Birth date (Calendar), automatically calculate age #DOB drop down dobLabel = ctk.CTkLabel(master=studentInfoFrame, text="DOB", font=('Calibri', 20)) dobLabel.grid(row=0, column=2) calPicker = DateEntry(studentInfoFrame, selectmode="day", year=2014, month=2, day=7, date_pattern="yyyy-mm-dd") calPicker.grid(row=1, column=2) #School Details schoolNameLabel = ctk.CTkLabel(master=studentInfoFrame, text="School Name", font=('Calibri', 20)) schoolNameLabel.grid(row=2, column=0) schoolNameText = ctk.CTkEntry(master=studentInfoFrame, height=30, width=150) schoolNameText.grid(row=3, column=0, padx=20) #School ID schoolIdLabel = ctk.CTkLabel(master=studentInfoFrame, text="School ID", font=('Calibri', 20)) schoolIdLabel.grid(row=2, column=1) schoolIdText = ctk.CTkEntry(master=studentInfoFrame, height=30, width=70) schoolIdText.grid(row=3, column=1, padx=20) #Address Line 1 & 2, City, State, Zip addressLineLabel = ctk.CTkLabel(master=studentInfoFrame, text="Address Line", font=('Calibri', 20)) addressLineLabel.grid(row=5, column=0) addressLineText = ctk.CTkEntry(master=studentInfoFrame, height=30, width=300) addressLineText.grid(row=6, column=0, padx=20) cityLabel = ctk.CTkLabel(master=studentInfoFrame, text="City", font=('Calibri', 20)) cityLabel.grid(row=5, column=1) cityText = ctk.CTkEntry(master=studentInfoFrame, height=30, width=120) cityText.grid(row=6, column=1, padx=20) stateLabel = ctk.CTkLabel(master=studentInfoFrame, text="State (dropdown)", font=('Calibri', 20)) stateLabel.grid(row=5, column=2) stateText = ctk.CTkEntry(master=studentInfoFrame, height=30, width=50) stateText.grid(row=6, column=2, padx=20) zipLabel = ctk.CTkLabel(master=studentInfoFrame, text="Zip Code", font=('Calibri', 20)) zipLabel.grid(row=5, column=3) zipText = ctk.CTkEntry(master=studentInfoFrame, height=30, width=50) zipText.grid(row=6, column=3, padx=20) #Language # Create Record Button createRecordButton = ctk.CTkButton(master=studentInfoFrame, text="Create Student Record", command=lambda : createStudentRecord(firstName, lastNameText, calPicker, schoolNameText, schoolIdText, addressLineText, cityText, zipText, language=None)) createRecordButton.grid(row=8, column=1, pady=80) # Main Menu Layout # Title Label title = ctk.CTkLabel(master = mainMenuFrame, text="LSSP Helper", font=('Arial', 32)) title.pack(pady=12, padx=10) # Text Label title2 = ctk.CTkLabel(master = mainMenuFrame, text="Can you") title2.pack(pady=12, padx=10) # Text Label title3 = ctk.CTkLabel(master = mainMenuFrame, text="please") title3.pack(pady=12, padx=10) # Text Label title4 = ctk.CTkLabel(master = mainMenuFrame, text="HELLLLLLLLLLLLLLLLLLLLLLLLLLLLLP!?!?!?!?!") title4.pack(pady=12, padx=10) # Button 1 button1 = ctk.CTkButton(master = mainMenuFrame, text="Create New Student Record", command=loadStudentInfoView) button1.pack(pady=12, padx=10) # Button 2 button2 = ctk.CTkButton(master = mainMenuFrame, text="Resume Student Record") button2.pack(pady=12, padx=10) # Button 3 button3 = ctk.CTkButton(master = mainMenuFrame, text="Observation Form") button3.pack(pady=12, padx=10) # Exit Button exitButton = ctk.CTkButton(master = mainMenuFrame, text="Exit", command=exitProgram) exitButton.pack(pady=12, padx=10) mainMenu.mainloop()
原输出结果
# empty value as I tried to use text.get() method .!ctkframe2.!ctkentry2 .!ctkframe2.!dateentry .!ctkframe2.!ctkentry4 .!ctkframe2.!ctkentry5 .!ctkframe2.!ctkentry6 .!ctkframe2.!ctkentry8 None
问题原因
- 提前获取值导致空内容:初始化
firstNameText后立即调用.get(),此时控件还没有用户输入,得到的是空值。 - 传递控件对象而非输入值:按钮命令中直接传递
lastNameText、calPicker等控件对象,而非调用.get()获取当前输入值,打印时自然输出控件的身份标识。 - 参数顺序不匹配:
createStudentRecord函数传递的参数顺序和Student类的__init__方法不匹配,导致数据填充错位。
修复方案
- 删除提前获取值的代码:移除
firstName = str(firstNameText.get()),改为在按钮点击时获取值。 - 按钮点击时获取实时值:在按钮的
command中,对每个输入控件调用.get()(DateEntry用.get_date()获取日期对象)。 - 修正参数顺序:确保传递给Student类的参数和
__init__方法的参数顺序一致。 - 优化年龄计算:将年龄计算逻辑改为返回值形式,避免局部变量无法更新的问题。
修改后的完整GUI代码
import sys import tkinter import customtkinter as ctk from tkcalendar import * from datetime import date, datetime from Student import * # Theme set-up ctk.set_appearance_mode("dark") ctk.set_default_color_theme("dark-blue") # GUI set-up mainMenu = ctk.CTk() mainMenu.title("GUI Application") mainMenu.geometry("800x500") # Frame set-up mainMenuFrame = ctk.CTkFrame(master=mainMenu) mainMenuFrame.pack(pady=20, padx=60, fill="both", expand=True) #Functions def exitProgram(): sys.exit() def calculateAge(dob): # 更准确的年龄计算方式 today = date.today() age = today.year - dob.year - ((today.month, today.day) < (dob.month, dob.day)) return age def createStudentRecord(firstName, lastName, dob, schoolName, schoolId, addressLine, city, zip_code, language): age = calculateAge(dob) s1 = Student(firstName, lastName, dob, age, schoolName, schoolId, addressLine, city, zip_code, language) # 打印验证数据 print("学生信息:") print(f"FirstName: {firstName}") print(f"LastName: {lastName}") print(f"DOB: {dob}") print(f"Age: {age}") print(f"SchoolName: {schoolName}") print(f"SchoolId: {schoolId}") print(f"AddressLine: {addressLine}") print(f"City: {city}") print(f"Zip: {zip_code}") print(f"Language: {language}") return s1 def loadStudentInfoView(): # Remove main menu frame mainMenuFrame.pack_forget() studentInfoFrame = ctk.CTkFrame(master=mainMenu) studentInfoFrame.grid(row=0, column=0) #First & Last Name firstNameLabel = ctk.CTkLabel(master=studentInfoFrame, text="First Name", font=('Calibri',20)) firstNameLabel.grid(row=0, column=0) firstNameText = ctk.CTkEntry(master=studentInfoFrame, height=30, width=150) firstNameText.grid(row=1, column=0, padx=20) lastNameLabel = ctk.CTkLabel(master=studentInfoFrame, text="Last Name", font=('Calibri', 20)) lastNameLabel.grid(row=0, column=1) lastNameText = ctk.CTkEntry(master=studentInfoFrame, height=30, width=150) lastNameText.grid(row=1, column=1, padx=20) # Birth date (Calendar) dobLabel = ctk.CTkLabel(master=studentInfoFrame, text="DOB", font=('Calibri', 20)) dobLabel.grid(row=0, column=2) calPicker = DateEntry(studentInfoFrame, selectmode="day", year=2014, month=2, day=7, date_pattern="yyyy-mm-dd") calPicker.grid(row=1, column=2) #School Details schoolNameLabel = ctk.CTkLabel(master=studentInfoFrame, text="School Name", font=('Calibri', 20)) schoolNameLabel.grid(row=2, column=0) schoolNameText = ctk.CTkEntry(master=studentInfoFrame, height=30, width=150) schoolNameText.grid(row=3, column=0, padx=20) #School ID schoolIdLabel = ctk.CTkLabel(master=studentInfoFrame, text="School ID", font=('Calibri', 20)) schoolIdLabel.grid(row=2, column=1) schoolIdText = ctk.CTkEntry(master=studentInfoFrame, height=30, width=70) schoolIdText.grid(row=3, column=1, padx=20) #Language languageLabel = ctk.CTkLabel(master=studentInfoFrame, text="Language", font=('Calibri', 20)) languageLabel.grid(row=2, column=2) languageText = ctk.CTkEntry(master=studentInfoFrame, height=30, width=100) languageText.grid(row=3, column=2, padx=20) #Address Line 1 & 2, City, State, Zip addressLineLabel = ctk.CTkLabel(master=studentInfoFrame, text="Address Line", font=('Calibri', 20)) addressLineLabel.grid(row=5, column=0) addressLineText = ctk.CTkEntry(master=studentInfoFrame, height=30, width=300) addressLineText.grid(row=6, column=0, padx=20) cityLabel = ctk.CTkLabel(master=studentInfoFrame, text="City", font=('Calibri', 20)) cityLabel.grid(row=5, column=1) cityText = ctk.CTkEntry(master=studentInfoFrame, height=30, width=120) cityText.grid(row=6, column=1, padx=20) stateLabel = ctk.CTkLabel(master=studentInfoFrame, text="State (dropdown)", font=('Calibri', 20)) stateLabel.grid(row=5, column=2) stateText = ctk.CTkEntry(master=studentInfoFrame, height=30, width=50) stateText.grid(row=6, column=2, padx=20) zipLabel = ctk.CTkLabel(master=studentInfoFrame, text="Zip Code", font=('Calibri', 20)) zipLabel.grid(row=5, column=3) zipText = ctk.CTkEntry(master=studentInfoFrame, height=30, width=50) zipText.grid(row=6, column=3, padx=20) # Create Record Button createRecordButton = ctk.CTkButton( master=studentInfoFrame, text="Create Student Record", command=lambda : createStudentRecord( firstNameText.get(), lastNameText.get(), calPicker.get_date(), schoolNameText.get(), schoolIdText.get(), addressLineText.get(), cityText.get(), zipText.get(), languageText.get() ) ) createRecordButton.grid(row=8, column=1, pady=80) # Main Menu Layout title = ctk.CTkLabel(master = mainMenuFrame,
相关产品推荐
相关产品推荐

