from tkinter import *
from tkinter import Tk
from tkinter import StringVar, Entry, Button, scrolledtext, Radiobutton
import math
# 定义计算器类
class Calculator:
def __init__(self, window):
window.title('带有界面的多功能科学计算器')
window.configure(background="white")
# 创建滚动条组件
bar = scrolledtext.Scrollbar(window, orient=HORIZONTAL) # orient设置水平
bar.grid(row=1, column=3, sticky=(W, E)) # 设置东西方向占满
self.string = StringVar() # 跟踪文本框内容的变量
entry = Entry(window, textvariable=self.string, xscrollcommand=bar.set, highlightthickness=80,
highlightcolor='red', width=65)
bar.config(command=entry.xview) # command和输入框组件关联
entry.grid(row=0, column=0, columnspan=100)
# entry.configure(background="white")#设置输入框的背景颜色
entry.focus() # 获取焦点
values = ["sqrt", ",", "(", ")", "pow", "进制转化",
"gcd", "C", "DEL", "%", "/", "sin",
"radians", "7", "8", "9", "*", "cos",
"degrees", "4", "5", "6", "-", "tan",
"exp", "1", "2", "3", "+", "pi",
"log", "e", "0", ".", "="]
i = 0
row = 2
col = 0
for txt in values:
padx = 36 # 每个按键的长和宽
pady = 36
if i % 6 == 0: # 控制每个按钮的布局
row = row + 1
col = 0
# 单独设置每个建的功能
if (txt == '='):
btn = Button(window, height=2, width=17, padx=padx, pady=pady, text=txt,
command=lambda txt=txt: self.SOLVE())
btn.grid(row=row, column=col, columnspan=2)
btn.configure(background="orange")
elif (txt == 'DEL'):
btn = Button(window, height=2, width=4, padx=padx, pady=pady, text=txt,
command=lambda: self.delete())
btn.grid(row=row, column=col, padx=1, pady=1)
btn.configure(background="orange")
elif (txt == 'C'):
btn = Button(window, height=2, width=4, padx=padx, pady=pady, text=txt,
command=lambda: self.clearall())
btn.grid(row=row, column=col, padx=1, pady=1)
btn.configure(background="orange")
elif (txt == '进制转化'): # 点击此按钮会新建一个窗口
btn = Button(window, height=2, width=4, padx=padx, pady=pady, text=txt,
command=self.count_change)
btn.grid(row=row, column=col, padx=1, pady=1)
btn.configure(background="red")
else:
btn = Button(window, height=2, width=4, padx=padx, pady=pady, text=txt,
command=lambda txt=txt: self.addChar(txt))
btn.grid(row=row, column=col, padx=1, pady=1)
btn.configure(background="white")
col = col + 1
i = i + 1
# 清空输入框的方法
def clearall(self):
self.string.set("")
# 等号绑定的方法
def SOLVE(self):
result = ""
try:
#普通带括号的四则运算和sin cos exp 用中缀转后缀求值
result = self.Infix_To_Suffix_value(self.string.get()) # 获得最终结果
self.string.set(result)
except:
# 如果是其他的没写尝试使用内置函数
try:
print("使用了eval")
result = eval(self.string.get())
self.string.set(result)
except:
#如果内置函数都求不出来就报错
result = '输入格式错误'
self.string.set(result)
# 添加math的一些功能
def addChar(self, char):
i = ['log', 'sqrt', 'pi', 'sin', 'cos', 'tan', 'e', "gcd", "radians", "degrees", "exp"]
if char in i:
self.string.set(self.string.get() + 'math.' + (str(char)))
else:
self.string.set(self.string.get() + (str(char)))
# 删除键
def delete(self):
self.string.set(self.string.get()[0:-1])
# 输入中缀表达式会先转成后缀表达式最后求值返回一个结果
def Infix_To_Suffix_value(self,expression):
# 处理最开始的字符串
def dealstr(expression):
s = expression
pattern_sin = r'\bmath.sin\b.*?[)]'
pattern_cos = r'\bmath.cos\b.*?[)]'
pattern_exp = r'\bmath.exp\b.*?[)]'
sin_list = re.findall(pattern_sin, s)
cos_list = re.findall(pattern_cos, s)
exp_list = re.findall(pattern_exp, s)
if sin_list:
for old in sin_list:
new = str(math.sin(m_a_v(old[9:-1])))
s = s.replace(old, new)
# print(s)
if cos_list:
for old in cos_list:
new = str(math.cos(m_a_v(old[9:-1])))
s = s.replace(old, new)
# print(s)
if exp_list:
for old in exp_list:
new = str(math.exp(m_a_v(old[9:-1])))
s = s.replace(old, new)
# print(s)
return s
# 设置优先级
def priority(z):
if z in ['*', '/']:
return 2
elif z in ['+', '-']:
return 1
# 中缀转后缀
def midToAfter(expression):
stack = [] # 存储栈用来存储运算符
post = [] # 后缀表达式存储
flag = 0 # 判断是否为小数和多位数的标志flag
for z in expression:
if z not in ['*', '/', '+', '-', '(', ')']: # 字符直接添加到后缀表达式存储列表中
if flag == 0:
post.append(z)
flag = 1
else:
# 当为数字或者'.'的时候就把当前z拼接到最后一个值后面
post[-1] = post[-1] + z
else:
flag = 0 # flag置0表明遇到了符号则上一个数存储完毕
if z != ')' and (not stack or z == '(' or stack[-1] == '('
or priority(z) > priority(stack[-1])): # stack 不空;栈顶为(;优先级大于
stack.append(z) # 运算符入栈
elif z == ')': # 右括号出栈
while True:
x = stack.pop()
if x != '(':
post.append(x)
else:
break
else: # 比较运算符优先级,看是否入栈出栈
while True:
if stack and stack[-1] != '(' and priority(z) <= priority(stack[-1]):
post.append(stack.pop())
else:
stack.append(z)
break
while stack: # 还未出栈的运算符,需要加到表达式末尾
post.append(stack.pop())
return post
# 处理后缀表达式得到结果
def Suffix_value(expression):
S1 = []
for i in expression:
if i not in ['+', '-', '*', '/']:
i = float(i) # 将字符数字装成浮点类型
S1.append(i)
else:
# s2是第一个s1是第二个注意顺序
if i == '+':
s2 = S1.pop()
if S1: # 判断非空才弹出后一个
s1 = S1.pop()
else:
s1 = 0
S1.append(s1 + s2)
if i == '-':
s2 = S1.pop()
if S1:
s1 = S1.pop()
else:
s1 = 0
S1.append(s1 - s2)
if i == '*':
s2 = S1.pop()
if S1:
s1 = S1.pop()
else:
s1 = 0
S1.append(s1 * s2)
if i == '/':
s2 = S1.pop()
if S1:
s1 = S1.pop()
else:
s1 = 0
S1.append(s1 / s2)
return S1[0]
# post=midToAfter(expression)
# result = str(Suffix_value(post)) # 得到最终的结果
# 将尾数为'.0'转换成整数显示
# if result[-1] == '0':
# result = result[0:-2]
# ------------------------------------------
# 进去中缀出来值
def m_a_v(expression):
value = Suffix_value(midToAfter(expression))
return value
result = str(m_a_v(dealstr(expression)))
if result[-1] == '0':
result = result[0:-2]
return result
# 进制转化函数
@staticmethod
def count_change():
# 定义进制转换类
class Programmer():
count = 0 # 类变量来记录选中的进制
def __init__(self):
window_top = Toplevel(root) # 弹出一个在root之上的窗口
window_top.transient(root) # 窗口只置顶root之上
window_top.resizable(False, False) # 不可调节窗体大小
window_top.title('进制转换界面')
# 跟踪文本框内容的变量
self.string = StringVar()
self.string_HEX = StringVar()
self.string_DEC = StringVar()
self.string_OCT = StringVar()
self.string_BIN = StringVar()
self.ALL = [[16, self.string_HEX], [10, self.string_DEC], [8, self.string_OCT], [2, self.string_BIN]]
self.var = StringVar()
Radiobutton(window_top, text="HEX", variable=self.var, value="HEX", indicatoron=False,
command=self.chose_key,
width=10).grid(row=0, column=0)
Radiobutton(window_top, text="DEC", variable=self.var, value="DEC", indicatoron=False,
command=self.chose_key,
width=10).grid(row=1, column=0)
Radiobutton(window_top, text="OCT", variable=self.var, value="OCT", indicatoron=False,
command=self.chose_key,
width=10).grid(row=2, column=0)
Radiobutton(window_top, text="BIN", variable=self.var, value="BIN", indicatoron=False,
command=self.chose_key,
width=10).grid(row=3, column=0)
entry_HEX = Entry(window_top, textvariable=self.string_HEX, width=44).grid(row=0, column=1,
columnspan=4)
entry_DEC = Entry(window_top, textvariable=self.string_DEC, width=44).grid(row=1, column=1,
columnspan=4)
entry_OCT = Entry(window_top, textvariable=self.string_OCT, width=44).grid(row=2, column=1,
columnspan=4)
entry_BIN = Entry(window_top, textvariable=self.string_BIN, width=44).grid(row=3, column=1,
columnspan=4)
values = ["A", ",", "(", ")", ".",
"B", "AC", "DEL", "%", "/",
"C", "7", "8", "9", "*",
"D", "4", "5", "6", "-",
"E", "1", "2", "3", "+",
"F", "0", "="]
i = 0
row = 4
col = 0
A = 10
for txt in values:
if i % 5 == 0: # 控制一列的按钮个数
row = row + 1
col = 0
# 单独设置每个建的功能
if (txt == '='):
btn = Button(window_top, height=2, width=33, text=txt, command=self.Equal)
btn.grid(row=row, column=col, columnspan=3)
btn.configure(background="orange")
elif (txt == 'DEL'):
btn = Button(window_top, height=2, width=A, text=txt, command=lambda: self.delete())
btn.grid(row=row, column=col)
btn.configure(background="orange")
elif (txt == 'AC'):
btn = Button(window_top, height=2, width=A, text=txt, command=lambda: self.clearall())
btn.grid(row=row, column=col)
btn.configure(background="orange")
else:
btn = Button(window_top, height=2, width=A, text=txt, command=lambda txt=txt: self.addChar(txt))
btn.grid(row=row, column=col)
btn.configure(background="white")
col = col + 1
i = i + 1
window_top.mainloop()
def addChar(self, char):
if self.count == 16:
self.string_HEX.set(self.string_HEX.get() + (str(char)))
if self.count == 10:
self.string_DEC.set(self.string_DEC.get() + (str(char)))
if self.count == 8:
self.string_OCT.set(self.string_OCT.get() + (str(char)))
if self.count == 2:
if self.string_BIN.get() == 0:
self.string_BIN.set('ob' + self.string_BIN.get())
self.string_BIN.set(self.string_BIN.get() + (str(char)))
# 等于按键的操作,按下按键会使的所有框框显示转换后的值
def Equal(self):
try:
if self.count == 16:
self.string_HEX.set(Programmer.Infix_To_Suffix_value(self.string_HEX.get(), 16, 'x'))
self.string_DEC.set(Programmer.Infix_To_Suffix_value(self.string_HEX.get(), 16, ''))
self.string_OCT.set(Programmer.Infix_To_Suffix_value(self.string_HEX.get(), 16, 'o'))
self.string_BIN.set(Programmer.Infix_To_Suffix_value(self.string_HEX.get(), 16, 'b'))
if self.count == 10:
self.string_DEC.set(Programmer.Infix_To_Suffix_value(self.string_DEC.get(), 10, ''))
self.string_HEX.set(Programmer.Infix_To_Suffix_value(self.string_DEC.get(), 10, 'x'))
self.string_OCT.set(Programmer.Infix_To_Suffix_value(self.string_DEC.get(), 10, 'o'))
self.string_BIN.set(Programmer.Infix_To_Suffix_value(self.string_DEC.get(), 10, 'b'))
if self.count == 8:
self.string_OCT.set(Programmer.Infix_To_Suffix_value(self.string_OCT.get(), 8, 'o'))
self.string_DEC.set(Programmer.Infix_To_Suffix_value(self.string_OCT.get(), 8, ''))
self.string_HEX.set(Programmer.Infix_To_Suffix_value(self.string_OCT.get(), 8, 'x'))
self.string_BIN.set(Programmer.Infix_To_Suffix_value(self.string_OCT.get(), 8, 'b'))
if self.count == 2:
self.string_BIN.set(Programmer.Infix_To_Suffix_value(self.string_BIN.get(), 2, 'b'))
self.string_OCT.set(Programmer.Infix_To_Suffix_value(self.string_BIN.get(), 2, 'o'))
self.string_DEC.set(Programmer.Infix_To_Suffix_value(self.string_BIN.get(), 2, ''))
self.string_HEX.set(Programmer.Infix_To_Suffix_value(self.string_BIN.get(), 2, 'x'))
except:
for i in self.ALL:
if i[0] != self.count:
i[1].set('输入错误')
def delete(self):
for i in self.ALL:
if i[0] == self.count:
i[1].set(i[1].get()[0:-1])
def clearall(self):
for i in self.ALL:
if i[0] == self.count:
i[1].set('')
# 判断是哪个按钮按下去了
def chose_key(self):
if self.var.get() == 'HEX':
self.count = 16
print('HEX')
if self.var.get() == 'DEC':
self.count = 10
print('DEC')
if self.var.get() == 'OCT':
self.count = 8
print('OCT')
if self.var.get() == 'BIN':
self.count = 2
print('BIN')
# 输入中缀表达式会先转成后缀表达式最后求值返回一个结果
@staticmethod
def Infix_To_Suffix_value(expression, input: int = 10, out: str = ''):
'''
expression为中缀表达式
input为expression的表达式类型eg:2,8,10,16,默认为10,
out为输出的类型eg:'b','o','x'默认为''代表10进制
'''
if input == 2:
a, b, c = ('0b', input, out)
elif input == 8:
a, b, c = ('0o', input, out)
elif input == 10:
a, b, c = ('', input, out)
else:
a, b, c = ('0x', input, out)
# 设置优先级
def priority(z):
if z in ['*', '/']:
return 2
elif z in ['+', '-']:
return 1
stack = [] # 存储栈用来存储运算符
post = [] # 后缀表达式存储
flag = 0 # 判断是否为小数和多位数的标志flag
for z in expression:
if z not in ['*', '/', '+', '-', '(', ')']: # 字符直接添加到后缀表达式存储列表中
if flag == 0:
post.append(z)
post[-1] = a + post[-1] # a
flag = 1
else:
# 当为数字或者'.'的时候就把当前z拼接到最后一个值后面
post[-1] = post[-1] + z
else:
flag = 0 # flag置0表明遇到了符号则上一个数存储完毕
if z != ')' and (not stack or z == '(' or stack[-1] == '('
or priority(z) > priority(stack[-1])): # stack 不空;栈顶为(;优先级大于
stack.append(z) # 运算符入栈
elif z == ')': # 右括号出栈
while True:
x = stack.pop()
if x != '(':
post.append(x)
else:
break
else: # 比较运算符优先级,看是否入栈出栈
while True:
if stack and stack[-1] != '(' and priority(z) <= priority(stack[-1]):
post.append(stack.pop())
else:
stack.append(z)
break
while stack: # 还未出栈的运算符,需要加到表达式末尾
post.append(stack.pop())
# 处理后缀表达式得到结果
def Suffix_value(expression):
S1 = []
for i in expression:
if i not in ['+', '-', '*', '/']:
i = int(i, b) # b 将字符数字转成整形进行10进制运算
S1.append(i)
else:
# s2是第一个s1是第二个注意顺序
if i == '+':
s2 = S1.pop()
if S1:
s1 = S1.pop()
else:
s1 = 0
S1.append(s1 + s2)
if i == '-':
s2 = S1.pop()
if S1:
s1 = S1.pop()
else:
s1 = 0
S1.append(s1 - s2)
if i == '*':
s2 = S1.pop()
if S1:
s1 = S1.pop()
else:
s1 = 0
S1.append(s1 * s2)
if i == '/':
s2 = S1.pop()
if S1:
s1 = S1.pop()
else:
s1 = 0
S1.append(s1 / s2)
return S1[0] # 结果为10进制数
result = str(format(Suffix_value(post), c)) # c 得到最终的结果
return result
# 实例化类
# print(id(programmer))
Programmer()
# 启动计算器
root = Tk()
Calculator(root)
root.mainloop()
这一份代码应付一下python的课程实践应该没问题。