上一篇:Python小试牛刀:GUI(图形界面)实现计算器UI界面(二)-CSDN博客
回顾前两篇文章,第一篇文章主要实现了计算器UI界面如何布局,以及简单概述Python常用的GUI库。第二篇文章主要实现了计算器UI界面按钮组件与事件的交互,而在本片文章则是实现计算器完整功能。
运行结果:
代码设计
"""
计算器
"""
# 通配符'*'
__all__ = ['main']
# 计算器UI设计
class CalculatorUI:
import tkinter as tk
from tkinter import font
base = tk.Tk() # 新建窗口
base.title('计算器') # 设置标题
base.geometry("458x400") # 设置窗口像素大小
# 全局变量
labelData1 = tk.StringVar() # 标签数据
labelData2 = tk.StringVar() # 标签数据
# 设置字体样式
setChineseFont = font.Font(family='Arial', size=20, weight='bold')
setFont = font.Font(family='Helvetica', size=12, weight='bold')
# 主框架
mainFrame = tk.LabelFrame(base, text='标准', borderwidth=2, relief=tk.FLAT, font=setChineseFont)
mainFrame.pack(expand=True)
# 标签框架
labelFrame = tk.Frame(mainFrame, borderwidth=2, relief=tk.GROOVE)
labelFrame.grid(columnspan=4)
# 标签
showLabel1 = tk.Label(labelFrame, textvariable=labelData1, anchor='e', width=26, font=setChineseFont)
showLabel1.pack()
showLabel2 = tk.Label(labelFrame, textvariable=labelData2, anchor='e', width=26, font=setChineseFont)
showLabel2.pack()
# 删除按钮
clear = tk.Button(mainFrame, text='C', width=10, height=2, font=setFont)
clear.grid(row=1, column=0)
# 退格按钮
backSpace = tk.Button(mainFrame, text='⬅', width=10, height=2, font=setFont)
backSpace.grid(row=1, column=1)
# 余数(百分号)
remainder = tk.Button(mainFrame, text='%', width=10, height=2, font=setFont)
remainder.grid(row=1, column=2)
# 除号
division = tk.Button(mainFrame, text='➗', width=10, height=2, font=setFont)
division.grid(row=1, column=3)
# 7
seven = tk.Button(mainFrame, text='7', width=10, height=2, font=setFont)
seven.grid(row=2, column=0)
# 8
eight = tk.Button(mainFrame, text='8', width=10, height=2, font=setFont)
eight.grid(row=2, column=1)
# 9
nine = tk.Button(mainFrame, text='9', width=10, height=2, font=setFont)
nine.grid(row=2, column=2)
# 乘号
multiplication = tk.Button(mainFrame, text='✖', width=10, height=2, font=setFont)
multiplication.grid(row=2, column=3)
# 4
four = tk.Button(mainFrame, text='4', width=10, height=2, font=setFont)
four.grid(row=3, column=0)
# 5
five = tk.Button(mainFrame, text='5', width=10, height=2, font=setFont)
five.grid(row=3, column=1)
# 6
six = tk.Button(mainFrame, text='6', width=10, height=2, font=setFont)
six.grid(row=3, column=2)
# 减法
subtraction = tk.Button(mainFrame, text='➖', width=10, height=2, font=setFont)
subtraction.grid(row=3, column=3)
# 1
one = tk.Button(mainFrame, text='1', width=10, height=2, font=setFont)
one.grid(row=4, column=0)
# 2
two = tk.Button(mainFrame, text='2', width=10, height=2, font=setFont)
two.grid(row=4, column=1)
# 3
three = tk.Button(mainFrame, text='3', width=10, height=2, font=setFont)
three.grid(row=4, column=2)
# 加法
addition = tk.Button(mainFrame, text='➕', width=10, height=2, font=setFont)
addition.grid(row=4, column=3)
# 括号
brackets = tk.Button(mainFrame, text='( )', width=10, height=2, font=setFont)
brackets.grid(row=5, column=0)
# 0
zero = tk.Button(mainFrame, text='0', width=10, height=2, font=setFont)
zero.grid(row=5, column=1)
# 小数点.
dit = tk.Button(mainFrame, text='.', width=10, height=2, font=setFont)
dit.grid(row=5, column=2)
# 等于
equal = tk.Button(mainFrame, text='=', width=10, height=2, background='#00BFFF', font=setFont)
equal.grid(row=5, column=3)
# 按钮间距
tk.Label(mainFrame, height=3, width=1).grid(row=1, column=4) # 行填充
tk.Label(mainFrame, height=3, width=1).grid(row=2, column=4)
tk.Label(mainFrame, height=3, width=1).grid(row=3, column=4)
tk.Label(mainFrame, height=3, width=1).grid(row=4, column=4)
tk.Label(mainFrame, height=3, width=1).grid(row=5, column=4)
tk.Label(mainFrame, height=1, width=16).grid(row=6, column=1) # 列填充
tk.Label(mainFrame, height=1, width=16).grid(row=6, column=3)
# 初始化事件
def initUI(event):
# 0-9
UI.zero.config(background='#f0f0f0') # 0
UI.one.config(background='#f0f0f0') # 1
UI.two.config(background='#f0f0f0') # 2
UI.three.config(background='#f0f0f0') # 3
UI.four.config(background='#f0f0f0') # 4
UI.five.config(background='#f0f0f0') # 5
UI.six.config(background='#f0f0f0') # 6
UI.seven.config(background='#f0f0f0') # 7
UI.eight.config(background='#f0f0f0') # 8
UI.nine.config(background='#f0f0f0') # 9
# 特殊字符
UI.clear.config(background='#f0f0f0') # 删除
UI.backSpace.config(background='#f0f0f0') # 退格
UI.remainder.config(background='#f0f0f0') # 百分号/求余
UI.division.config(background='#f0f0f0') # 除号
UI.multiplication.config(background='#f0f0f0') # 乘号
UI.subtraction.config(background='#f0f0f0') # 减号
UI.addition.config(background='#f0f0f0') # 加号
UI.equal.config(background='#00BFFF') # 等于
UI.brackets.config(background='#f0f0f0') # 括号
UI.dit.config(background='#f0f0f0') # 小数点
# 鼠标在组件上的焦点事件
# 0-9
# 0
def zeroBackground(event):
UI.zero.config(background='pink')
def zeroReleaseBackground(event):
UI.zero.config(state=tk.DISABLED, background='pink')
UI.base.update()
time.sleep(0.1)
UI.zero.config(state=tk.NORMAL, background='#f0f0f0')
zeroEvent(event)
# 1
def oneBackground(event):
UI.one.config(background='pink')
def oneReleaseBackground(event):
UI.one.config(state=tk.DISABLED, background='pink')
UI.base.update()
time.sleep(0.1)
UI.one.config(state=tk.NORMAL, background='#f0f0f0')
oneEvent(event)
# 2
def twoBackground(event):
UI.two.config(background='pink')
def twoReleaseBackground(event):
UI.two.config(state=tk.DISABLED, background='pink')
UI.base.update()
time.sleep(0.1)
UI.two.config(state=tk.NORMAL, background='#f0f0f0')
twoEvent(event)
# 3
def threeBackground(event):
UI.three.config(background='pink')
def threeReleaseBackground(event):
UI.three.config(state=tk.DISABLED, background='pink')
UI.base.update()
time.sleep(0.1)
UI.three.config(state=tk.NORMAL, background='#f0f0f0')
threeEvent(event)
# 4
def fourBackground(event):
UI.four.config(background='pink')
def fourReleaseBackground(event):
UI.four.config(state=tk.DISABLED, background='pink')
UI.base.update()
time.sleep(0.1)
UI.four.config(state=tk.NORMAL, background='#f0f0f0')
fourEvent(event)
# 5
def fiveBackground(event):
UI.five.config(background='pink')
def fiveReleaseBackground(event):
UI.five.config(state=tk.DISABLED, background='pink')
UI.base.update()
time.sleep(0.1)
UI.five.config(state=tk.NORMAL, background='#f0f0f0')
fiveEvent(event)
# 6
def sixBackground(event):
UI.six.config(background='pink')
def sixReleaseBackground(event):
UI.six.config(state=tk.DISABLED, background='pink')
UI.base.update()
time.sleep(0.1)
UI.six.config(state=tk.NORMAL, background='#f0f0f0')
sixEvent(event)
# 7
def sevenBackground(event):
UI.seven.config(background='pink')
def sevenReleaseBackground(event):
UI.seven.config(state=tk.DISABLED, background='pink')
UI.base.update()
time.sleep(0.1)
UI.seven.config(state=tk.NORMAL, background='#f0f0f0')
sevenEvent(event)
# 8
def eightBackground(event):
UI.eight.config(background='pink')
def eightReleaseBackground(event):
UI.eight.config(state=tk.DISABLED, background='pink')
UI.base.update()
time.sleep(0.1)
UI.eight.config(state=tk.NORMAL, background='#f0f0f0')
eightEvent(event)
# 9
def nineBackground(event):
UI.nine.config(background='pink')
def nineReleaseBackground(event):
UI.nine.config(state=tk.DISABLED, background='pink')
UI.base.update()
time.sleep(0.1)
UI.nine.config(state=tk.NORMAL, background='#f0f0f0')
nineEvent(event)
# 特殊字符
# 删除
def clearBackground(event):
UI.clear.config(background='pink')
def clearReleaseBackground(event):
UI.clear.config(state=tk.DISABLED, background='pink')
UI.base.update()
time.sleep(0.1)
UI.clear.config(state=tk.NORMAL, background='#f0f0f0')
clearEvent(event)
# 退格
def backSpaceBackground(event):
UI.backSpace.config(background='pink')
def backSpaceReleaseBackground(event):
UI.backSpace.config(state=tk.DISABLED, background='pink')
UI.base.update()
time.sleep(0.1)
UI.backSpace.config(state=tk.NORMAL, background='#f0f0f0')
backSpaceEvent(event)
# 百分号/求余
def remainderBackground(event):
UI.remainder.config(background='pink')
def remainderReleaseBackground(event):
UI.remainder.config(state=tk.DISABLED, background='pink')
UI.base.update()
time.sleep(0.1)
UI.remainder.config(state=tk.NORMAL, background='#f0f0f0')
remainderEvent(event)
# 除号
def divisionBackground(event):
UI.division.config(background='pink')
def divisionReleaseBackground(event):
UI.division.config(state=tk.DISABLED, background='pink')
UI.base.update()
time.sleep(0.1)
UI.division.config(state=tk.NORMAL, background='#f0f0f0')
divisionEvent(event)
# 乘号
def multiplicationBackground(event):
UI.multiplication.config(background='pink')
def multiplicationReleaseBackground(event):
UI.multiplication.config(state=tk.DISABLED, background='pink')
UI.base.update()
time.sleep(0.1)
UI.multiplication.config(state=tk.NORMAL, background='#f0f0f0')
multiplicationEvent(event)
# 减号
def subtractionBackground(event):
UI.subtraction.config(background='pink')
def subtractionReleaseBackground(event):
UI.subtraction.config(state=tk.DISABLED, background='pink')
UI.base.update()
time.sleep(0.1)
UI.subtraction.config(state=tk.NORMAL, background='#f0f0f0')
subtractionEvent(event)
# 加号
def additionBackground(event):
UI.addition.config(background='pink')
def additionReleaseBackground(event):
UI.addition.config(state=tk.DISABLED, background='pink')
UI.base.update()
time.sleep(0.1)
UI.addition.config(state=tk.NORMAL, background='#f0f0f0')
additionEvent(event)
# 等于
def equalBackground(event):
UI.equal.config(background='pink')
def equalReleaseBackground(event):
UI.equal.config(state=tk.DISABLED, background='pink')
UI.base.update()
time.sleep(0.1)
UI.equal.config(state=tk.NORMAL, background='#00BFFF')
equalEvent(event)
# 括号
def bracketsBackground(event):
UI.brackets.config(background='pink')
def bracketsReleaseBackground(event):
UI.brackets.config(state=tk.DISABLED, background='pink')
UI.base.update()
time.sleep(0.1)
UI.brackets.config(state=tk.NORMAL, background='#f0f0f0')
bracketsEvent(event)
# 小数点
def ditBackground(event):
UI.dit.config(background='pink')
def ditReleaseBackground(event):
UI.dit.config(state=tk.DISABLED, background='pink')
UI.base.update()
time.sleep(0.1)
UI.dit.config(state=tk.NORMAL, background='#f0f0f0')
ditEvent(event)
# 组件背景颜色事件触发
def widgetColor():
# 初始化
UI.base.bind('<Leave>', initUI)
UI.showLabel1.config(foreground='gray', background='white')
UI.showLabel2.config(background='white')
# 0-9
UI.zero.bind('<Motion>', zeroBackground) # 0
UI.one.bind('<Motion>', oneBackground) # 1
UI.two.bind('<Motion>', twoBackground) # 2
UI.three.bind('<Motion>', threeBackground) # 3
UI.four.bind('<Motion>', fourBackground) # 4
UI.five.bind('<Motion>', fiveBackground) # 5
UI.six.bind('<Motion>', sixBackground) # 6
UI.seven.bind('<Motion>', sevenBackground) # 7
UI.eight.bind('<Motion>', eightBackground) # 8
UI.nine.bind('<Motion>', nineBackground) # 9
# 特殊字符
UI.clear.bind('<Motion>', clearBackground) # 删除
UI.backSpace.bind('<Motion>', backSpaceBackground) # 退格
UI.remainder.bind('<Motion>', remainderBackground) # 百分号/求余
UI.division.bind('<Motion>', divisionBackground) # 除号
UI.multiplication.bind('<Motion>', multiplicationBackground) # 乘号
UI.subtraction.bind('<Motion>', subtractionBackground) # 减号
UI.addition.bind('<Motion>', additionBackground) # 加号
UI.equal.bind('<Motion>', equalBackground) # 等于
UI.brackets.bind('<Motion>', bracketsBackground) # 括号
UI.dit.bind('<Motion>', ditBackground) # 小数点
# 按钮按下
UI.base.bind('<KeyPress-0>', zeroReleaseBackground) # 0
UI.zero.bind('<Button-1>', zeroEvent)
UI.base.bind('<KeyPress-1>', oneReleaseBackground) # 1
UI.one.bind('<Button-1>', oneEvent)
UI.base.bind('<KeyPress-2>', twoReleaseBackground) # 2
UI.two.bind('<Button-1>', twoEvent)
UI.base.bind('<KeyPress-3>', threeReleaseBackground) # 3
UI.three.bind('<Button-1>', threeEvent)
UI.base.bind('<KeyPress-4>', fourReleaseBackground) # 4
UI.four.bind('<Button-1>', fourEvent)
UI.base.bind('<KeyPress-5>', fiveReleaseBackground) # 5
UI.five.bind('<Button-1>', fiveEvent)
UI.base.bind('<KeyPress-6>', sixReleaseBackground) # 6
UI.six.bind('<Button-1>', sixEvent)
UI.base.bind('<KeyPress-7>', sevenReleaseBackground) # 7
UI.seven.bind('<Button-1>', sevenEvent)
UI.base.bind('<KeyPress-8>', eightReleaseBackground) # 8
UI.eight.bind('<Button-1>', eightEvent)
UI.base.bind('<KeyPress-9>', nineReleaseBackground) # 9
UI.nine.bind('<Button-1>', nineEvent)
UI.base.bind('<KeyPress-Delete>', clearReleaseBackground) # 删除
UI.base.bind('<KeyPress-c>', clearReleaseBackground) # 删除
UI.base.bind('<Key-C>', clearReleaseBackground) # 删除
UI.clear.bind('<Button-1>', clearEvent)
UI.base.bind('<KeyPress-BackSpace>', backSpaceReleaseBackground) # 退格
UI.backSpace.bind('<Button-1>', backSpaceEvent)
UI.base.bind('<Shift-Key-%>', remainderReleaseBackground) # 百分号、求余
UI.remainder.bind('<Button-1>', remainderEvent)
UI.base.bind('<KeyPress-slash>', divisionReleaseBackground) # 除号
UI.division.bind('<Button-1>', divisionEvent)
UI.base.bind('<KeyPress-asterisk>', multiplicationReleaseBackground) # 乘号
UI.base.bind('<Shift-Key-*>', multiplicationReleaseBackground) # 乘号
UI.multiplication.bind('<Button-1>', multiplicationEvent)
UI.base.bind('<KeyPress-minus>', subtractionReleaseBackground) # 减号
UI.subtraction.bind('<Button-1>', subtractionEvent)
UI.base.bind('<KeyPress-plus>', additionReleaseBackground) # 加号
UI.base.bind('<Shift-Key-+>', additionReleaseBackground) # 加号
UI.addition.bind('<Button-1>', additionEvent)
UI.base.bind('<KeyPress-Return>', equalReleaseBackground) # 等号
UI.base.bind('<KeyPress-equal>', equalReleaseBackground) # 等号
UI.equal.bind('<Button-1>', equalEvent)
UI.base.bind('<Shift-Key-(>', bracketsReleaseBackground) # 左括号
UI.base.bind('<Shift-Key-)>', bracketsReleaseBackground) # 右括号
UI.brackets.bind('<Button-1>', bracketsEvent)
UI.base.bind('<KeyPress-period>', ditReleaseBackground) # 小数点
UI.dit.bind('<Button-1>', ditEvent)
# 0 事件
def zeroEvent(event):
global labelShow2
# 数字前面不能是右括号')'
if ('原来是小瘪三'+labelShow2)[-1] in ')=':
return
labelShow2 += '0'
# 补小数点
if labelShow2 == '0' or labelShow2[-2] in '(+-×÷':
labelShow2 += '.'
UI.labelData2.set(labelShow2)
UI.zero.config(activeforeground='gray')
# 1 事件
def oneEvent(event):
global labelShow2
# 数字前面不能是右括号')'
if ('防止空字符'+labelShow2)[-1] in ')=':
return
labelShow2 += '1'
UI.labelData2.set(labelShow2)
UI.one.config(activeforeground='gray')
# 2 事件
def twoEvent(event):
global labelShow2
# 数字前面不能是右括号')'
if ('什么字符都可以'+labelShow2)[-1] in ')=':
return
labelShow2 += '2'
UI.labelData2.set(labelShow2)
UI.two.config(activeforeground='gray')
# 3 事件
def threeEvent(event):
global labelShow2
# 数字前面不能是右括号')'
if ('不影响代码'+labelShow2)[-1] in ')=':
return
labelShow2 += '3'
UI.labelData2.set(labelShow2)
UI.three.config(activeforeground='gray')
# 4 事件
def fourEvent(event):
global labelShow2
# 数字前面不能是右括号')'
if ('虽然可以封装成函数'+labelShow2)[-1] in ')=':
return
labelShow2 += '4'
UI.labelData2.set(labelShow2)
UI.four.config(activeforeground='gray')
# 5 事件
def fiveEvent(event):
global labelShow2
# 数字前面不能是右括号')'
if ('但是只有两行代码'+labelShow2)[-1] in ')=':
return
labelShow2 += '5'
UI.labelData2.set(labelShow2)
UI.five.config(activeforeground='gray')
# 6 事件
def sixEvent(event):
global labelShow2
# 数字前面不能是右括号')'
if ('调用函数还是两行代码'+labelShow2)[-1] in ')=':
return
labelShow2 += '6'
UI.labelData2.set(labelShow2)
UI.six.config(activeforeground='gray')
# 7 事件
def sevenEvent(event):
global labelShow2
# 数字前面不能是右括号')'
if ('索性来个自我介绍吧'+labelShow2)[-1] in ')=':
return
labelShow2 += '7'
UI.labelData2.set(labelShow2)
UI.seven.config(activeforeground='gray')
# 8 事件
def eightEvent(event):
global labelShow2
# 数字前面不能是右括号')'
if ('我是周华2022'+labelShow2)[-1] in ')=':
return
labelShow2 += '8'
UI.labelData2.set(labelShow2)
UI.eight.config(activeforeground='gray')
# 9 事件
def nineEvent(event):
global labelShow2
# 数字前面不能是右括号')'
if ('欢迎大家关注!'+labelShow2)[-1] in ')=':
return
labelShow2 += '9'
UI.labelData2.set(labelShow2)
UI.nine.config(activeforeground='gray')
# 删除 事件
def clearEvent(event):
global labelShow2, operator, operationData, bracketsFlag
# 数据初始化
bracketsFlag = 0
labelShow2 = ''
operator = []
operationData = []
UI.labelData2.set(labelShow2)
UI.clear.config(activeforeground='gray')
# 退格 事件
def backSpaceEvent(event):
global labelShow2
# 在数据内退格
if not operator:
labelShow2 = labelShow2[:-1:]
# 运算符退格
elif operator and operationData:
if labelShow2[-1] in '+-×÷%':
operator.pop()
operationData.pop()
labelShow2 = labelShow2[:-1:]
UI.labelData2.set(labelShow2)
UI.backSpace.config(activeforeground='gray')
# 求余 事件
def remainderEvent(event):
global labelShow2
# 首个字符不能出现百分号/求余
if not labelShow2:
return
# 百分号前面不能出现运算符,除了右括号')'
elif labelShow2[-1] in '+-×÷%(.=':
return
# 分割数据,获取数值和运算符
elif not operator:
operationData.append(labelShow2)
elif operator:
operationData.append(labelShow2.split(operationData[-1] + operator[-1])[-1])
operator.append('%')
labelShow2 += '%'
print(operator, operationData)
UI.labelData2.set(labelShow2)
UI.remainder.config(activeforeground='gray')
# 除法 事件
def divisionEvent(event):
global labelShow2
# 首个字符不能出现除号
if not labelShow2:
return
# 除号前面不能出现运算符,除了右括号')'和百分号'%'
elif labelShow2[-1] in '+-×÷(.=':
return
# 分割数据,获取数值和运算符
elif not operator:
operationData.append(labelShow2)
elif operator:
if labelShow2[-1] == '%':
operationData[-1] += operator.pop()
else:
operationData.append(labelShow2.split(operationData[-1]+operator[-1])[-1])
operator.append('÷')
labelShow2 += '÷'
print(operator, operationData)
UI.labelData2.set(labelShow2)
UI.division.config(activeforeground='gray')
# 乘法 事件
def multiplicationEvent(event):
global labelShow2
# 首个字符不能出现乘号
if not labelShow2:
return
# 乘号前面不能出现运算符,除了右括号')'和百分号'%'
elif labelShow2[-1] in '+-×÷(.=':
return
# 分割数据,获取数值和运算符
elif not operator:
operationData.append(labelShow2)
elif operator:
if labelShow2[-1] == '%':
operationData[-1] += operator.pop()
else:
operationData.append(labelShow2.split(operationData[-1] + operator[-1])[-1])
operator.append('×')
labelShow2 += '×'
print(operator, operationData)
UI.labelData2.set(labelShow2)
UI.multiplication.config(activeforeground='gray')
# 减法 事件
def subtractionEvent(event):
addFlag = 1 # 添加运算符旗帜
global labelShow2
# 首字符出现减号,视为负号
if not labelShow2:
addFlag = 0 # 添加运算符旗帜
# 减号前面不能出现运算符,除了括号'()'和百分号'%'
elif labelShow2[-1] in '+-×÷.=':
return
# 分割数据,获取数值和运算符
elif not operator and labelShow2[-1] not in '(':
operationData.append(labelShow2)
# 非首个数据
elif operator and operationData:
if labelShow2[-1] == '%':
operationData[-1] += operator.pop()
elif labelShow2[-1] == '(':
addFlag = 0 # 添加运算符旗帜
else:
operationData.append(labelShow2.split(operationData[-1] + operator[-1])[-1])
else:
addFlag = 0
# 不保存运算符旗帜
if addFlag:
operator.append('-')
print(operator, operationData)
labelShow2 += '-'
UI.labelData2.set(labelShow2)
UI.subtraction.config(activeforeground='gray')
# 加法 事件
def additionEvent(event):
addFlag = 1 # 添加运算符旗帜
global labelShow2
# 首字符出现加号,视为正号
if not labelShow2:
addFlag = 0 # 添加运算符旗帜
# 加号前面不能出现运算符,除了括号'()'和百分号'%'
elif labelShow2[-1] in '+-×÷.=':
return
# 分割数据,获取数值和运算符
elif not operator and labelShow2[-1] not in '(':
operationData.append(labelShow2)
# 非首个数据
elif operator and operationData:
if labelShow2[-1] == '%':
operationData[-1] += operator.pop()
elif labelShow2[-1] == '(':
addFlag = 0 # 添加运算符旗帜
else:
operationData.append(labelShow2.split(operationData[-1] + operator[-1])[-1])
else:
addFlag = 0
# 不保存运算符旗帜
if addFlag:
operator.append('+')
print(operator, operationData)
labelShow2 += '+' # 添加加号
UI.labelData2.set(labelShow2)
UI.addition.config(activeforeground='gray')
# 等于 事件
def equalEvent(event):
global labelShow2, labelShow1
labelShow1 = labelShow2 # 显示式子
# 首字符不能输入等号
if not labelShow2:
return
# 等号前不能出现的运算符,除了数字、右括号、百分号
elif labelShow2[-1] in '+-×÷=.':
return
# 括号必须成对,
elif len(re.findall(r'\(', labelShow2)) != len(re.findall(r'\)', labelShow2)):
UI.labelData1.set(labelShow1+'=错误')
UI.labelData2.set('括号不完整')
return
# 等号前面不能是不带括号的正数
elif not operator and labelShow2[0] != '+' and not len(re.findall(r'\(', labelShow2)):
return
# 处理等号前面只有一个数时
elif not operator or (labelShow2.strip('()+-')[-1] == '%' and len(operator) == 1 and operator[0] == '%'):
subtractionNum = len(re.findall('-', labelShow2)) # 减号数
# 查找百分号
if labelShow2.strip('()+-')[-1] == '%':
num = float(labelShow2.strip('()+-%')) / 100
# 奇数负为负,偶数负为正
if subtractionNum % 2:
labelShow2 = str(-num)
else:
labelShow2 = str(num)
elif labelShow2.strip('()+-')[-1] != '%':
num = labelShow2.strip('()+-')
# 奇数负为负,偶数负为正
if subtractionNum % 2:
labelShow2 = '-'+num
else:
labelShow2 = num
# 复杂运算
else:
# 防止报错
try:
# 计算式子结果
if resultEvent(event) == '求余错误':
return
except:
UI.labelData1.set(labelShow1 + '=崩溃')
UI.labelData2.set('抱歉,小算脑子烧坏了')
return
print(operator, operationData)
labelShow1 += '='+labelShow2 # 显示计算的式子
UI.labelData1.set(labelShow1)
UI.labelData2.set(labelShow2)
UI.equal.config(activeforeground='gray')
# 显示结果后删除存储的数据
if operationData:
operator.clear()
operationData.clear()
# 括号 事件
def bracketsEvent(event):
global labelShow2, bracketsFlag
# 首字符出现左括号'('
if not labelShow2:
labelShow2 += '('
# 左括号前面不能出现数字和小数点
elif labelShow2[-1] in '+-×÷(%':
labelShow2 += '('
# 右括号前面必须是数字和右括号
elif labelShow2[-1] not in '+-×÷%(.=' and len(re.findall(r'\(', labelShow2)) != len(re.findall(r'\)', labelShow2)):
labelShow2 += ')'
# 括号前面的百分号
if ('出来单挑啊'+labelShow2)[-2] == '%':
bracketsFlag += 1
if bracketsFlag % 2:
labelShow2 = labelShow2[:-1:]+'('
else:
labelShow2 = labelShow2[:-1:]+')'
UI.labelData2.set(labelShow2)
UI.brackets.config(activeforeground='gray')
# 小数点 事件
def ditEvent(event):
global labelShow2
# 小数点开头或者小数点前面是运算符就补零
if not labelShow2 or labelShow2[-1] in '(+-×÷%':
labelShow2 += '0'
# 小数点前面不能是右括号')'
elif labelShow2[-1] in ')=':
return
# 限制小数点输入(一)
elif not operator:
if len(re.findall(r'\.', labelShow2)) >= 1:
return
# 限制小数点输入(二)
elif operator and operationData:
str = labelShow2.split(operationData[-1]+operator[-1])[-1]
if len(re.findall(r'\.', str)) >= 1:
return
labelShow2 += '.'
UI.labelData2.set(labelShow2)
UI.dit.config(activeforeground='gray')
# 计算式子结果
def resultEvent(event):
global labelShow1, labelShow2, operator, operationData
# 分割最后一个数
if labelShow2[-1] == '%':
operationData[-1] += operator.pop()
else:
operationData.append(labelShow2.split(operationData[-1] + operator[-1])[-1])
print(operator, operationData)
# 化繁为简,逐个括号化简
while True:
leftBrackets = [] # 左括号
rightBrackets = [] # 右括号
minBrackets = [] # 最小括号区间
# 查找括号,并存储其索引号
for i in range(len(operationData)):
if '(' in operationData[i]:
leftBrackets.append(i)
elif ')' in operationData[i]:
rightBrackets.append(i)
# 判断式子是否有括号
if leftBrackets:
sign = ''
if operationData[leftBrackets[0]][0] == '-':
sign = '-'
# 找到最里层的括号
for i in range(len(rightBrackets)):
# 找到了
if leftBrackets[-1] < rightBrackets[i]:
left = leftBrackets[-1]
right = rightBrackets[i]
minBrackets.extend([left, right])
break
# 无括号式子设置
if not minBrackets:
minBrackets.extend([0, len(operationData)-1])
bracketsNum = operationData[minBrackets[0]:minBrackets[1] + 1:]
bracketsOperation = operator[minBrackets[0]:minBrackets[1]:]
# 左括号数分割
bracketsSplit = ''
if re.findall(r'\(', bracketsNum[0]):
bracketsSplit = bracketsNum[0].split('(')
bracketsNum[0] = bracketsSplit[-1]
# 化简括号内的式子
while True:
# 结束循环条件
if not bracketsOperation:
break
# 排除运算错误(除数不为零、求余需整数)
for i in range(len(bracketsOperation)):
# 让百分号'%'参与运算
for j in range(2):
if '%' in bracketsNum[i+j]:
bracketsNum[i+j] = str(float(bracketsNum[i+j].strip(')')[:-1:])/100)
# 查找除号
if bracketsOperation[i] == '÷':
# 判断除数是否为零
if float(bracketsNum[i+1].strip(')')) == 0:
UI.labelData1.set(labelShow1 + '=错误')
UI.labelData2.set('除数不能为零')
return '除数错误'
# 查找求余号
elif bracketsOperation[i] == '%':
# 判断两个数是否为整数
for j in range(2):
if re.findall(r'\.', bracketsNum[i+j]):
UI.labelData1.set(labelShow1 + '=错误')
UI.labelData2.set('求余必须为整数')
return '求余错误'
# 查找乘除求余(优先级高)
if bracketsOperation[i] in '×÷%':
# 计算两数之积
if bracketsOperation[i] == '×':
result = float(bracketsNum[i]) * float(bracketsNum[i+1].strip(')'))
# 计算两数之商
elif bracketsOperation[i] == '÷':
result = float(bracketsNum[i]) / float(bracketsNum[i+1].strip(')'))
# 计算两数之余
elif bracketsOperation[i] == '%':
result = float(bracketsNum[i]) % float(bracketsNum[i+1].strip(')'))
# 修改括号区间的数据,并进入下一次循环查找
bracketsNum.pop(i)
bracketsNum.pop(i)
bracketsOperation.pop(i)
bracketsNum.insert(i, str(result))
break
# 查找加减(优先级低)
elif bracketsOperation[i] in '+-':
if '×' in bracketsOperation:
continue
elif '÷' in bracketsOperation:
continue
elif '%' in bracketsOperation:
continue
# 计算两数之和
if bracketsOperation[i] == '+':
result = float(bracketsNum[i]) + float(bracketsNum[i + 1].strip(')'))
# 计算两数之差
elif bracketsOperation[i] == '-':
result = float(bracketsNum[i]) - float(bracketsNum[i + 1].strip(')'))
# 修改括号区间的数据,并进入下一次循环查找
bracketsNum.pop(i)
bracketsNum.pop(i)
bracketsOperation.pop(i)
bracketsNum.insert(i, str(result))
break
# 替换数据之前要补括号
leftBracketsNum = len(re.findall(r'\(', operationData[minBrackets[0]]))-1
rightBracketsNum = len(re.findall(r'\)', operationData[minBrackets[1]]))-1
# 删除数据
for i in range(minBrackets[0], minBrackets[1]+1):
operationData.pop(minBrackets[0])
for i in range(minBrackets[0], minBrackets[1]):
operator.pop(minBrackets[0])
# 化简一个括号后,根据左括号前正负号改变数值正负号
if leftBracketsNum >= 0 and bracketsSplit[-2] == '-':
if bracketsNum[0][0] == '-':
bracketsNum[0] = bracketsNum[0][1::]
else:
bracketsNum[0] = '-' + bracketsNum[0]
# 合并分割的左括号
leftBracketsStr = ''
if leftBracketsNum > rightBracketsNum:
for i in range(len(bracketsSplit)-2):
leftBracketsStr += bracketsSplit[i]+'('
bracketsNum[0] = leftBracketsStr + bracketsNum[0]
# 补左括号,并插入计算结果数据
if leftBracketsNum > rightBracketsNum:
operationData.insert(minBrackets[0], f"{bracketsNum[0]}")
# 补右括号,并插入计算结果数据
elif rightBracketsNum > leftBracketsNum:
operationData.insert(minBrackets[0], f"{bracketsNum[0]}{')' * (rightBracketsNum-leftBracketsNum)}")
# 删除两边多余的括号,并插入计算结果数据
elif leftBracketsNum == rightBracketsNum:
string = bracketsNum[0]
# 计算左括号的负号数
num = 0
for i in bracketsSplit[:-2:]:
if i == '-':
num += 1
# 消除括号
if leftBracketsNum >= 0 and num:
if num % 2:
if string[0] == '+':
string = '-' + string[1::]
elif string[0] != '-':
string = '-' + string
else:
if string[0] == '+':
string = string[1::]
operationData.insert(minBrackets[0], string)
# 结束条件循环条件
if not operator:
labelShow2 = operationData[0]
if ('one piece'+operationData[0])[-2::] == '.0':
labelShow2 = operationData[0][:-2:]
return
# 全局变量
import tkinter as tk
import time, re
UI = CalculatorUI() # 计算器UI设计
operator = [] # 运算符
operationData = [] # 运算数据
labelShow1 = '' # 标签内容1
labelShow2 = '' # 标签内容2
bracketsFlag = 0 # 计数旗帜
# 主函数
def main():
widgetColor() # 组件背景颜色改变
UI.base.mainloop() # 保持窗口运行
# 代码测试
if __name__ == '__main__':
main()
else:
print(f'导入{__name__}模块')
作者:周华
创作日期:2023/11/5