|
|
|
|
import tkinter as tk
|
|
|
|
|
from tkinter import messagebox
|
|
|
|
|
import re
|
|
|
|
|
from math import *
|
|
|
|
|
|
|
|
|
|
# 创建主窗口
|
|
|
|
|
window = tk.Tk()
|
|
|
|
|
# 设置窗口大小和位置
|
|
|
|
|
window.geometry('520x300+600+300')
|
|
|
|
|
# 不允许改变窗口大小
|
|
|
|
|
window.resizable(False, False)
|
|
|
|
|
# 设置窗口标题
|
|
|
|
|
window.title('计算器')
|
|
|
|
|
# 背景颜色,例:window.config(background="BlueViolet")
|
|
|
|
|
window.config(background="Blue")
|
|
|
|
|
# 自动刷新字符串变量,可用 set 和 get 方法进行传值和取值
|
|
|
|
|
content_var = tk.StringVar(window, '')
|
|
|
|
|
# 创建单行文本框
|
|
|
|
|
content_entry = tk.Entry(window, textvariable=content_var, bd=10)
|
|
|
|
|
# 设置文本框为只读
|
|
|
|
|
content_entry['state'] = 'readonly'
|
|
|
|
|
# 设置文本框坐标及宽高
|
|
|
|
|
content_entry.place(x=20, y=10, width=300, height=38)
|
|
|
|
|
# 记录计算过程
|
|
|
|
|
record_text = tk.Text(window, wrap=tk.WORD, height=10)
|
|
|
|
|
record_text.place(x=320, y=50, width=180, height=240)
|
|
|
|
|
|
|
|
|
|
# 按钮显示内容
|
|
|
|
|
values = ['eˣ', 'π', '**', '%', '//', 'ln',
|
|
|
|
|
'√', '⌫', '(', ')', '/', 'lg',
|
|
|
|
|
'x!', '7', '8', '9', '*', 'tan',
|
|
|
|
|
'x³', '4', '5', '6', '-', 'cos',
|
|
|
|
|
'x²', '1', '2', '3', '+', 'sin']
|
|
|
|
|
|
|
|
|
|
# 其余特殊按钮
|
|
|
|
|
value = ['+/-', 'C', '0', '.', '=']
|
|
|
|
|
|
|
|
|
|
index_s = 0
|
|
|
|
|
index = 0
|
|
|
|
|
# 将按钮进行 5x6 放置
|
|
|
|
|
for row in range(5):
|
|
|
|
|
for col in range(6):
|
|
|
|
|
d = values[index_s]
|
|
|
|
|
index_s += 1
|
|
|
|
|
if row == 1:
|
|
|
|
|
if col == 1 or col == 2 or col == 3:
|
|
|
|
|
btn_digit = tk.Button(window, text=d, font=("Helvetica", 14, "bold"),
|
|
|
|
|
command=lambda x=d: onclick(x), bg="gray", fg="black")
|
|
|
|
|
btn_digit.place(x=20 + col * 50, y=50 + row * 40, width=50, height=40)
|
|
|
|
|
elif col == 0 or col == 4:
|
|
|
|
|
btn_digit = tk.Button(window, text=d, font=("Helvetica", 14, "bold"),
|
|
|
|
|
command=lambda x=d: onclick(x), bg="DeepSkyBlue", fg="purple")
|
|
|
|
|
btn_digit.place(x=20 + col * 50, y=50 + row * 40, width=50, height=40)
|
|
|
|
|
else:
|
|
|
|
|
btn_digit = tk.Button(window, text=d, font=("Helvetica", 14, "bold"),
|
|
|
|
|
command=lambda x=d: onclick(x), bg="orange", fg="blue")
|
|
|
|
|
btn_digit.place(x=20 + col * 50, y=50 + row * 40, width=50, height=40)
|
|
|
|
|
|
|
|
|
|
elif row == 2 or row == 3 or row == 4:
|
|
|
|
|
if col == 1 or col == 2 or col == 3:
|
|
|
|
|
btn_digit = tk.Button(window, text=d, font=("Helvetica", 14, "bold"),
|
|
|
|
|
command=lambda x=d: onclick(x), bg="LightPink", fg="red")
|
|
|
|
|
btn_digit.place(x=20 + col * 50, y=50 + row * 40, width=50, height=40)
|
|
|
|
|
elif col == 0 or col == 4:
|
|
|
|
|
btn_digit = tk.Button(window, text=d, font=("Helvetica", 14, "bold"),
|
|
|
|
|
command=lambda x=d: onclick(x), bg="DeepSkyBlue", fg="purple")
|
|
|
|
|
btn_digit.place(x=20 + col * 50, y=50 + row * 40, width=50, height=40)
|
|
|
|
|
else:
|
|
|
|
|
btn_digit = tk.Button(window, text=d, font=("Helvetica", 14, "bold"),
|
|
|
|
|
command=lambda x=d: onclick(x), bg="orange", fg="blue")
|
|
|
|
|
btn_digit.place(x=20 + col * 50, y=50 + row * 40, width=50, height=40)
|
|
|
|
|
|
|
|
|
|
elif col == 5:
|
|
|
|
|
btn_digit = tk.Button(window, text=d, font=("Helvetica", 14, "bold"),
|
|
|
|
|
command=lambda x=d: onclick(x), bg="orange", fg="blue")
|
|
|
|
|
btn_digit.place(x=20 + col * 50, y=50 + row * 40, width=50, height=40)
|
|
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
btn_digit = tk.Button(window, text=d, font=("Helvetica", 14, "bold"),
|
|
|
|
|
command=lambda x=d: onclick(x), bg="DeepSkyBlue", fg="purple")
|
|
|
|
|
btn_digit.place(x=20 + col * 50, y=50 + row * 40, width=50, height=40)
|
|
|
|
|
|
|
|
|
|
for leo in range(5):
|
|
|
|
|
c = value[index]
|
|
|
|
|
index += 1
|
|
|
|
|
if leo == 2:
|
|
|
|
|
btn_digit = tk.Button(window, text=c, font=("Helvetica", 14, "bold"),
|
|
|
|
|
command=lambda x=c: onclick(x), bg="LightPink", fg="red")
|
|
|
|
|
btn_digit.place(x=20 + leo * 50, y=250, width=50, height=40)
|
|
|
|
|
|
|
|
|
|
elif leo == 0:
|
|
|
|
|
btn_digit = tk.Button(window, text=c, font=("Helvetica", 14, "bold"),
|
|
|
|
|
command=lambda x=c: onclick(x), bg="SpringGreen", fg="red")
|
|
|
|
|
btn_digit.place(x=20 + leo * 50, y=250, width=50, height=40)
|
|
|
|
|
|
|
|
|
|
elif leo == 1:
|
|
|
|
|
btn_digit = tk.Button(window, text=c, font=("Helvetica", 14, "bold"),
|
|
|
|
|
command=lambda x=c: onclick(x), bg="yellow", fg="red")
|
|
|
|
|
btn_digit.place(x=20 + leo * 50, y=250, width=50, height=40)
|
|
|
|
|
|
|
|
|
|
elif leo == 3:
|
|
|
|
|
btn_digit = tk.Button(window, text=c, font=("Helvetica", 14, "bold"),
|
|
|
|
|
command=lambda x=c: onclick(x), bg="SkyBlue", fg="red")
|
|
|
|
|
btn_digit.place(x=20 + leo * 50, y=250, width=50, height=40)
|
|
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
btn_digit = tk.Button(window, text=c, font=("Helvetica", 14, "bold"),
|
|
|
|
|
command=lambda x=c: onclick(x), bg="LightCoral", fg="black")
|
|
|
|
|
btn_digit.place(x=220, y=250, width=100, height=40)
|
|
|
|
|
|
|
|
|
|
lab_text_record = tk.Label(window, text='历史记录', font=("Helvetica", 14, "bold"), bg="white", fg="black")
|
|
|
|
|
lab_text_record.place(x=320, y=10, width=180, height=40)
|
|
|
|
|
|
|
|
|
|
# 添加清除历史记录按钮
|
|
|
|
|
btn_clear_record = tk.Button(window, text='清除记录', font=("Helvetica", 14, "bold"),
|
|
|
|
|
command=lambda: record_text.delete(1.0, tk.END), bg="white", fg="black")
|
|
|
|
|
btn_clear_record.place(x=320, y=250, width=180, height=40)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 点击事件
|
|
|
|
|
def onclick(key):
|
|
|
|
|
# 运算符
|
|
|
|
|
operation = ('+', '-', '*', '/', '**', '//', '%')
|
|
|
|
|
# 获取文本框中的内容
|
|
|
|
|
content = content_var.get()
|
|
|
|
|
# 如果已有内容是以小数点开头的,在前面加 0
|
|
|
|
|
if content.startswith('.'):
|
|
|
|
|
content = '0' + content # 字符串可以直接用+来增加字符
|
|
|
|
|
# 根据不同的按钮作出不同的反应
|
|
|
|
|
if key in '0123456789':
|
|
|
|
|
# 按下 0-9 在 content 中追加
|
|
|
|
|
content += key
|
|
|
|
|
|
|
|
|
|
elif key == '.':
|
|
|
|
|
# 将 content 从 +-*/ 这些字符的地方分割开来
|
|
|
|
|
last_part = re.split(r'[+\-*/]', content)[-1]
|
|
|
|
|
if '.' in last_part:
|
|
|
|
|
# 信息提示对话框
|
|
|
|
|
tk.messagebox.showerror('错误', '数字只有一个小数点,所以不能再次点击!')
|
|
|
|
|
return
|
|
|
|
|
else:
|
|
|
|
|
content += key
|
|
|
|
|
|
|
|
|
|
elif key == 'C':
|
|
|
|
|
# 清除文本框
|
|
|
|
|
content = ''
|
|
|
|
|
|
|
|
|
|
elif key == '=':
|
|
|
|
|
try:
|
|
|
|
|
# 对输入的表达式求值
|
|
|
|
|
result = str(eval(content.replace("π", str(pi)).replace("rad", "radians")))
|
|
|
|
|
record_text.insert(tk.END, f"{content} = {result}\n")
|
|
|
|
|
content = result
|
|
|
|
|
except ZeroDivisionError:
|
|
|
|
|
tk.messagebox.showerror('错误', '这个值太大了,以至于无法算出其值,0不能作为除数!')
|
|
|
|
|
return
|
|
|
|
|
except Exception as e:
|
|
|
|
|
tk.messagebox.showerror('错误', f'无效表达式: {e}')
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
elif key in operation:
|
|
|
|
|
if content.endswith(operation):
|
|
|
|
|
tk.messagebox.showerror('错误', '运算符号之间不能直接连接,需要加入数值!')
|
|
|
|
|
return
|
|
|
|
|
content += key
|
|
|
|
|
|
|
|
|
|
elif key == '+/-':
|
|
|
|
|
# 将正负号切换
|
|
|
|
|
if content.startswith('-'):
|
|
|
|
|
content = content[1:]
|
|
|
|
|
else:
|
|
|
|
|
content = '-' + content
|
|
|
|
|
|
|
|
|
|
elif key in '()':
|
|
|
|
|
# 直接在内容后面追加括号
|
|
|
|
|
content += key
|
|
|
|
|
|
|
|
|
|
elif key == '√':
|
|
|
|
|
# 从 . 处分割存入 n,n 是一个列表
|
|
|
|
|
n = content.split('.')
|
|
|
|
|
# 如果列表中所有的都是数字,就是为了检查表达式是不是正确的
|
|
|
|
|
if all(map(lambda x: x.isdigit(), n)):
|
|
|
|
|
content = sqrt(eval(content))
|
|
|
|
|
else:
|
|
|
|
|
tk.messagebox.showerror('错误', '在实数范围内,负数不能算数平方根!')
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
elif key == 'eˣ':
|
|
|
|
|
# 添加常数e的x次方,content = exp(eval(content))
|
|
|
|
|
content += 'e**'
|
|
|
|
|
|
|
|
|
|
elif key == '⌫':
|
|
|
|
|
# 删除最后一个字符
|
|
|
|
|
content = content[:-1]
|
|
|
|
|
|
|
|
|
|
elif key == 'x²':
|
|
|
|
|
# 计算平方
|
|
|
|
|
try:
|
|
|
|
|
content = str(float(content) ** 2)
|
|
|
|
|
except Exception as e:
|
|
|
|
|
tk.messagebox.showerror('错误', f'无效表达式: {e}')
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
elif key == 'x³':
|
|
|
|
|
# 计算立方
|
|
|
|
|
try:
|
|
|
|
|
content = str(float(content) ** 3)
|
|
|
|
|
except Exception as e:
|
|
|
|
|
tk.messagebox.showerror('错误', f'无效表达式: {e}')
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
elif key == 'x!':
|
|
|
|
|
# 计算阶乘
|
|
|
|
|
try:
|
|
|
|
|
num = int(content)
|
|
|
|
|
if num < 0:
|
|
|
|
|
tk.messagebox.showerror('错误', '请输入一个非负整数进行阶乘运算!')
|
|
|
|
|
return
|
|
|
|
|
content = str(factorial(num))
|
|
|
|
|
except ValueError:
|
|
|
|
|
tk.messagebox.showerror('错误', '请输入一个非负整数进行阶乘运算!')
|
|
|
|
|
return
|
|
|
|
|
except Exception as e:
|
|
|
|
|
tk.messagebox.showerror('错误', f'无效的表达式: {e}')
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
elif key == 'π':
|
|
|
|
|
# 添加常数π
|
|
|
|
|
content += 'π'
|
|
|
|
|
|
|
|
|
|
elif key == 'sin':
|
|
|
|
|
# 计算sin值,content = sin(eval(content))
|
|
|
|
|
content += 'sin('
|
|
|
|
|
|
|
|
|
|
elif key == 'cos':
|
|
|
|
|
# 计算cos值,content = cos(eval(content))
|
|
|
|
|
content += 'cos('
|
|
|
|
|
|
|
|
|
|
elif key == 'tan':
|
|
|
|
|
# 计算tan值,content = tan(eval(content))
|
|
|
|
|
content += 'tan('
|
|
|
|
|
|
|
|
|
|
elif key == 'lg':
|
|
|
|
|
# 计算常数对数lg的值,content = log10(eval(content))
|
|
|
|
|
content += 'log10('
|
|
|
|
|
|
|
|
|
|
elif key == 'ln':
|
|
|
|
|
# 计算自然对数ln的值,content = log(eval(content))
|
|
|
|
|
content += 'log('
|
|
|
|
|
|
|
|
|
|
elif key == 'rad':
|
|
|
|
|
# 当输入数字到三角函数运算时,默认为弧度制。
|
|
|
|
|
content = str(eval(content)) + ' rad'
|
|
|
|
|
|
|
|
|
|
# 将结果显示到文本框中
|
|
|
|
|
content_var.set(content)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 运行主循环
|
|
|
|
|
|
|
|
|
|
window.mainloop()
|
|
|
|
|
|
|
|
|
|
# 2 + 9 * ((3*12) - 8) // 10 = 27
|
|
|
|
|
# 3 * 4 ** 2 // 8 % 7 = 6
|
|
|
|
|
# 3 + 5 % 6 * 2 // 8 = 4
|