Как заставить минус работать как операцию вычитания, а не как знак на PythonQT?
В моем калькуляторе не так работает вычитание. При нажатии на знак «-» число становится отрицательным, и должно происходить вычитание.
Нужно за "-" вычитать, а кнопку "+/-" менять знак на противоположный.
Видео на котором видно проблему.
main.py
import sys
from typing import Union, Optional
from operator import add, sub, mul, truediv
from PySide6.QtWidgets import QApplication, QMainWindow
from PySide6.QtGui import QFontDatabase
from design import Ui_MainWindow
import config
operations = {
'+': add,
'-': sub,
'×': mul,
'/': truediv
}
class Calculator(QMainWindow):
def __init__(self):
super(Calculator, self).__init__()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.setWindowTitle("OneCalculator")
self.entry = self.ui.le_entry
self.temp = self.ui.lbl_temp
self.entry_max_len = self.entry.maxLength()
QFontDatabase.addApplicationFont("ui/fonts/Intro.ttf")
for btn in config.DIGIT_BUTTONS:
getattr(self.ui, btn).clicked.connect(self.add_digit)
self.ui.btn_calc.clicked.connect(self.calculate)
for btn in config.MATH_OPERATIONS:
getattr(self.ui, btn).clicked.connect(self.math_operation)
self.ui.btn_clear.clicked.connect(self.clear_all)
self.ui.btn_ce.clicked.connect(self.clear_entry)
self.ui.btn_point.clicked.connect(self.add_point)
self.ui.btn_neg.clicked.connect(self.negate)
self.ui.btn_backspace.clicked.connect(self.backspace)
def add_digit(self) -> None:
self.remove_error()
self.clear_temp_if_equality()
btn = self.sender()
if btn.objectName() in config.DIGIT_BUTTONS:
if self.entry.text() == '0':
self.entry.setText(btn.text())
else:
self.entry.setText(self.entry.text() + btn.text())
self.adjust_entry_font_size()
def add_point(self) -> None:
self.clear_temp_if_equality()
if '.' not in self.entry.text():
self.entry.setText(self.entry.text() + '.')
self.adjust_entry_font_size()
def avoid_deleting_char_on_negation(self, entry: str) -> None:
if len(entry) == self.entry_max_len + 1 and '-' in entry:
self.entry.setMaxLength(self.entry_max_len + 1)
else:
self.entry.setMaxLength(self.entry_max_len)
def negate(self) -> None:
self.clear_temp_if_equality()
entry = self.ui.le_entry.text()
if '-' not in entry:
if entry != '0':
entry = '-' + entry
else:
entry = entry[1:]
self.avoid_deleting_char_on_negation(entry)
self.entry.setText(entry)
self.adjust_entry_font_size()
def backspace(self) -> None:
self.remove_error()
self.clear_temp_if_equality()
entry = self.entry.text()
if len(entry) != 1:
if len(entry) == 2 and '-' in entry:
self.entry.setText('0')
else:
self.entry.setText(entry[:-1])
else:
self.entry.setText('0')
self.adjust_entry_font_size()
def clear_all(self) -> None:
self.remove_error()
self.entry.setText('0')
self.adjust_entry_font_size()
self.temp.clear()
self.adjust_temp_font_size()
def clear_entry(self) -> None:
self.remove_error()
self.clear_temp_if_equality()
self.entry.setText('0')
self.adjust_entry_font_size()
def clear_temp_if_equality(self) -> None:
if self.get_math_sign() == '=':
self.temp.clear()
self.adjust_temp_font_size()
@staticmethod
def remove_trailing_zeros(num: Union[float, int, str]) -> str:
n = str(float(num))
return n.replace('.0', '') if n.endswith('.0') else n
def add_temp(self) -> None:
btn = self.sender()
entry = self.remove_trailing_zeros(self.entry.text())
if not self.temp.text() or self.get_math_sign() == '=':
self.ui.lbl_temp.setText(self.ui.le_entry.text() + f' {btn.text()} ')
self.adjust_temp_font_size()
self.entry.setText('0')
self.adjust_entry_font_size()
def get_entry_num(self) -> Union[int, float]:
entry = self.entry.text().strip('.')
return float(entry) if '.' in entry else int(entry)
def get_temp_num(self) -> Union[int, float, None]:
if self.temp.text():
temp = self.temp.text().strip('.').split()[0]
return float(temp) if '.' in temp else int(temp)
def get_math_sign(self) -> Optional[str]:
if self.temp.text():
return self.temp.text().strip('.').split()[-1]
def get_entry_text_width(self) -> int:
return self.entry.fontMetrics().boundingRect(self.entry.text()).width()
def get_temp_text_width(self) -> int:
return self.temp.fontMetrics().boundingRect(self.temp.text()).width()
def calculate(self) -> Optional[str]:
try:
result = self.remove_trailing_zeros(
(operations[self.get_math_sign()](self.get_temp_num(), self.get_entry_num())))
self.temp.setText(self.temp.text() + self.remove_trailing_zeros(self.entry.text()) + ' =')
self.adjust_temp_font_size()
self.entry.setText(result)
self.adjust_entry_font_size()
return result
except KeyError:
pass
except ZeroDivisionError:
self.show_zero_division_error()
def show_zero_division_error(self) -> None:
if self.get_temp_num() == 0:
self.show_error(config.ERROR_UNDEFINED)
else:
self.show_error(config.ERROR_ZERO_DIV)
def math_operation(self) -> None:
btn = self.sender()
if not self.temp.text():
self.add_temp()
else:
if self.get_math_sign() != btn.text():
if self.get_math_sign() == '=':
self.add_temp()
else:
self.replace_temp_sign()
else:
try:
self.temp.setText(self.calculate() + f' {btn.text()} ')
except TypeError:
pass
self.adjust_temp_font_size()
def replace_temp_sign(self) -> None:
btn = self.sender()
self.temp.setText(self.temp.text()[:-2] + f'{btn.text()} ')
def show_error(self, text: str) -> None:
self.entry.setMaxLength(len(text))
self.entry.setText(text)
self.adjust_entry_font_size()
self.disable_buttons(True)
def remove_error(self) -> None:
if self.entry.text() in (config.ERROR_UNDEFINED, config.ERROR_ZERO_DIV):
self.entry.setMaxLength(self.entry_max_len)
self.entry.setText('0')
self.adjust_entry_font_size()
self.disable_buttons(False)
def disable_buttons(self, disable: bool) -> None:
for btn in config.BUTTONS_TO_DISABLE:
getattr(self.ui, btn).setDisabled(disable)
color = 'color: #E6E6E6;' if disable else 'color: white;'
self.change_buttons_color(color)
def change_buttons_color(self, css_color: str) -> None:
for btn in config.BUTTONS_TO_DISABLE:
getattr(self.ui, btn).setStyleSheet(css_color)
def adjust_entry_font_size(self) -> None:
font_size = config.DEFAULT_ENTRY_FONT_SIZE
while self.get_entry_text_width() > self.entry.width() - 15:
font_size -= 1
self.entry.setStyleSheet(f'font-size: {font_size}pt; border: none;')
font_size = 1
while self.get_entry_text_width() < self.entry.width() - 60:
font_size += 1
if font_size > config.DEFAULT_ENTRY_FONT_SIZE:
break
self.entry.setStyleSheet(f'font-size: {font_size}pt; border: none;')
def adjust_temp_font_size(self) -> None:
font_size = config.DEFAULT_FONT_SIZE
while self.get_temp_text_width() > self.temp.width() - 10:
font_size -= 1
self.temp.setStyleSheet(f'font-size: {font_size}pt; color: #E6E6E6;')
font_size = 1
while self.get_temp_text_width() < self.temp.width() - 60:
font_size += 1
if font_size > config.DEFAULT_FONT_SIZE:
break
self.temp.setStyleSheet(f'font-size: {font_size}pt; color: #E6E6E6;')
def resizeEvent(self, event) -> None:
self.adjust_entry_font_size()
self.adjust_temp_font_size()
if __name__ == "__main__":
app = QApplication(sys.argv)
window = Calculator()
window.show()
sys.exit(app.exec())
design.py:
from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
QMetaObject, QObject, QPoint, QRect,
QSize, QTime, QUrl, Qt)
from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
QFont, QFontDatabase, QGradient, QIcon,
QImage, QKeySequence, QLinearGradient, QPainter,
QPalette, QPixmap, QRadialGradient, QTransform)
from PySide6.QtWidgets import (QApplication, QGridLayout, QLabel, QLineEdit,
QMainWindow, QPushButton, QSizePolicy, QVBoxLayout,
QWidget)
import files_rc
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
if not MainWindow.objectName():
MainWindow.setObjectName(u"MainWindow")
MainWindow.resize(300, 500)
MainWindow.setMinimumSize(QSize(300, 500))
icon = QIcon()
icon.addFile(u":/icons/calculator.png", QSize(), QIcon.Normal, QIcon.Off)
MainWindow.setWindowIcon(icon)
MainWindow.setStyleSheet(u"QLabel {\n"
" color: #E6E6E6;\n"
"}\n"
"\n"
"QWidget {\n"
" color: white;\n"
" background-color: #7a7a7a;\n"
" font-family: Intro;\n"
" font-size: 16pt;\n"
" font-weight: 600;\n"
"}\n"
"\n"
"QPushButton {\n"
" background-color: transparent;\n"
" border: none;\n"
"}\n"
"\n"
"QPushButton:hover {\n"
" background-color: #666;\n"
"}\n"
"\n"
"QPushButton:pressed {\n"
" background-color: #424242;\n"
"}")
self.centralwidget = QWidget(MainWindow)
self.centralwidget.setObjectName(u"centralwidget")
self.centralwidget.setStyleSheet(u"")
self.verticalLayout = QVBoxLayout(self.centralwidget)
self.verticalLayout.setObjectName(u"verticalLayout")
self.lbl_temp = QLabel(self.centralwidget)
self.lbl_temp.setObjectName(u"lbl_temp")
sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Maximum)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.lbl_temp.sizePolicy().hasHeightForWidth())
self.lbl_temp.setSizePolicy(sizePolicy)
font = QFont()
font.setFamilies([u"Intro"])
font.setPointSize(16)
font.setBold(True)
self.lbl_temp.setFont(font)
self.lbl_temp.setStyleSheet(u"color: #E6E6E6;")
self.lbl_temp.setAlignment(Qt.AlignRight|Qt.AlignTrailing|Qt.AlignVCenter)
self.verticalLayout.addWidget(self.lbl_temp)
self.le_entry = QLineEdit(self.centralwidget)
self.le_entry.setObjectName(u"le_entry")
sizePolicy1 = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Maximum)
sizePolicy1.setHorizontalStretch(0)
sizePolicy1.setVerticalStretch(0)
sizePolicy1.setHeightForWidth(self.le_entry.sizePolicy().hasHeightForWidth())
self.le_entry.setSizePolicy(sizePolicy1)
font1 = QFont()
font1.setFamilies([u"Intro"])
font1.setPointSize(40)
font1.setBold(True)
self.le_entry.setFont(font1)
self.le_entry.setCursor(QCursor(Qt.IBeamCursor))
self.le_entry.setStyleSheet(u"font-size: 40pt;\n"
"border: none;\n"
"color: #white;")
self.le_entry.setMaxLength(10)
self.le_entry.setAlignment(Qt.AlignRight|Qt.AlignTrailing|Qt.AlignVCenter)
self.le_entry.setReadOnly(True)
self.verticalLayout.addWidget(self.le_entry)
self.layout_buttons = QGridLayout()
self.layout_buttons.setObjectName(u"layout_buttons")
self.btn_7 = QPushButton(self.centralwidget)
self.btn_7.setObjectName(u"btn_7")
sizePolicy2 = QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Expanding)
sizePolicy2.setHorizontalStretch(0)
sizePolicy2.setVerticalStretch(0)
sizePolicy2.setHeightForWidth(self.btn_7.sizePolicy().hasHeightForWidth())
self.btn_7.setSizePolicy(sizePolicy2)
self.btn_7.setFont(font)
self.btn_7.setCursor(QCursor(Qt.PointingHandCursor))
self.layout_buttons.addWidget(self.btn_7, 2, 0, 1, 1)
self.btn_4 = QPushButton(self.centralwidget)
self.btn_4.setObjectName(u"btn_4")
sizePolicy2.setHeightForWidth(self.btn_4.sizePolicy().hasHeightForWidth())
self.btn_4.setSizePolicy(sizePolicy2)
self.btn_4.setFont(font)
self.btn_4.setCursor(QCursor(Qt.PointingHandCursor))
self.layout_buttons.addWidget(self.btn_4, 3, 0, 1, 1)
self.btn_1 = QPushButton(self.centralwidget)
self.btn_1.setObjectName(u"btn_1")
sizePolicy2.setHeightForWidth(self.btn_1.sizePolicy().hasHeightForWidth())
self.btn_1.setSizePolicy(sizePolicy2)
self.btn_1.setFont(font)
self.btn_1.setCursor(QCursor(Qt.PointingHandCursor))
self.layout_buttons.addWidget(self.btn_1, 4, 0, 1, 1)
self.btn_ce = QPushButton(self.centralwidget)
self.btn_ce.setObjectName(u"btn_ce")
sizePolicy2.setHeightForWidth(self.btn_ce.sizePolicy().hasHeightForWidth())
self.btn_ce.setSizePolicy(sizePolicy2)
self.btn_ce.setFont(font)
self.btn_ce.setCursor(QCursor(Qt.PointingHandCursor))
self.layout_buttons.addWidget(self.btn_ce, 1, 1, 1, 1)
self.btn_clear = QPushButton(self.centralwidget)
self.btn_clear.setObjectName(u"btn_clear")
sizePolicy2.setHeightForWidth(self.btn_clear.sizePolicy().hasHeightForWidth())
self.btn_clear.setSizePolicy(sizePolicy2)
self.btn_clear.setFont(font)
self.btn_clear.setCursor(QCursor(Qt.PointingHandCursor))
self.btn_clear.setIconSize(QSize(16, 16))
self.layout_buttons.addWidget(self.btn_clear, 1, 0, 1, 1)
self.btn_sub = QPushButton(self.centralwidget)
self.btn_sub.setObjectName(u"btn_sub")
sizePolicy2.setHeightForWidth(self.btn_sub.sizePolicy().hasHeightForWidth())
self.btn_sub.setSizePolicy(sizePolicy2)
self.btn_sub.setFont(font)
self.btn_sub.setCursor(QCursor(Qt.PointingHandCursor))
self.layout_buttons.addWidget(self.btn_sub, 5, 0, 1, 1)
self.btn_mul = QPushButton(self.centralwidget)
self.btn_mul.setObjectName(u"btn_mul")
sizePolicy2.setHeightForWidth(self.btn_mul.sizePolicy().hasHeightForWidth())
self.btn_mul.setSizePolicy(sizePolicy2)
self.btn_mul.setFont(font)
self.btn_mul.setCursor(QCursor(Qt.PointingHandCursor))
self.layout_buttons.addWidget(self.btn_mul, 2, 3, 1, 1)
self.btn_div = QPushButton(self.centralwidget)
self.btn_div.setObjectName(u"btn_div")
sizePolicy2.setHeightForWidth(self.btn_div.sizePolicy().hasHeightForWidth())
self.btn_div.setSizePolicy(sizePolicy2)
self.btn_div.setFont(font)
self.btn_div.setCursor(QCursor(Qt.PointingHandCursor))
self.layout_buttons.addWidget(self.btn_div, 1, 3, 1, 1)
self.btn_neg = QPushButton(self.centralwidget)
self.btn_neg.setObjectName(u"btn_neg")
sizePolicy2.setHeightForWidth(self.btn_neg.sizePolicy().hasHeightForWidth())
self.btn_neg.setSizePolicy(sizePolicy2)
self.btn_neg.setFont(font)
self.btn_neg.setCursor(QCursor(Qt.PointingHandCursor))
self.layout_buttons.addWidget(self.btn_neg, 3, 3, 1, 1)
self.btn_add = QPushButton(self.centralwidget)
self.btn_add.setObjectName(u"btn_add")
sizePolicy2.setHeightForWidth(self.btn_add.sizePolicy().hasHeightForWidth())
self.btn_add.setSizePolicy(sizePolicy2)
self.btn_add.setFont(font)
self.btn_add.setCursor(QCursor(Qt.PointingHandCursor))
self.layout_buttons.addWidget(self.btn_add, 4, 3, 1, 1)
self.btn_calc = QPushButton(self.centralwidget)
self.btn_calc.setObjectName(u"btn_calc")
sizePolicy2.setHeightForWidth(self.btn_calc.sizePolicy().hasHeightForWidth())
self.btn_calc.setSizePolicy(sizePolicy2)
self.btn_calc.setFont(font)
self.btn_calc.setCursor(QCursor(Qt.PointingHandCursor))
self.layout_buttons.addWidget(self.btn_calc, 5, 3, 1, 1)
self.btn_backspace = QPushButton(self.centralwidget)
self.btn_backspace.setObjectName(u"btn_backspace")
sizePolicy2.setHeightForWidth(self.btn_backspace.sizePolicy().hasHeightForWidth())
self.btn_backspace.setSizePolicy(sizePolicy2)
self.btn_backspace.setFont(font)
self.btn_backspace.setCursor(QCursor(Qt.PointingHandCursor))
icon1 = QIcon()
icon1.addFile(u":/icons/outline_backspace_white_24dp.png", QSize(), QIcon.Normal, QIcon.Off)
self.btn_backspace.setIcon(icon1)
self.btn_backspace.setIconSize(QSize(24, 24))
self.layout_buttons.addWidget(self.btn_backspace, 1, 2, 1, 1)
self.btn_9 = QPushButton(self.centralwidget)
self.btn_9.setObjectName(u"btn_9")
sizePolicy2.setHeightForWidth(self.btn_9.sizePolicy().hasHeightForWidth())
self.btn_9.setSizePolicy(sizePolicy2)
self.btn_9.setFont(font)
self.btn_9.setCursor(QCursor(Qt.PointingHandCursor))
self.layout_buttons.addWidget(self.btn_9, 2, 2, 1, 1)
self.btn_6 = QPushButton(self.centralwidget)
self.btn_6.setObjectName(u"btn_6")
sizePolicy2.setHeightForWidth(self.btn_6.sizePolicy().hasHeightForWidth())
self.btn_6.setSizePolicy(sizePolicy2)
self.btn_6.setFont(font)
self.btn_6.setCursor(QCursor(Qt.PointingHandCursor))
self.layout_buttons.addWidget(self.btn_6, 3, 2, 1, 1)
self.btn_3 = QPushButton(self.centralwidget)
self.btn_3.setObjectName(u"btn_3")
sizePolicy2.setHeightForWidth(self.btn_3.sizePolicy().hasHeightForWidth())
self.btn_3.setSizePolicy(sizePolicy2)
self.btn_3.setFont(font)
self.btn_3.setCursor(QCursor(Qt.PointingHandCursor))
self.layout_buttons.addWidget(self.btn_3, 4, 2, 1, 1)
self.btn_point = QPushButton(self.centralwidget)
self.btn_point.setObjectName(u"btn_point")
sizePolicy2.setHeightForWidth(self.btn_point.sizePolicy().hasHeightForWidth())
self.btn_point.setSizePolicy(sizePolicy2)
self.btn_point.setFont(font)
self.btn_point.setCursor(QCursor(Qt.PointingHandCursor))
self.layout_buttons.addWidget(self.btn_point, 5, 2, 1, 1)
self.btn_8 = QPushButton(self.centralwidget)
self.btn_8.setObjectName(u"btn_8")
sizePolicy2.setHeightForWidth(self.btn_8.sizePolicy().hasHeightForWidth())
self.btn_8.setSizePolicy(sizePolicy2)
self.btn_8.setFont(font)
self.btn_8.setCursor(QCursor(Qt.PointingHandCursor))
self.layout_buttons.addWidget(self.btn_8, 2, 1, 1, 1)
self.btn_5 = QPushButton(self.centralwidget)
self.btn_5.setObjectName(u"btn_5")
sizePolicy2.setHeightForWidth(self.btn_5.sizePolicy().hasHeightForWidth())
self.btn_5.setSizePolicy(sizePolicy2)
self.btn_5.setFont(font)
self.btn_5.setCursor(QCursor(Qt.PointingHandCursor))
self.layout_buttons.addWidget(self.btn_5, 3, 1, 1, 1)
self.btn_2 = QPushButton(self.centralwidget)
self.btn_2.setObjectName(u"btn_2")
sizePolicy2.setHeightForWidth(self.btn_2.sizePolicy().hasHeightForWidth())
self.btn_2.setSizePolicy(sizePolicy2)
self.btn_2.setFont(font)
self.btn_2.setCursor(QCursor(Qt.PointingHandCursor))
self.layout_buttons.addWidget(self.btn_2, 4, 1, 1, 1)
self.btn_0 = QPushButton(self.centralwidget)
self.btn_0.setObjectName(u"btn_0")
sizePolicy2.setHeightForWidth(self.btn_0.sizePolicy().hasHeightForWidth())
self.btn_0.setSizePolicy(sizePolicy2)
self.btn_0.setFont(font)
self.btn_0.setCursor(QCursor(Qt.PointingHandCursor))
self.btn_0.setIconSize(QSize(16, 16))
self.layout_buttons.addWidget(self.btn_0, 5, 1, 1, 1)
self.verticalLayout.addLayout(self.layout_buttons)
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QMetaObject.connectSlotsByName(MainWindow)
# setupUi
def retranslateUi(self, MainWindow):
MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"OneCalculator", None))
self.lbl_temp.setText(QCoreApplication.translate("MainWindow", u"", None))
self.le_entry.setText(QCoreApplication.translate("MainWindow", u"0", None))
self.btn_7.setText(QCoreApplication.translate("MainWindow", u"7", None))
self.btn_7.setShortcut(QCoreApplication.translate("MainWindow", u"7", None))
self.btn_4.setText(QCoreApplication.translate("MainWindow", u"4", None))
self.btn_4.setShortcut(QCoreApplication.translate("MainWindow", u"4", None))
self.btn_1.setText(QCoreApplication.translate("MainWindow", u"1", None))
self.btn_1.setShortcut(QCoreApplication.translate("MainWindow", u"1", None))
self.btn_ce.setText(QCoreApplication.translate("MainWindow", u"CE", None))
self.btn_ce.setShortcut(QCoreApplication.translate("MainWindow", u"Del", None))
self.btn_clear.setText(QCoreApplication.translate("MainWindow", u"C", None))
self.btn_sub.setText(QCoreApplication.translate("MainWindow", u"+/-", None))
self.btn_mul.setText(QCoreApplication.translate("MainWindow", u"\u00d7", None))
self.btn_mul.setShortcut(QCoreApplication.translate("MainWindow", u"*", None))
self.btn_div.setText(QCoreApplication.translate("MainWindow", u"/", None))
self.btn_div.setShortcut(QCoreApplication.translate("MainWindow", u"/", None))
self.btn_neg.setText(QCoreApplication.translate("MainWindow", u"-", None))
self.btn_neg.setShortcut(QCoreApplication.translate("MainWindow", u"-", None))
self.btn_add.setText(QCoreApplication.translate("MainWindow", u"+", None))
self.btn_add.setShortcut(QCoreApplication.translate("MainWindow", u"+", None))
self.btn_calc.setText(QCoreApplication.translate("MainWindow", u"=", None))
self.btn_calc.setShortcut(QCoreApplication.translate("MainWindow", u"=", None))
self.btn_backspace.setText("")
self.btn_backspace.setShortcut(QCoreApplication.translate("MainWindow", u"Backspace", None))
self.btn_9.setText(QCoreApplication.translate("MainWindow", u"9", None))
self.btn_9.setShortcut(QCoreApplication.translate("MainWindow", u"9", None))
self.btn_6.setText(QCoreApplication.translate("MainWindow", u"6", None))
self.btn_6.setShortcut(QCoreApplication.translate("MainWindow", u"6", None))
self.btn_3.setText(QCoreApplication.translate("MainWindow", u"3", None))
self.btn_3.setShortcut(QCoreApplication.translate("MainWindow", u"3", None))
self.btn_point.setText(QCoreApplication.translate("MainWindow", u".", None))
self.btn_point.setShortcut(QCoreApplication.translate("MainWindow", u".", None))
self.btn_8.setText(QCoreApplication.translate("MainWindow", u"8", None))
self.btn_8.setShortcut(QCoreApplication.translate("MainWindow", u"8", None))
self.btn_5.setText(QCoreApplication.translate("MainWindow", u"5", None))
self.btn_5.setShortcut(QCoreApplication.translate("MainWindow", u"5", None))
self.btn_2.setText(QCoreApplication.translate("MainWindow", u"2", None))
self.btn_2.setShortcut(QCoreApplication.translate("MainWindow", u"2", None))
self.btn_0.setText(QCoreApplication.translate("MainWindow", u"0", None))
self.btn_0.setShortcut(QCoreApplication.translate("MainWindow", u"0", None))
config.py
ERROR_ZERO_DIV = 'Division by zero'
ERROR_UNDEFINED = 'Result is undefined'
DEFAULT_FONT_SIZE = 16
DEFAULT_ENTRY_FONT_SIZE = 40
DIGIT_BUTTONS = [f'btn_{num}' for num in range(10)]
MATH_OPERATIONS = ['btn_add', 'btn_sub', 'btn_mul', 'btn_div']
BUTTONS_TO_DISABLE = [
'btn_calc', 'btn_add', 'btn_sub',
'btn_mul', 'btn_div', 'btn_neg', 'btn_point'
]
Ответы (3 шт):
Без воспроизводимого примера ничего сказать не могу.
Пример, ссылку которого я вам предоставил в комментариях, видимо вам не подошел.
Вот вам вариант покруче, попробуйте.
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_())
В результате исследований выяснилось что кнопки +/- и - были перепутаны в разметке:
В функуии retranslateUi заменены строки:
self.btn_sub.setText(QCoreApplication.translate("MainWindow", u"+/-", None))
self.btn_neg.setText(QCoreApplication.translate("MainWindow", u"-", None))
self.btn_neg.setShortcut(QCoreApplication.translate("MainWindow", u"-", None))
на
self.btn_neg.setText(QCoreApplication.translate("MainWindow", u"+/-", None))
self.btn_sub.setText(QCoreApplication.translate("MainWindow", u"-", None))
self.btn_sub.setShortcut(QCoreApplication.translate("MainWindow", u"-", None))
И заменены строки отвечающие за расположение этих кнопок
self.layout_buttons.addWidget(self.btn_sub, 5, 0, 1, 1)
self.layout_buttons.addWidget(self.btn_neg, 3, 3, 1, 1)
на
self.layout_buttons.addWidget(self.btn_sub, 3, 3, 1, 1)
self.layout_buttons.addWidget(self.btn_neg, 5, 0, 1, 1)
Я исправил три строки в вашем коде:
1 . в main.py:
# !!! - btn_neg - negate
# self.ui.btn_neg.clicked.connect(self.negate)
self.ui.btn_sub.clicked.connect(self.negate)
# ------------> ^^^^^^^ <------------------------------------------------- btn_sub !!!
2 . в config.py:
# !!! - MATH_OPERATIONS = ['btn_add', 'btn_sub', 'btn_mul', 'btn_div']
MATH_OPERATIONS = ['btn_add', 'btn_neg', 'btn_mul', 'btn_div']
# ---------------------------> ^^^^^^^ <---------------------------------- btn_neg !!!
3 . в design.py:
замените строку "color: #white;") на строку "color: white;")
main.py:
import sys
from typing import Union, Optional
from operator import add, sub, mul, truediv
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.Qt import *
'''
from PySide6.QtWidgets import QApplication, QMainWindow
from PySide6.QtGui import QFontDatabase
'''
from design import Ui_MainWindow
import config
operations = {
'+': add,
'-': sub,
'×': mul,
'/': truediv
}
class Calculator(QMainWindow):
def __init__(self):
super(Calculator, self).__init__()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.setWindowTitle("OneCalculator")
self.entry = self.ui.le_entry
self.temp = self.ui.lbl_temp
self.entry_max_len = self.entry.maxLength()
QFontDatabase.addApplicationFont("ui/fonts/Intro.ttf")
for btn in q1445887_config.DIGIT_BUTTONS:
getattr(self.ui, btn).clicked.connect(self.add_digit) # цифры
self.ui.btn_calc.clicked.connect(self.calculate) # calculate =
for btn in q1445887_config.MATH_OPERATIONS:
getattr(self.ui, btn).clicked.connect(self.math_operation) # math_operation
self.ui.btn_clear.clicked.connect(self.clear_all)
self.ui.btn_ce.clicked.connect(self.clear_entry)
self.ui.btn_point.clicked.connect(self.add_point)
# !!! - btn_neg - negate
# self.ui.btn_neg.clicked.connect(self.negate)
self.ui.btn_sub.clicked.connect(self.negate)
# ------------> ^^^^^^^ <------------------------------------------------- btn_sub !!!
self.ui.btn_backspace.clicked.connect(self.backspace)
def add_digit(self) -> None:
...
config.py
ERROR_ZERO_DIV = 'Division by zero'
ERROR_UNDEFINED = 'Result is undefined'
DEFAULT_FONT_SIZE = 16
DEFAULT_ENTRY_FONT_SIZE = 40
DIGIT_BUTTONS = [f'btn_{num}' for num in range(10)]
# !!! - MATH_OPERATIONS = ['btn_add', 'btn_sub', 'btn_mul', 'btn_div']
MATH_OPERATIONS = ['btn_add', 'btn_neg', 'btn_mul', 'btn_div']
# ---------------------------> ^^^^^^^ <---------------------------------- btn_neg !!!
BUTTONS_TO_DISABLE = [
'btn_calc', 'btn_add', 'btn_sub',
'btn_mul', 'btn_div', 'btn_neg', 'btn_point'
]


