1. 程式人生 > >一個基於python3+PyQt5實現的簡單計算器程式

一個基於python3+PyQt5實現的簡單計算器程式

【開發平臺】ubuntu14 + 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_())