之前写了一个很朴素的长度单位换算器(用Python写一个朴素的长度单位转换器),现在进行了一次改写,对比效果如下(分别是1.0、1.1、2.0版本):
可以转换的选项增加,版面排布进行了改善,使用滚动条将常规输入规范化,可以实现双向换算,之前的只能单向换算为米。还有很大的改良空间,可以继续改写。
Python3代码:
'''###############################################################################
# Name: UnitsExchange2.0
# Author: Wenchao Liu
# Date: 2018-11-27
# Description: To exchange the different units
# Debug in python 3.5.3
###############################################################################'''
from tkinter import *
#### 创建一个单位转换的类 ####
class UnitExchange():
'''这是一个用于单位换算的类,实现常用单位的互相换算'''
def __init__(self):
'''属性初始化'''
#### 创建主窗口 ####
self.root = Tk()
self.root.title('长度单位换算器')
#### 创建变量 ####
self.target_value = StringVar() # 输入数值
self.result_value = StringVar() # 输出数值
self.target_unit = StringVar() # 输入单位
self.result_unit = StringVar() # 输出单位
#### 创建输入输出的显示框架组件 ####
'''包含数值输入框、输入单位显示框、等号标签、结果数值显示框和结果单位显示框'''
self.top_frame = Frame(self.root) # 创建一个框架(纯容器)
# 数值输入框
self.target_entry = Entry(self.top_frame, width=18, textvariable=self.target_value)
self.target_entry.grid(column=1, row=1, sticky=W) # 第1列1行,罗盘式靠西
# 输入单位显示框
self.tar_unit_list = Listbox(self.top_frame, height=1, width=4)
self.tar_unit_list.grid(column=2, row=1, sticky=W)
# 等号标签
self.equal_label = Label(self.top_frame, text='=')
self.equal_label.grid(column=3, row=1)
# 结果数值显示框
self.res_value_list = Listbox(self.top_frame, height=1, width=18)
self.res_value_list.grid(column=4, row=1, sticky=E)
# 结果单位显示框
self.res_unit_list = Listbox(self.top_frame, height=1, width=4)
self.res_unit_list.grid(column=5, row=1, sticky=E)
self.top_frame.pack(side=TOP) # 将整个框架显示到主窗口顶端
#### 输入选项框架组件 ####
'''包含输入单位选项列表框和列表框的滚动条,将输入单位可选内容显示出来,可以进行竖直方向滚动。
调用的方法有:targetUnit()'''
self.target_frame = Frame(self.root)
# 滚动条
self.target_scroll = Scrollbar(self.target_frame)
self.target_scroll.pack(side=RIGHT, fill=Y)
# 输入单位选项列表框
self.target_list = Listbox(self.target_frame, height=5, width= 18, yscrollcommand=self.target_scroll.set)
self.target_list.bind('', self.targetUnit) # 双击列表框中的选项,调用targetUnit()方法
self.target_scroll.config(command=self.target_list.yview) # 竖直方向滚动
self.target_list.pack(side=LEFT, fill = BOTH)
self.target_frame.pack(side=LEFT) # 整个框架显示到主窗口左侧
#### 输出选项框架组件 ####
'''包含结果单位选项列表框和列表框的滚动条,将输出单位可选内容显示出来,可以进行竖直方向滚动。
调用的方法有:resultUnit()'''
# 滚动条
self.result_frame = Frame(self.root)
self.result_scroll = Scrollbar(self.result_frame)
self.result_scroll.pack(side=RIGHT, fill=Y)
# 输出单位选项列表框
self.result_list = Listbox(self.result_frame, height=5, width= 18, yscrollcommand=self.result_scroll.set)
self.result_list.bind('', self.resultUnit)
self.result_scroll.config(command=self.result_list.yview) # 竖直方向滚动
self.result_list.pack(side=LEFT, fill = BOTH)
self.result_frame.pack(side=RIGHT) # 整个框架显示到主窗口右侧
#### 创建按键 ####
'''点击换算按钮,进行单位换算。调用的方法有:calculateUnit()'''
self.calculate = Button(self.root, text='换算', command=self.calculateUnit)
self.calculate.pack(side=BOTTOM)
# 如果用户按下回车键,和点击换算按钮一样,启动换算
# self.root.bind('', self.calculateUnit)
#### 单位列表 ####
self.units = ['fm', 'pm', 'nm', 'um','mm','cm', 'm', 'km']
#### GUI初始化 ####
'''将列表框所有选项内容显示出来。调用方法有:self.targetList(),self.resultList() '''
self.targetList() # 调用targetList()方法,将输入选项列表框的内容显示出来
self.resultList() # 调用resultList()方法,将结果选项列表框的内容显示出来
#### 定义类的方法 ####
'''curselection() 返回列表框中的行号值,get()在没有传递参数时,获得列表框所有内容,将行号作为参数
传递,则获得行号对应选项的内容。定义的方法有:targetUnit(), resultUnit(), targetList(), resultList(),
switch2Meter(), switch2Other(), calculateUnit()'''
def targetUnit(self, ev=None):
'''得到转换前的单位'''
self.target_unit.set( self.target_list.get(self.target_list.curselection()))
self.tar_unit_list.insert(END, self.target_unit.get())
# 将选定的输入单位插入到输入单位选项显示框(在第一个框架组件里)
def resultUnit(self, ev=None):
'''得到转换后的单位'''
self.result_unit.set(self.result_list.get(self.result_list.curselection()))
self.res_unit_list.insert(END, self.result_unit.get())
# 将选定的输出单位插入到输出单位选项显示框(在第一个框架组件里)
def targetList(self, ev=None):
'''显示转换前的所有单位选项'''
tar_list = self.units
for item in tar_list:
# 将单位内容插入到输入单位选项列表框(在第二个框架组件里)
self.target_list.insert(END, item)
def resultList(self, ev=None):
'''显示转换后的所有单位选项'''
res_list = self.units
for item in res_list:
# 将单位内容插入到结果单位选项列表框(在第三个框架组件里)
self.result_list.insert(END, item)
def switch2Meter(self, var, x):
'''用字典实现switch功能,将其他长度单位换算为米'''
return {'cm' : lambda x: x/100.0,
'mm' : lambda x: x/1000.0,
'km' : lambda x: x*1000.0,
'um' : lambda x: x/1E6,
'nm' : lambda x: x/1E9,
'A' : lambda x: x/1E10,
'pm' : lambda x: x/1E12,
'fm' : lambda x: x/1E15,
'm' : lambda x: x,
}[var](x)
def switch2Other(self, var, x):
'''用字典实现switch功能,将米换算为其他长度单位'''
return {'cm' : lambda x: x*100.0,
'mm' : lambda x: x*1000.0,
'km' : lambda x: x/1000.0,
'um' : lambda x: x*1E6,
'nm' : lambda x: x*1E9,
'A' : lambda x: x*1E10,
'pm' : lambda x: x*1E12,
'fm' : lambda x: x*1E15,
'm' : lambda x: x,
}[var](x)
def calculateUnit(self):
'''根据需求,对单位进行换算,调用方法有:switch2Meter(),switch2Other()'''
try:
'''异常处理'''
tar_value = float(self.target_value.get()) # 获取输入值
tar_unit = self.target_unit.get() # 获取输入单位
res_unit = self.result_unit.get() # 获取输出单位
if (res_unit == 'm'):
# 如果是转换为米,则直接转换
self.result_value.set(self.switch2Meter(tar_unit, tar_value))
else:
# 如果不是转换为米,先转换为米作为过渡,再转换为其他单位
temp = StringVar() # 过渡量
temp.set(self.switch2Meter(tar_unit, tar_value))
temp_value = float(temp.get())
self.result_value.set(self.switch2Other(res_unit, temp_value))
'''输出数值插入到输出数值显示框,calculateUnit()方法被调用时,数值显示出来'''
self.res_value_list.insert(END, self.result_value.get())
except ValueError:
pass
#### 主函数 ####
def main():
x = UnitExchange() # 类实例化
mainloop() # 窗口消息循环
if __name__=='__main__':
main()