温度转换器 GUI UnboundLocalError/AttributeError 问题
Temperature Converter GUI UnboundLocalError/AttributeError issues
我使用 Tkinter 在 Python 中做了一个相对简单的温度应用程序。
我设法让大部分部分工作,但实际处理获取答案的部分给我带来了麻烦。我认为这与我决定如何从 "x temperature unit" 转换为 "y temperature unit" 的方式有关,通过使用 if/elif 将我的程序定向到适当的转换函数。在我目前的尝试中,我倾向于得到 UnboundLocalError,据我所知,这意味着我在为变量赋值之前以某种方式尝试使用变量,在本例中为 converted_temp。但是,我不确定如何解决这个问题,因为我已经尝试将它分配给某个占位符,但最终没有输出任何内容。有什么方法可以通过我编写程序的方式来解决这个错误吗?
这是我写的:
import tkinter
import tkinter.messagebox
class TempConverterGUI:
def __init__(self):
# create main window, and set a custom window title
self.main_window = tkinter.Tk()
self.main_window.wm_title("Convert Temperatures")
# creates a top frame with label to give a title for the application
self.top_frame = tkinter.Frame(self.main_window)
self.title_label = tkinter.Label(self.top_frame, text= 'Temperature Converter')
self.title_label.pack(side='top')
self.top_frame.pack()
# create middle frame to hold main program components
self.mid_frame = tkinter.Frame(self.main_window)
#############################################################################################
# create frame to hold the unit lists
self.lists_frame = tkinter.Frame(self.mid_frame)
##########################
# create frame to hold original unit to convert from list components
self.from_list_frame = tkinter.Frame(self.lists_frame)
self.from_label = tkinter.Label(self.from_list_frame, text='Convert from:')
self.from_label.pack(side='top')
# creates radio button lists to allow user to decide which units to convert from
self.from_radio = tkinter.StringVar()
self.fb1 = tkinter.Radiobutton(self.from_list_frame, text= 'Fahrenheit', variable= self.from_radio, value= 'FAHRENHEIT')
self.fb2 = tkinter.Radiobutton(self.from_list_frame, text= 'Celsius', variable= self.from_radio, value= 'CELSIUS')
self.fb3 = tkinter.Radiobutton(self.from_list_frame, text= 'Kelvin', variable= self.from_radio, value= 'KELVIN')
self.fb1.pack()
self.fb2.pack()
self.fb3.pack()
########################
# create frame to hold list components to decide which unit to convert to
self.to_list_frame = tkinter.Frame(self.lists_frame)
self.to_label = tkinter.Label(self.to_list_frame, text='Convert to:')
self.to_label.pack(side='top')
# creates radio button lists to allow user to decide which units to convert to
self.to_radio = tkinter.StringVar()
self.tb1 = tkinter.Radiobutton(self.to_list_frame, text= 'Fahrenheit', variable= self.to_radio, value= 'FAHRENHEIT')
self.tb2 = tkinter.Radiobutton(self.to_list_frame, text= 'Celsius', variable= self.to_radio, value= 'CELSIUS')
self.tb3 = tkinter.Radiobutton(self.to_list_frame, text= 'Kelvin', variable= self.to_radio, value= 'KELVIN')
self.tb1.pack()
self.tb2.pack()
self.tb3.pack()
#############################################################################################
#Create frame to hold textbox input
self.entry_frame = tkinter.Frame(self.mid_frame)
self.temp_prompt_label = tkinter.Label(self.entry_frame, text='Enter a temperature:')
self.temp_entry = tkinter.Entry(self.entry_frame, width=10)
self.temp_prompt_label.pack(side='top')
self.temp_entry.pack(side='top')
############################################################################################################################################################################
############################################################################################################################################################################
# create frame to hold convert button components and answer label components
self.convert_frame = tkinter.Frame(self.mid_frame)
# label to display answer
self.answer = tkinter.StringVar()
self.answer_label = tkinter.Label(self.convert_frame, textvariable=self.answer)
self.answer_label.pack(side='bottom')
# convert button for actual conversion
self.convert_button = tkinter.Button(self.convert_frame, text='Convert', command=self.do_convert)##################################
self.convert_button.pack(side='top')
#####################################################
##Consider creating either error box or popup
# create a bottom frame for miscellaneous buttons
self.bottom_frame = tkinter.Frame(self.main_window)
# instructions button that makes popup box telling how to use app
self.instructions_button = tkinter.Button(self.bottom_frame, text='Instructions', command=self.instructions)
self.instructions_button.pack(side='left')
# quit button that quits app
self.quit_button = tkinter.Button(self.bottom_frame, text='Quit', command=self.main_window.destroy)
self.quit_button.pack(side='right')
##############################################
# packup the frames
self.from_list_frame.pack(side='left')
self.to_list_frame.pack(side='left')
self.lists_frame.pack(side='left')
self.convert_frame.pack(side='left')
self.entry_frame.pack(side='right')
self.mid_frame.pack(side ='top')
self.bottom_frame.pack(side='bottom')
# enter main loop
tkinter.mainloop()
#print(self.from_radio.get(), self.to_radio.get(), self.temp_entry)####
def instructions(self):
tkinter.messagebox.showinfo('Instructions', 'This application allows the user to convert a temperature between Fahrenheit, Celsius, and Kelvin. '\
'A user may select a unit to convert from, a unit to convert to, and what temperature they would like to convert. '\
'Using this information they may convert the entered temperature into the desired unit.')
#########################################
# called by the convert button, uses from_radio selection to decide who to convert into(which conversion function to call)
def do_convert(self):
#self.converted_temp = None
if self.from_radio == 'FAHRENHEIT':
converted_temp = f_convert()
elif self.from_radio == 'CELSIUS':
converted_temp = c_convert()
elif self.from_radio == 'KELVIN':
converted_temp = k_convert()
# sets self.answer(and so answer label) to value returned into converted_temp
self.answer.set(converted_temp)
###########################################################
# series of functions for each individual unit to hold conversion formulas for each possible case
# using self.to_radio selection to decide which conversion to perform, then returns the resulting temperature
# for use in do_convert
def f_convert(self):
if self.to_radio == 'FAHRENHEIT':
new_temp = self.temp_entry
elif self.to_radio == 'CELSIUS':
new_temp = (self.temp_entry - 32)*(5/9.0)
elif self.to_radio == 'KELVIN':
new_temp = (self.temp_entry + 459.67)*(5/9.0)
return new_temp
def c_convert(self):
if self.to_radio == 'FAHRENHEIT':
new_temp = (9/5.0)*self.temp_entry + 32.0
elif self.to_radio == 'CELSIUS':
new_temp = self.temp_entry
elif self.to_radio == 'KELVIN':
new_temp = self.temp_entry + 273.15
return new_temp
def k_convert(self):
if self.to_radio == 'FAHRENHEIT':
new_temp = (9/5.0)*(self.temp_entry-273.15) + 32
elif self.to_radio == 'CELSIUS':
new_temp = self.temp_entry - 273.15
elif self.to_radio == 'KELVIN':
new_temp = self.temp_entry
return new_temp
conv_gui = TempConverterGUI()
您收到错误是因为您忘记使用类型为 tkinter.StringVar
的 self.from_radio
对象的 get()
方法来检索其当前值。因为 if
语句中的 none 为真,并且局部变量 converted_temp
未定义,因为它在被引用之前从未被赋值。
下面是一个修改版本,显示了一种避免该问题的方法:
# called by the convert_button, uses from_radio selection to
# decide what to convert into (i.e. which conversion function to call)
def do_convert(self):
converted_temp = '' # default if somehow there's no match
from_radio = self.from_radio.get()
if from_radio == 'FAHRENHEIT':
converted_temp = f_convert()
elif from_radio == 'CELSIUS':
converted_temp = c_convert()
elif from_radio == 'KELVIN':
converted_temp = k_convert()
self.answer.set(converted_temp)
代码可以重构——有很多重复——但我只提一下实际上导致错误的两件事:
- 从未调用
self.from_radio
的 .get()
方法。
- 在调用 class 方法(例如
f_convert()
、c_convert()
等)之前缺少 self
s
示例:
def do_convert(self):
if self.from_radio == 'FAHRENHEIT': <---- missing ".get()" after "self.from_radio"
converted_temp = f_convert() <---- missing "self" before f_convert()
elif self.from_radio == 'CELSIUS':
converted_temp = c_convert()
elif self.from_radio == 'KELVIN':
converted_temp = k_convert()
self.answer.set(converted_temp)
您可以将其重新写成这样:
def do_convert(self):
radio_value = self.from_radio.get()
if radio_value == 'FAHRENHEIT':
converted_temp = self.f_convert()
elif radio_value == 'CELSIUS':
converted_temp = self.c_convert()
elif radio_value == 'KELVIN':
converted_temp = self.k_convert()
self.answer.set(converted_temp)
我使用 Tkinter 在 Python 中做了一个相对简单的温度应用程序。
我设法让大部分部分工作,但实际处理获取答案的部分给我带来了麻烦。我认为这与我决定如何从 "x temperature unit" 转换为 "y temperature unit" 的方式有关,通过使用 if/elif 将我的程序定向到适当的转换函数。在我目前的尝试中,我倾向于得到 UnboundLocalError,据我所知,这意味着我在为变量赋值之前以某种方式尝试使用变量,在本例中为 converted_temp。但是,我不确定如何解决这个问题,因为我已经尝试将它分配给某个占位符,但最终没有输出任何内容。有什么方法可以通过我编写程序的方式来解决这个错误吗?
这是我写的:
import tkinter
import tkinter.messagebox
class TempConverterGUI:
def __init__(self):
# create main window, and set a custom window title
self.main_window = tkinter.Tk()
self.main_window.wm_title("Convert Temperatures")
# creates a top frame with label to give a title for the application
self.top_frame = tkinter.Frame(self.main_window)
self.title_label = tkinter.Label(self.top_frame, text= 'Temperature Converter')
self.title_label.pack(side='top')
self.top_frame.pack()
# create middle frame to hold main program components
self.mid_frame = tkinter.Frame(self.main_window)
#############################################################################################
# create frame to hold the unit lists
self.lists_frame = tkinter.Frame(self.mid_frame)
##########################
# create frame to hold original unit to convert from list components
self.from_list_frame = tkinter.Frame(self.lists_frame)
self.from_label = tkinter.Label(self.from_list_frame, text='Convert from:')
self.from_label.pack(side='top')
# creates radio button lists to allow user to decide which units to convert from
self.from_radio = tkinter.StringVar()
self.fb1 = tkinter.Radiobutton(self.from_list_frame, text= 'Fahrenheit', variable= self.from_radio, value= 'FAHRENHEIT')
self.fb2 = tkinter.Radiobutton(self.from_list_frame, text= 'Celsius', variable= self.from_radio, value= 'CELSIUS')
self.fb3 = tkinter.Radiobutton(self.from_list_frame, text= 'Kelvin', variable= self.from_radio, value= 'KELVIN')
self.fb1.pack()
self.fb2.pack()
self.fb3.pack()
########################
# create frame to hold list components to decide which unit to convert to
self.to_list_frame = tkinter.Frame(self.lists_frame)
self.to_label = tkinter.Label(self.to_list_frame, text='Convert to:')
self.to_label.pack(side='top')
# creates radio button lists to allow user to decide which units to convert to
self.to_radio = tkinter.StringVar()
self.tb1 = tkinter.Radiobutton(self.to_list_frame, text= 'Fahrenheit', variable= self.to_radio, value= 'FAHRENHEIT')
self.tb2 = tkinter.Radiobutton(self.to_list_frame, text= 'Celsius', variable= self.to_radio, value= 'CELSIUS')
self.tb3 = tkinter.Radiobutton(self.to_list_frame, text= 'Kelvin', variable= self.to_radio, value= 'KELVIN')
self.tb1.pack()
self.tb2.pack()
self.tb3.pack()
#############################################################################################
#Create frame to hold textbox input
self.entry_frame = tkinter.Frame(self.mid_frame)
self.temp_prompt_label = tkinter.Label(self.entry_frame, text='Enter a temperature:')
self.temp_entry = tkinter.Entry(self.entry_frame, width=10)
self.temp_prompt_label.pack(side='top')
self.temp_entry.pack(side='top')
############################################################################################################################################################################
############################################################################################################################################################################
# create frame to hold convert button components and answer label components
self.convert_frame = tkinter.Frame(self.mid_frame)
# label to display answer
self.answer = tkinter.StringVar()
self.answer_label = tkinter.Label(self.convert_frame, textvariable=self.answer)
self.answer_label.pack(side='bottom')
# convert button for actual conversion
self.convert_button = tkinter.Button(self.convert_frame, text='Convert', command=self.do_convert)##################################
self.convert_button.pack(side='top')
#####################################################
##Consider creating either error box or popup
# create a bottom frame for miscellaneous buttons
self.bottom_frame = tkinter.Frame(self.main_window)
# instructions button that makes popup box telling how to use app
self.instructions_button = tkinter.Button(self.bottom_frame, text='Instructions', command=self.instructions)
self.instructions_button.pack(side='left')
# quit button that quits app
self.quit_button = tkinter.Button(self.bottom_frame, text='Quit', command=self.main_window.destroy)
self.quit_button.pack(side='right')
##############################################
# packup the frames
self.from_list_frame.pack(side='left')
self.to_list_frame.pack(side='left')
self.lists_frame.pack(side='left')
self.convert_frame.pack(side='left')
self.entry_frame.pack(side='right')
self.mid_frame.pack(side ='top')
self.bottom_frame.pack(side='bottom')
# enter main loop
tkinter.mainloop()
#print(self.from_radio.get(), self.to_radio.get(), self.temp_entry)####
def instructions(self):
tkinter.messagebox.showinfo('Instructions', 'This application allows the user to convert a temperature between Fahrenheit, Celsius, and Kelvin. '\
'A user may select a unit to convert from, a unit to convert to, and what temperature they would like to convert. '\
'Using this information they may convert the entered temperature into the desired unit.')
#########################################
# called by the convert button, uses from_radio selection to decide who to convert into(which conversion function to call)
def do_convert(self):
#self.converted_temp = None
if self.from_radio == 'FAHRENHEIT':
converted_temp = f_convert()
elif self.from_radio == 'CELSIUS':
converted_temp = c_convert()
elif self.from_radio == 'KELVIN':
converted_temp = k_convert()
# sets self.answer(and so answer label) to value returned into converted_temp
self.answer.set(converted_temp)
###########################################################
# series of functions for each individual unit to hold conversion formulas for each possible case
# using self.to_radio selection to decide which conversion to perform, then returns the resulting temperature
# for use in do_convert
def f_convert(self):
if self.to_radio == 'FAHRENHEIT':
new_temp = self.temp_entry
elif self.to_radio == 'CELSIUS':
new_temp = (self.temp_entry - 32)*(5/9.0)
elif self.to_radio == 'KELVIN':
new_temp = (self.temp_entry + 459.67)*(5/9.0)
return new_temp
def c_convert(self):
if self.to_radio == 'FAHRENHEIT':
new_temp = (9/5.0)*self.temp_entry + 32.0
elif self.to_radio == 'CELSIUS':
new_temp = self.temp_entry
elif self.to_radio == 'KELVIN':
new_temp = self.temp_entry + 273.15
return new_temp
def k_convert(self):
if self.to_radio == 'FAHRENHEIT':
new_temp = (9/5.0)*(self.temp_entry-273.15) + 32
elif self.to_radio == 'CELSIUS':
new_temp = self.temp_entry - 273.15
elif self.to_radio == 'KELVIN':
new_temp = self.temp_entry
return new_temp
conv_gui = TempConverterGUI()
您收到错误是因为您忘记使用类型为 tkinter.StringVar
的 self.from_radio
对象的 get()
方法来检索其当前值。因为 if
语句中的 none 为真,并且局部变量 converted_temp
未定义,因为它在被引用之前从未被赋值。
下面是一个修改版本,显示了一种避免该问题的方法:
# called by the convert_button, uses from_radio selection to
# decide what to convert into (i.e. which conversion function to call)
def do_convert(self):
converted_temp = '' # default if somehow there's no match
from_radio = self.from_radio.get()
if from_radio == 'FAHRENHEIT':
converted_temp = f_convert()
elif from_radio == 'CELSIUS':
converted_temp = c_convert()
elif from_radio == 'KELVIN':
converted_temp = k_convert()
self.answer.set(converted_temp)
代码可以重构——有很多重复——但我只提一下实际上导致错误的两件事:
- 从未调用
self.from_radio
的.get()
方法。 - 在调用 class 方法(例如
f_convert()
、c_convert()
等)之前缺少self
s
示例:
def do_convert(self):
if self.from_radio == 'FAHRENHEIT': <---- missing ".get()" after "self.from_radio"
converted_temp = f_convert() <---- missing "self" before f_convert()
elif self.from_radio == 'CELSIUS':
converted_temp = c_convert()
elif self.from_radio == 'KELVIN':
converted_temp = k_convert()
self.answer.set(converted_temp)
您可以将其重新写成这样:
def do_convert(self):
radio_value = self.from_radio.get()
if radio_value == 'FAHRENHEIT':
converted_temp = self.f_convert()
elif radio_value == 'CELSIUS':
converted_temp = self.c_convert()
elif radio_value == 'KELVIN':
converted_temp = self.k_convert()
self.answer.set(converted_temp)