Python小试牛刀:GUI(图形界面)实现计算器UI界面(三)

news2024/11/28 14:48:12

上一篇: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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1177006.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

shiro-cve2016-4437漏洞复现

一、漏洞特征 Apache Shiro是一款开源强大且易用的Java安全框架&#xff0c;提供身份验证、授权、密码学和会话管理。Shiro框架直观、易用&#xff0c;同时也能提供健壮的安全性。 因为在反序列化时,不会对其进行过滤,所以如果传入恶意代码将会造成安全问题 在 1.2.4 版本前, 加…

Disk Drill v5.3.1313(数据恢复备份)

Disk Drill是一款功能强大的数据恢复软件&#xff0c;它可以帮助用户恢复已删除、丢失、格式化或损坏的文件&#xff0c;并支持多种存储设备&#xff0c;包括计算机硬盘驱动器、外部硬盘、USB闪存驱动器、内存卡和其他存储介质。它和很多的文件系统都兼容&#xff0c;比如&…

如何快速搭建本地书库结合内网穿透实现公网随时远程访问

Kindle中国电子书店停运不要慌&#xff0c;十分钟搭建自己的在线书库随时随地看小说&#xff01; 文章目录 Kindle中国电子书店停运不要慌&#xff0c;十分钟搭建自己的在线书库随时随地看小说&#xff01;1.网络书库软件下载安装2.网络书库服务器设置3.内网穿透工具设置4.公网…

高压放大器在微机电工程中有哪些应用

高压放大器在微机电工程中有许多重要的应用。微机电工程是一种利用微电子加工技术制造微米级或纳米级机械结构并与电子元件集成的领域。高压放大器在MEMS领域发挥着关键的作用&#xff0c;下面将介绍几个高压放大器在MEMS工程中的应用。 MEMS驱动器&#xff1a;MEMS驱动器常用于…

CLIP Surgery论文阅读

CLIP Surgery for Better Explainability with Enhancement in Open-Vocabulary Tasks&#xff08;CVPR2023&#xff09; M norm ⁡ ( resize ⁡ ( reshape ⁡ ( F i ˉ ∥ F i ‾ ∥ 2 ⋅ ( F t ∥ F t ‾ ∥ 2 ) ⊤ ) ) ) M\operatorname{norm}\left(\operatorname{resize}\…

Linux认识协议

目录 TCP协议通信流程TCP三次握手数据传输过程四次挥手过程TCP 和 UDP 对比 认识协议协议的概念结构化数据的传输序列化和反序列化 网络版计算器服务端代码面向字节流 协议定制客户端代码编写代码测试守护进程守护进程创建 关于协议制定中使用现成方法实现 TCP协议通信流程 下…

华为H12-831题库

单选&#xff09;当IS-IS网络中有多条冗余链路时&#xff0c;可能会出现多条等价路由。关于IS-IS网络内的等价路由&#xff0c;以下哪个描述是错误的? A、当组网中存在的等价路由数量大于通过命令配置的数量&#xff0c;且这些路由优先级相同时&#xff0c;优选下一跳设备Sys…

三、机器学习基础知识:Python常用机器学习库(SKlearn)

文章目录 1、Scikit learn简介2、主要步骤3、数据预处理4、模型选择与算法评价 1、Scikit learn简介 Scikit learn 的简称是 SKlearn&#xff0c;专门提供了 Python 中实现机器学习的模块。Sklearn 是一个简单高效的数据分析算法工具&#xff0c;建立在 NumPy、SciPy和 Matplo…

深入研究Android内存

深入研究Android内存 Android应用程序开发时&#xff0c;我们始终意识到自己是Android硬件和操作系统的一部分。 从硬件角度来看&#xff0c;我们可以将Android手机分为不同级别。基本上&#xff0c;我们可以将它们分类为适用于低端硬件或API的入门级、中级和高级硬件-API手机…

Python+Selenium WebUI自动化框架 -- 基础操作封装

