一个基于python3+PyQt5实现的简单计算器程序

时间:2022-12-29 14:39:57

【开发平台】ubuntu14 + python3 + PyQt5

【运行界面】
一个基于python3+PyQt5实现的简单计算器程序


一个基于python3+PyQt5实现的简单计算器程序


【源代码】

# -*- coding: utf-8 -*-

'''
Description: A simple calculater based on PyQt5
Author: waterfronter
Last Edit: 2017.10.15
'''

import sys
import re
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QVBoxLayout, QGridLayout, QGroupBox, QLineEdit
from PyQt5.QtCore import Qt

class Calculater(QWidget):

    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.setWindowTitle('Calculater')
        self.setGeometry(100, 100, 350, 150)
        #禁用最大化按钮
        self.setWindowFlags(Qt.WindowMinimizeButtonHint | Qt.WindowCloseButtonHint)

        #显示区
        self.resultflag = 0
        self.errflag = 0
        
        self.display = QLineEdit('0')
        self.display.setReadOnly(True)
        self.display.setAlignment(Qt.AlignRight)
        self.display.setMaxLength(30)        
        
        #操作区
        self.createGridLayout()
        
        windowLayout = QVBoxLayout()
        windowLayout.addWidget(self.display)
        windowLayout.addWidget(self.horizontalGroupBox)
        self.setLayout(windowLayout)

        self.show()

    def createGridLayout(self):
        self.horizontalGroupBox = QGroupBox('')
        layout = QGridLayout()

        #操作区第1行
        button00 = QPushButton('Backspace')
        button00.clicked.connect(self.on_click)
        layout.addWidget(button00, 0, 0)

        button01 = QPushButton('Clear')
        button01.clicked.connect(self.on_click)
        layout.addWidget(button01, 0, 1)

        button02 = QPushButton('Clear All')
        button02.clicked.connect(self.on_click)
        layout.addWidget(button02, 0, 2)

        button03 = QPushButton('/')
        button03.clicked.connect(self.on_click)
        layout.addWidget(button03, 0, 3)

        #操作区第2行
        button10 = QPushButton('7')
        button10.clicked.connect(self.on_click)
        layout.addWidget(button10, 1, 0)

        button11 = QPushButton('8')
        button11.clicked.connect(self.on_click)
        layout.addWidget(button11, 1, 1)

        button12 = QPushButton('9')
        button12.clicked.connect(self.on_click)
        layout.addWidget(button12, 1, 2)

        button13 = QPushButton('*')
        button13.clicked.connect(self.on_click)
        layout.addWidget(button13, 1, 3)

        #操作区第3行
        button20 = QPushButton('4')
        button20.clicked.connect(self.on_click)
        layout.addWidget(button20, 2, 0)

        button21 = QPushButton('5')
        button21.clicked.connect(self.on_click)
        layout.addWidget(button21, 2, 1)

        button22 = QPushButton('6')
        button22.clicked.connect(self.on_click)
        layout.addWidget(button22, 2, 2)

        button23 = QPushButton('-')
        button23.clicked.connect(self.on_click)
        layout.addWidget(button23, 2, 3)

        #操作区第4行
        button30 = QPushButton('1')
        button30.clicked.connect(self.on_click)
        layout.addWidget(button30, 3, 0)

        button31 = QPushButton('2')
        button31.clicked.connect(self.on_click)
        layout.addWidget(button31, 3, 1)

        button32 = QPushButton('3')
        button32.clicked.connect(self.on_click)
        layout.addWidget(button32, 3, 2)

        button33 = QPushButton('+')
        button33.clicked.connect(self.on_click)
        layout.addWidget(button33, 3, 3)

        #操作区第5行,其中'0'独占1行2列
        button40 = QPushButton('0')
        button40.clicked.connect(self.on_click)
        layout.addWidget(button40, 4, 0, 1, 2)  #从4行0列开始占1行2列

        button42 = QPushButton('.')
        button42.clicked.connect(self.on_click)
        layout.addWidget(button42, 4, 2, 1, 1)  #从4行2列开始占1行1列

        button43 = QPushButton('=')
        button43.clicked.connect(self.on_click)
        layout.addWidget(button43, 4, 3, 1, 1)  #从4行3列开始占1行1列

        self.horizontalGroupBox.setLayout(layout)
        
    def on_click(self):
        source = self.sender()
        
        #全部输入清零
        if source.text() == 'Clear All':
            self.display.setText('0')


        #删除最近输入的一个操作数
        elif source.text() == 'Clear':
            if self.resultflag != 1:           
                clrreg = re.compile(r'[0-9.]+$')
                substr = clrreg.sub('', self.display.text())
                if substr == '':
                    substr = '0'
                self.display.setText(substr)


        #退格键功能    
        elif source.text() == 'Backspace':
            if self.resultflag != 1:           
                if len(self.display.text()) <= 1:
                    newtext = '0'
                else:
                    newtext = self.display.text()[0 : (len(self.display.text()) - 1)]
                
                self.display.setText(newtext)


        #计算输入的算术表达式并将结果显示
        elif source.text() == '=':
            if self.resultflag != 1:           
                try:
                    disstr = self.display.text()[:]
                    #考虑表达式不完整的情况处理:尾部为运算符*/则补1
                    if disstr[len(disstr) - 1 : ] in '*/':
                        calstr = disstr + '1'
                    #尾部为运算符+-或小数点则补0
                    elif disstr[len(disstr) - 1 : ] in '+-.':
                        calstr = disstr + '0'
                    else:
                        calstr = disstr[:]
                    result = str(eval(calstr))
                    
                #考虑除0异常处理
                except (ZeroDivisionError, Exception) as errinfo:
                    result = 'Error: '+ str(errinfo)
                    self.errflag = 1
                
                self.display.setText(result)
                self.resultflag = 1
            

        #输入数字或小数点:将算术表达式输入同步显示出来
        else:
            self.numhandle() 
    
    def numhandle(self):
        rawstr = self.display.text()[:]
        strlen = len(rawstr)
        lastchar = rawstr[strlen-1 : ]
        inchar = self.sender().text()[:]
        newstr = ''
        
        #前面输入尚未计算结果
        if self.resultflag != 1:
            #当前最后一个字符为运算符(+-*/)
            if lastchar in '+-*/':
                #输入为0-9 -> 直接追加
                if inchar in '0123456789':
                    newstr = rawstr + inchar
                #输入为运算符 -> 忽略输入
                elif inchar in '+-*/':
                    newstr = rawstr[:]
                #输入为小数点 -> 小数点前补0再追加
                else:
                    newstr = rawstr + '0' + inchar
            
            #当前最后一个字符为小数点
            elif lastchar == '.':
                #输入为0-9 -> 直接追加
                if inchar in '0123456789':
                    newstr = rawstr + inchar
                #输入为小数点 -> 忽略输入
                elif inchar == '.':
                    newstr = rawstr[:]
                #输入为运算符 -> 运算符前补0再追加
                else:
                    newstr = rawstr + '0' + inchar
            
            #当前最后一个字符为0-9
            else:
                numreg1 = re.compile(r'[+\-*/]{0,1}[0-9]+\.[0-9]*[0-9]$')
                srchrslt1 = numreg1.search(rawstr)
                #当前最后一个数字前面已经有小数点
                if srchrslt1 != None: 
                    #输入为小数点 -> 忽略输入
                    if inchar == '.':
                        newstr = rawstr[:]
                    #输入为0-9或运算符 -> 直接追加
                    else:
                        newstr = rawstr + inchar
                
                #当前最后一个数字前面没有小数点
                else:
                    numreg2 = re.compile(r'[+\-*/]0$')
                    srchrslt2 = numreg2.search(rawstr)
                    #当前最后一个字符为0且作为最近运算符后的第一个数字
                    if srchrslt2 != None:
                        #输入为小数点或运算符 -> 直接追加
                        if inchar == '.' or inchar in '+-*/':
                            newstr = rawstr + inchar
                        #输入为0-9 -> 忽略输入
                        else:
                            newstr = rawstr[:]
                    #当前字符串即是'0'
                    elif rawstr == '0':
                        #输入为0-9 -> 用输入取代原字符'0'
                        if inchar in '0123456789':
                            newstr = inchar[:]
                        #输入为小数点或运算符 -> 直接追加
                        else:
                            newstr = rawstr + inchar
                    #其他情况均可直接追加
                    else:
                        newstr = rawstr + inchar


        #前面输入已经计算出结果
        else:
            #考虑计算有无异常
            if self.errflag == 0:
                #输入为运算符 -> 直接追加
                if inchar in '+-*/':
                    newstr = rawstr + inchar
                #输入小数点 -> 以小数点前补0刷新显示
                elif inchar == '.':
                    newstr = '0' + inchar
                #输入0-9 -> 以输入刷新显示
                else:
                    newstr = inchar[:]
            else:
                #输入为运算符 -> 忽略输入并擦除err信息
                if inchar in '+-*/':
                    newstr = '0'
                #输入小数点 -> 以小数点前补0刷新显示
                elif inchar == '.':
                    newstr = '0' + inchar
                #输入0-9 -> 以输入刷新显示
                else:
                    newstr = inchar[:]
                self.errflag = 0
                
            self.resultflag = 0

        self.display.setText(newstr)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Calculater()
    sys.exit(app.exec_())