Files
cursopython2023/aula202-calculadora/buttons.py

162 lines
4.7 KiB
Python

import math
from typing import TYPE_CHECKING
from PySide6.QtCore import Slot
from PySide6.QtWidgets import QGridLayout, QPushButton
from utils import isEmpty, isNumOrDot, isValidNumber
from variables import MEDIUM_FONT_SIZE
if TYPE_CHECKING:
from display import Display
from info import Info
class Button(QPushButton):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.configStyle()
def configStyle(self):
font = self.font()
font.setPixelSize(MEDIUM_FONT_SIZE)
self.setFont(font)
self.setMinimumSize(75, 75)
class ButtonsGrid(QGridLayout):
def __init__(
self, display: 'Display', info: 'Info', *args, **kwargs
) -> None:
super().__init__(*args, **kwargs)
self._gridMask = [
['C', 'D', '^', '/'],
['7', '8', '9', '*'],
['4', '5', '6', '-'],
['1', '2', '3', '+'],
['', '0', '.', '='],
]
self.display = display
self.info = info
self._equation = ''
self._equationInitialValue = 'Sua conta'
self._left = None
self._right = None
self._op = None
self.equation = self._equationInitialValue
self._makeGrid()
@property
def equation(self):
return self._equation
@equation.setter
def equation(self, value):
self._equation = value
self.info.setText(value)
def _makeGrid(self):
for rowNumber, rowData in enumerate(self._gridMask):
for colNumber, buttonText in enumerate(rowData):
button = Button(buttonText)
if not isNumOrDot(buttonText) and not isEmpty(buttonText):
button.setProperty('cssClass', 'specialButton')
self._configSpecialButton(button)
self.addWidget(button, rowNumber, colNumber)
slot = self._makeSlot(self._insertButtonTextToDisplay, button)
self._connectButtonClicked(button, slot)
def _connectButtonClicked(self, button, slot):
button.clicked.connect(slot) # type: ignore
def _configSpecialButton(self, button):
text = button.text()
if text == 'C':
self._connectButtonClicked(button, self._clear)
if text in 'D':
self._connectButtonClicked(button, self.display.backspace)
if text in '+-/*^':
self._connectButtonClicked(
button,
self._makeSlot(self._operatorClicked, button)
)
if text in '=':
self._connectButtonClicked(button, self._eq)
def _makeSlot(self, func, *args, **kwargs):
@ Slot(bool)
def realSlot(_):
func(*args, **kwargs)
return realSlot
def _insertButtonTextToDisplay(self, button):
buttonText = button.text()
newDisplayValue = self.display.text() + buttonText
if not isValidNumber(newDisplayValue):
return
self.display.insert(buttonText)
def _clear(self):
self._left = None
self._right = None
self._op = None
self.equation = self._equationInitialValue
self.display.clear()
def _operatorClicked(self, button):
buttonText = button.text() # +-/* (etc...)
displayText = self.display.text() # Deverá ser meu número _left
self.display.clear() # Limpa o display
# Se a pessoa clicou no operador sem
# configurar qualquer número
if not isValidNumber(displayText) and self._left is None:
print('Não tem nada para colocar no valor da esquerda')
return
# Se houver algo no número da esquerda,
# não fazemos nada. Aguardaremos o número da direita.
if self._left is None:
self._left = float(displayText)
self._op = buttonText
self.equation = f'{self._left} {self._op} ??'
def _eq(self):
displayText = self.display.text()
if not isValidNumber(displayText):
print('Sem nada para a direita')
return
self._right = float(displayText)
self.equation = f'{self._left} {self._op} {self._right}'
result = 'error'
try:
if '^' in self.equation and isinstance(self._left, float):
result = math.pow(self._left, self._right)
else:
result = eval(self.equation)
except ZeroDivisionError:
print('Zero Division Error')
except OverflowError:
print('Número muito grande')
self.display.clear()
self.info.setText(f'{self.equation} = {result}')
self._left = result
self._right = None
if result == 'error':
self._left = None