前言&#xff1a; 封装Selenium基本操作&#xff0c;让所有页面操作一键调用&#xff0c;让UI自动化框架脱离高成本、低效率时代&#xff0c;将用例的重用性贯彻到极致&#xff0c;让烦人的PO模型变得无所谓&#xff0c;让一个测试小白都能编写并实现自动化。 知识储备前提&a…

WordPress自适应图片主题源码CX-UDY主题模板 带会员积分下载系统

说明&#xff1a;该主题只适用于WordPress 4.8及以下版本&#xff0c;高版本暂不支持&#xff0c;介意的请勿下&#xff01; 下载地址 qnziyw点cn/cmsmb/wordpress/8084点html

Flutter:安装依赖报错doesn‘t support null safety

项目中需要引用http依赖&#xff0c;在pubspec.yaml文件中添加如下信息&#xff1a; 当同步时&#xff0c;报错信息如下&#xff1a; [myflutter] flutter pub upgrade Resolving dependencies... The current Dart SDK version is 3.1.3. Because myflutter depends on http &…

超简单的Mac双开微信,升级后失败重复操作仍然有效

首先找到安装的微信 应用程序 -> 微信 右键 -> 复制 复制出来效果如下&#xff1a; 在复制出来的微信应用右键-> 点击显示包内容 但是每次打开微信都特别麻烦&#xff0c;这里选择脚本右键制作替身&#xff0c;最后多出来的替身图标&#xff0c;拖拽到桌面就可以了…

6.数据类型与运算符

目录 mysql数据类型 整型数据类型 浮点数类型和定点数类型 1、日期时间类型 1、YEAR 2、TIME 3、DATE类型 4、DATETIME 5、TIMESTAMP 2、字符串类型 1、CHAR 和 VARCHAR类型&#xff1a; 2、TEXT类型 3、ENUM类型 4、SET类型 二进制字符串类型 1、BIT类型 2、…

Java学习 7.Java-方法的使用

一、为什么要使用方法 在编程中&#xff0c;某段功能的代码可能频繁使用&#xff0c;如果在某个位置重新实现一遍&#xff0c;会&#xff1a; 1.使程序变得繁琐 2.开发效率底下&#xff0c;做了大量重复性工作 3.不利于维护&#xff0c;需要改动时&#xff0c;所有用到该段…

Flink SQL DataGen Connector 示例

Flink SQL DataGen Connector 示例 1、概述 使用 Flink SQL DataGen Connector&#xff0c;可以快速地生成符合规则的测试数据&#xff0c;可以在不依赖真实数据的情况下进行开发和测试。 2、使用示例 创建一个名为 “users” 的表&#xff0c;包含 6 个字段&#xff1a;id…

智能井盖生产商家,万宾科技井盖传感器产品详情

市政府管理水平决定城市人民幸福程度&#xff0c;所以在智慧城市推进过程中&#xff0c;市政府也在加快城市信息基础设施建设&#xff0c;希望提高公共服务水平&#xff0c;以此来满足城市居民的需求&#xff0c;进一步推进城市信息化智能化发展。作为城市生命线的一个组成部分…

Docker学习——④

文章目录 1、Docker Image&#xff08;镜像&#xff09;2、镜像命令详解2.1 docker rmi2.2 docker save2.3 docker load2.4 docker image inspect2.5 docker history2.6 docker image prune 3、镜像综合实战3.1 离线镜像迁移3.2 镜像存储的压缩与共享 1、Docker Image&#xff…

第七章《搞懂算法:线性回归是怎么回事》笔记

线性回归算法是机器学习算法中最简单的一类&#xff0c;线性回归算法主要用于连续值的预测问题。 7.1 什么是线性回归 这种刻画了不同变量之间关系的模型叫作回归模型&#xff0c;如果这个模型是线性的&#xff0c;则为线性回归模型。 线性回归主要是应用回归分析来确定两种…