mirror of
https://github.com/pyqt/examples.git
synced 2025-08-22 17:47:10 +00:00
The commits since then moved many files into the src/ subdirectory. This would have broken existing links on the internet. To solve this, we leave the master branch as-is and make such breaking changes on a different branch.
358 lines
12 KiB
Python
358 lines
12 KiB
Python
#!/usr/bin/env python
|
|
|
|
|
|
#############################################################################
|
|
##
|
|
## Copyright (C) 2013 Riverbank Computing Limited.
|
|
## Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
|
## All rights reserved.
|
|
##
|
|
## This file is part of the examples of PyQt.
|
|
##
|
|
## $QT_BEGIN_LICENSE:BSD$
|
|
## You may use this file under the terms of the BSD license as follows:
|
|
##
|
|
## "Redistribution and use in source and binary forms, with or without
|
|
## modification, are permitted provided that the following conditions are
|
|
## met:
|
|
## * Redistributions of source code must retain the above copyright
|
|
## notice, this list of conditions and the following disclaimer.
|
|
## * Redistributions in binary form must reproduce the above copyright
|
|
## notice, this list of conditions and the following disclaimer in
|
|
## the documentation and/or other materials provided with the
|
|
## distribution.
|
|
## * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
|
|
## the names of its contributors may be used to endorse or promote
|
|
## products derived from this software without specific prior written
|
|
## permission.
|
|
##
|
|
## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
|
## $QT_END_LICENSE$
|
|
##
|
|
#############################################################################
|
|
|
|
|
|
import math
|
|
|
|
from PyQt5.QtCore import Qt
|
|
from PyQt5.QtWidgets import (QApplication, QGridLayout, QLayout, QLineEdit,
|
|
QSizePolicy, QToolButton, QWidget)
|
|
|
|
|
|
class Button(QToolButton):
|
|
def __init__(self, text, parent=None):
|
|
super(Button, self).__init__(parent)
|
|
|
|
self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
|
|
self.setText(text)
|
|
|
|
def sizeHint(self):
|
|
size = super(Button, self).sizeHint()
|
|
size.setHeight(size.height() + 20)
|
|
size.setWidth(max(size.width(), size.height()))
|
|
return size
|
|
|
|
|
|
class Calculator(QWidget):
|
|
NumDigitButtons = 10
|
|
|
|
def __init__(self, parent=None):
|
|
super(Calculator, self).__init__(parent)
|
|
|
|
self.pendingAdditiveOperator = ''
|
|
self.pendingMultiplicativeOperator = ''
|
|
|
|
self.sumInMemory = 0.0
|
|
self.sumSoFar = 0.0
|
|
self.factorSoFar = 0.0
|
|
self.waitingForOperand = True
|
|
|
|
self.display = QLineEdit('0')
|
|
self.display.setReadOnly(True)
|
|
self.display.setAlignment(Qt.AlignRight)
|
|
self.display.setMaxLength(15)
|
|
|
|
font = self.display.font()
|
|
font.setPointSize(font.pointSize() + 8)
|
|
self.display.setFont(font)
|
|
|
|
self.digitButtons = []
|
|
|
|
for i in range(Calculator.NumDigitButtons):
|
|
self.digitButtons.append(self.createButton(str(i),
|
|
self.digitClicked))
|
|
|
|
self.pointButton = self.createButton(".", self.pointClicked)
|
|
self.changeSignButton = self.createButton(u"\N{PLUS-MINUS SIGN}",
|
|
self.changeSignClicked)
|
|
|
|
self.backspaceButton = self.createButton("Backspace",
|
|
self.backspaceClicked)
|
|
self.clearButton = self.createButton("Clear", self.clear)
|
|
self.clearAllButton = self.createButton("Clear All", self.clearAll)
|
|
|
|
self.clearMemoryButton = self.createButton("MC", self.clearMemory)
|
|
self.readMemoryButton = self.createButton("MR", self.readMemory)
|
|
self.setMemoryButton = self.createButton("MS", self.setMemory)
|
|
self.addToMemoryButton = self.createButton("M+", self.addToMemory)
|
|
|
|
self.divisionButton = self.createButton(u"\N{DIVISION SIGN}",
|
|
self.multiplicativeOperatorClicked)
|
|
self.timesButton = self.createButton(u"\N{MULTIPLICATION SIGN}",
|
|
self.multiplicativeOperatorClicked)
|
|
self.minusButton = self.createButton("-", self.additiveOperatorClicked)
|
|
self.plusButton = self.createButton("+", self.additiveOperatorClicked)
|
|
|
|
self.squareRootButton = self.createButton("Sqrt",
|
|
self.unaryOperatorClicked)
|
|
self.powerButton = self.createButton(u"x\N{SUPERSCRIPT TWO}",
|
|
self.unaryOperatorClicked)
|
|
self.reciprocalButton = self.createButton("1/x",
|
|
self.unaryOperatorClicked)
|
|
self.equalButton = self.createButton("=", self.equalClicked)
|
|
|
|
mainLayout = QGridLayout()
|
|
mainLayout.setSizeConstraint(QLayout.SetFixedSize)
|
|
|
|
mainLayout.addWidget(self.display, 0, 0, 1, 6)
|
|
mainLayout.addWidget(self.backspaceButton, 1, 0, 1, 2)
|
|
mainLayout.addWidget(self.clearButton, 1, 2, 1, 2)
|
|
mainLayout.addWidget(self.clearAllButton, 1, 4, 1, 2)
|
|
|
|
mainLayout.addWidget(self.clearMemoryButton, 2, 0)
|
|
mainLayout.addWidget(self.readMemoryButton, 3, 0)
|
|
mainLayout.addWidget(self.setMemoryButton, 4, 0)
|
|
mainLayout.addWidget(self.addToMemoryButton, 5, 0)
|
|
|
|
for i in range(1, Calculator.NumDigitButtons):
|
|
row = ((9 - i) / 3) + 2
|
|
column = ((i - 1) % 3) + 1
|
|
mainLayout.addWidget(self.digitButtons[i], row, column)
|
|
|
|
mainLayout.addWidget(self.digitButtons[0], 5, 1)
|
|
mainLayout.addWidget(self.pointButton, 5, 2)
|
|
mainLayout.addWidget(self.changeSignButton, 5, 3)
|
|
|
|
mainLayout.addWidget(self.divisionButton, 2, 4)
|
|
mainLayout.addWidget(self.timesButton, 3, 4)
|
|
mainLayout.addWidget(self.minusButton, 4, 4)
|
|
mainLayout.addWidget(self.plusButton, 5, 4)
|
|
|
|
mainLayout.addWidget(self.squareRootButton, 2, 5)
|
|
mainLayout.addWidget(self.powerButton, 3, 5)
|
|
mainLayout.addWidget(self.reciprocalButton, 4, 5)
|
|
mainLayout.addWidget(self.equalButton, 5, 5)
|
|
self.setLayout(mainLayout)
|
|
|
|
self.setWindowTitle("Calculator")
|
|
|
|
def digitClicked(self):
|
|
clickedButton = self.sender()
|
|
digitValue = int(clickedButton.text())
|
|
|
|
if self.display.text() == '0' and digitValue == 0.0:
|
|
return
|
|
|
|
if self.waitingForOperand:
|
|
self.display.clear()
|
|
self.waitingForOperand = False
|
|
|
|
self.display.setText(self.display.text() + str(digitValue))
|
|
|
|
def unaryOperatorClicked(self):
|
|
clickedButton = self.sender()
|
|
clickedOperator = clickedButton.text()
|
|
operand = float(self.display.text())
|
|
|
|
if clickedOperator == "Sqrt":
|
|
if operand < 0.0:
|
|
self.abortOperation()
|
|
return
|
|
|
|
result = math.sqrt(operand)
|
|
elif clickedOperator == u"x\N{SUPERSCRIPT TWO}":
|
|
result = math.pow(operand, 2.0)
|
|
elif clickedOperator == "1/x":
|
|
if operand == 0.0:
|
|
self.abortOperation()
|
|
return
|
|
|
|
result = 1.0 / operand
|
|
|
|
self.display.setText(str(result))
|
|
self.waitingForOperand = True
|
|
|
|
def additiveOperatorClicked(self):
|
|
clickedButton = self.sender()
|
|
clickedOperator = clickedButton.text()
|
|
operand = float(self.display.text())
|
|
|
|
if self.pendingMultiplicativeOperator:
|
|
if not self.calculate(operand, self.pendingMultiplicativeOperator):
|
|
self.abortOperation()
|
|
return
|
|
|
|
self.display.setText(str(self.factorSoFar))
|
|
operand = self.factorSoFar
|
|
self.factorSoFar = 0.0
|
|
self.pendingMultiplicativeOperator = ''
|
|
|
|
if self.pendingAdditiveOperator:
|
|
if not self.calculate(operand, self.pendingAdditiveOperator):
|
|
self.abortOperation()
|
|
return
|
|
|
|
self.display.setText(str(self.sumSoFar))
|
|
else:
|
|
self.sumSoFar = operand
|
|
|
|
self.pendingAdditiveOperator = clickedOperator
|
|
self.waitingForOperand = True
|
|
|
|
def multiplicativeOperatorClicked(self):
|
|
clickedButton = self.sender()
|
|
clickedOperator = clickedButton.text()
|
|
operand = float(self.display.text())
|
|
|
|
if self.pendingMultiplicativeOperator:
|
|
if not self.calculate(operand, self.pendingMultiplicativeOperator):
|
|
self.abortOperation()
|
|
return
|
|
|
|
self.display.setText(str(self.factorSoFar))
|
|
else:
|
|
self.factorSoFar = operand
|
|
|
|
self.pendingMultiplicativeOperator = clickedOperator
|
|
self.waitingForOperand = True
|
|
|
|
def equalClicked(self):
|
|
operand = float(self.display.text())
|
|
|
|
if self.pendingMultiplicativeOperator:
|
|
if not self.calculate(operand, self.pendingMultiplicativeOperator):
|
|
self.abortOperation()
|
|
return
|
|
|
|
operand = self.factorSoFar
|
|
self.factorSoFar = 0.0
|
|
self.pendingMultiplicativeOperator = ''
|
|
|
|
if self.pendingAdditiveOperator:
|
|
if not self.calculate(operand, self.pendingAdditiveOperator):
|
|
self.abortOperation()
|
|
return
|
|
|
|
self.pendingAdditiveOperator = ''
|
|
else:
|
|
self.sumSoFar = operand
|
|
|
|
self.display.setText(str(self.sumSoFar))
|
|
self.sumSoFar = 0.0
|
|
self.waitingForOperand = True
|
|
|
|
def pointClicked(self):
|
|
if self.waitingForOperand:
|
|
self.display.setText('0')
|
|
|
|
if "." not in self.display.text():
|
|
self.display.setText(self.display.text() + ".")
|
|
|
|
self.waitingForOperand = False
|
|
|
|
def changeSignClicked(self):
|
|
text = self.display.text()
|
|
value = float(text)
|
|
|
|
if value > 0.0:
|
|
text = "-" + text
|
|
elif value < 0.0:
|
|
text = text[1:]
|
|
|
|
self.display.setText(text)
|
|
|
|
def backspaceClicked(self):
|
|
if self.waitingForOperand:
|
|
return
|
|
|
|
text = self.display.text()[:-1]
|
|
if not text:
|
|
text = '0'
|
|
self.waitingForOperand = True
|
|
|
|
self.display.setText(text)
|
|
|
|
def clear(self):
|
|
if self.waitingForOperand:
|
|
return
|
|
|
|
self.display.setText('0')
|
|
self.waitingForOperand = True
|
|
|
|
def clearAll(self):
|
|
self.sumSoFar = 0.0
|
|
self.factorSoFar = 0.0
|
|
self.pendingAdditiveOperator = ''
|
|
self.pendingMultiplicativeOperator = ''
|
|
self.display.setText('0')
|
|
self.waitingForOperand = True
|
|
|
|
def clearMemory(self):
|
|
self.sumInMemory = 0.0
|
|
|
|
def readMemory(self):
|
|
self.display.setText(str(self.sumInMemory))
|
|
self.waitingForOperand = True
|
|
|
|
def setMemory(self):
|
|
self.equalClicked()
|
|
self.sumInMemory = float(self.display.text())
|
|
|
|
def addToMemory(self):
|
|
self.equalClicked()
|
|
self.sumInMemory += float(self.display.text())
|
|
|
|
def createButton(self, text, member):
|
|
button = Button(text)
|
|
button.clicked.connect(member)
|
|
return button
|
|
|
|
def abortOperation(self):
|
|
self.clearAll()
|
|
self.display.setText("####")
|
|
|
|
def calculate(self, rightOperand, pendingOperator):
|
|
if pendingOperator == "+":
|
|
self.sumSoFar += rightOperand
|
|
elif pendingOperator == "-":
|
|
self.sumSoFar -= rightOperand
|
|
elif pendingOperator == u"\N{MULTIPLICATION SIGN}":
|
|
self.factorSoFar *= rightOperand
|
|
elif pendingOperator == u"\N{DIVISION SIGN}":
|
|
if rightOperand == 0.0:
|
|
return False
|
|
|
|
self.factorSoFar /= rightOperand
|
|
|
|
return True
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
import sys
|
|
|
|
app = QApplication(sys.argv)
|
|
calc = Calculator()
|
|
calc.show()
|
|
sys.exit(app.exec_())
|