БлогNot. QT: калькулятор "как в Windows"

QT: калькулятор "как в Windows"

Приложение QT5 практически копирует стандартный калькулятор Windows XP в версии "Вид" - "Обычный", только оно написано лучше, чем вот этот пример.

Не хватает работы с клавиатурой, добавьте её из предыдущей заметки.

Вот внешний вид обеих программ, а код приводится ниже, понадобилось в учебных целях.

Файл button.h
#ifndef BUTTON_H
#define BUTTON_H

#include <QToolButton>

class Button : public QToolButton {
Q_OBJECT
 public:
  Button(const QString &text, const QColor &color, QWidget *parent = 0);
  QSize sizeHint() const;
};
#endif
Файл button.cpp
#include <QtGui>
#include "button.h"

Button::Button(const QString &text, const QColor &color, QWidget *parent) : QToolButton(parent) {
 setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
 setText(text);
 QPalette newPalette = palette();
 newPalette.setColor(QPalette::Button, color);
 setPalette(newPalette);
}

QSize Button::sizeHint() const {
 QSize size = QToolButton::sizeHint();
 size.rheight() += 20;
 size.rwidth() = qMax(size.width(), size.height());
 return size;
}
Файл calculator.h
#ifndef CALCULATOR_H
#define CALCULATOR_H

#include <QDialog>

class QLineEdit;
class Button;

class Calculator : public QDialog {
 Q_OBJECT
public:
 Calculator(QWidget *parent = 0);
protected:
 bool eventFilter(QObject *target, QEvent *event);
private slots:
 void digitClicked();
 void unaryOperatorClicked();
 void additiveOperatorClicked();
 void multiplicativeOperatorClicked();
 void equalClicked();
 void pointClicked();
 void changeSignClicked();
 void backspaceClicked();
 void clear();
 void clearAll();
 void clearMemory();
 void readMemory();
 void setMemory();
 void addToMemory();

private:
 Button *createButton (const QString &text, const QColor &color, const char *member);
 void abortOperation();
 bool calculate (double rightOperand, const QString &pendingOperator);

 double sumInMemory;
 double sumSoFar;
 double factorSoFar;
 QString pendingAdditiveOperator;
 QString pendingMultiplicativeOperator;
 bool waitingForOperand;

 QLineEdit *display;

 enum { NumDigitButtons = 10 };
 Button *digitButtons[NumDigitButtons];

 Button *pointButton;
 Button *changeSignButton;
 Button *backspaceButton;
 Button *clearButton;
 Button *clearAllButton;
 Button *clearMemoryButton;
 Button *readMemoryButton;
 Button *setMemoryButton;
 Button *addToMemoryButton;

 Button *divisionButton;
 Button *timesButton;
 Button *minusButton;
 Button *plusButton;
 Button *squareRootButton;
 Button *powerButton;
 Button *reciprocalButton;
 Button *equalButton;
};

#endif
Файл calculator.cpp
#include <QtWidgets>
#include <math.h>
#include "button.h"
#include "calculator.h"

Calculator::Calculator(QWidget *parent) : QDialog(parent) {
 sumInMemory = 0.0;
 sumSoFar = 0.0;
 factorSoFar = 0.0;
 waitingForOperand = true;

 display = new QLineEdit("0");
 display->setReadOnly(true);
 display->setAlignment(Qt::AlignRight);
 display->setMaxLength(15);
 display->installEventFilter(this);

 QFont font = display->font();
 font.setPointSize(font.pointSize() + 8);
 display->setFont(font);

 QColor digitColor(150, 205, 205);
 QColor backspaceColor(225, 185, 135);
 QColor memoryColor(100, 155, 155);
 QColor operatorColor(155, 175, 195);

 for (int i = 0; i < NumDigitButtons; ++i) {
  digitButtons[i] = createButton(QString::number(i), digitColor, SLOT(digitClicked()));
 }

 pointButton = createButton(tr("."), digitColor, SLOT(pointClicked()));
 changeSignButton = createButton(tr("+/-"), digitColor, SLOT(changeSignClicked()));
 backspaceButton = createButton(tr("Bksp"), backspaceColor, SLOT(backspaceClicked()));
 clearButton = createButton(tr("Clear"), backspaceColor, SLOT(clear()));
 clearAllButton = createButton(tr("Clear All"), backspaceColor.light(120), SLOT(clearAll()));
 clearMemoryButton = createButton(tr("MC"), memoryColor, SLOT(clearMemory()));
 readMemoryButton = createButton(tr("MR"), memoryColor, SLOT(readMemory()));
 setMemoryButton = createButton(tr("MS"), memoryColor, SLOT(setMemory()));
 addToMemoryButton = createButton(tr("M+"), memoryColor, SLOT(addToMemory()));
 divisionButton = createButton(tr("/"), operatorColor, SLOT(multiplicativeOperatorClicked()));
 timesButton = createButton(tr("*"), operatorColor, SLOT(multiplicativeOperatorClicked()));
 minusButton = createButton(tr("-"), operatorColor, SLOT(additiveOperatorClicked()));
 plusButton = createButton(tr("+"), operatorColor, SLOT(additiveOperatorClicked()));
 squareRootButton = createButton(tr("Sqrt"), operatorColor, SLOT(unaryOperatorClicked()));
 powerButton = createButton(tr("%"), operatorColor, SLOT(unaryOperatorClicked()));
 reciprocalButton = createButton(tr("1/x"), operatorColor, SLOT(unaryOperatorClicked()));
 equalButton = createButton(tr("="), operatorColor.light(120), SLOT(equalClicked()));

 QGridLayout *mainLayout = new QGridLayout;
 mainLayout->setSizeConstraint(QLayout::SetFixedSize);

 mainLayout->addWidget(display, 0, 0, 1, 6);
 mainLayout->addWidget(backspaceButton, 1, 0, 1, 2);
 mainLayout->addWidget(clearButton, 1, 2, 1, 2);
 mainLayout->addWidget(clearAllButton, 1, 4, 1, 2);

 mainLayout->addWidget(clearMemoryButton, 2, 0);
 mainLayout->addWidget(readMemoryButton, 3, 0);
 mainLayout->addWidget(setMemoryButton, 4, 0);
 mainLayout->addWidget(addToMemoryButton, 5, 0);

 for (int i = 1; i < NumDigitButtons; ++i) {
  int row = ((9 - i) / 3) + 2;
  int column = ((i - 1) % 3) + 1;
  mainLayout->addWidget(digitButtons[i], row, column);
 }

 mainLayout->addWidget(digitButtons[0], 5, 1);
 mainLayout->addWidget(pointButton, 5, 2);
 mainLayout->addWidget(changeSignButton, 5, 3);

 mainLayout->addWidget(divisionButton, 2, 4);
 mainLayout->addWidget(timesButton, 3, 4);
 mainLayout->addWidget(minusButton, 4, 4);
 mainLayout->addWidget(plusButton, 5, 4);

 mainLayout->addWidget(squareRootButton, 2, 5);
 mainLayout->addWidget(powerButton, 3, 5);
 mainLayout->addWidget(reciprocalButton, 4, 5);
 mainLayout->addWidget(equalButton, 5, 5);
 setLayout(mainLayout);

 setWindowTitle(tr("Calculator"));
}

bool Calculator::eventFilter(QObject *target, QEvent *event) {
 if (target == display) {
  if (event->type() == QEvent::MouseButtonPress
  || event->type() == QEvent::MouseButtonDblClick
  || event->type() == QEvent::MouseButtonRelease
  || event->type() == QEvent::ContextMenu) {
   QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
   if (mouseEvent->buttons() & Qt::LeftButton) {
    QPalette newPalette = palette();
    newPalette.setColor(QPalette::Base, display->palette().color(QPalette::Text));
    newPalette.setColor(QPalette::Text, display->palette().color(QPalette::Base));
    display->setPalette(newPalette);
   }
   else {
    display->setPalette(palette());
   }
   return true;
  }
 }
 return QDialog::eventFilter(target, event);
}

void Calculator::digitClicked() {
 Button *clickedButton = qobject_cast<Button *>(sender());
 int digitValue = clickedButton->text().toInt();
 if (display->text() == "0" && digitValue == 0.0) return;
 if (waitingForOperand) {
  display->clear();
  waitingForOperand = false;
 }
 display->setText(display->text() + QString::number(digitValue));
}

void Calculator::unaryOperatorClicked() {
 Button *clickedButton = qobject_cast<Button *>(sender());
 QString clickedOperator = clickedButton->text();
 double operand = display->text().toDouble();
 double result = 0.0;

 if (clickedOperator == tr("Sqrt")) {
  if (operand < 0.0) {
   abortOperation();
   return;
  }
  result = sqrt(operand);
 }
 else if (clickedOperator == tr("%")) {
  result = pow(operand, 2.0);
 }
 else if (clickedOperator == tr("1/x")) {
  if (operand == 0.0) {
   abortOperation();
   return;
  }
  result = 1.0 / operand;
 }
 display->setText(QString::number(result));
 waitingForOperand = true;
}

void Calculator::additiveOperatorClicked() {
 Button *clickedButton = qobject_cast<Button *>(sender());
 QString clickedOperator = clickedButton->text();
 double operand = display->text().toDouble();

 if (!pendingMultiplicativeOperator.isEmpty()) {
  if (!calculate(operand, pendingMultiplicativeOperator)) {
   abortOperation();
   return;
  }
  display->setText(QString::number(factorSoFar));
  operand = factorSoFar;
  factorSoFar = 0.0;
  pendingMultiplicativeOperator.clear();
 }

 if (!pendingAdditiveOperator.isEmpty()) {
  if (!calculate(operand, pendingAdditiveOperator)) {
   abortOperation();
   return;
  }
  display->setText(QString::number(sumSoFar));
 }
 else {
  sumSoFar = operand;
 }

 pendingAdditiveOperator = clickedOperator;
 waitingForOperand = true;
}

void Calculator::multiplicativeOperatorClicked() {
 Button *clickedButton = qobject_cast<Button *>(sender());
 QString clickedOperator = clickedButton->text();
 double operand = display->text().toDouble();

 if (!pendingMultiplicativeOperator.isEmpty()) {
  if (!calculate(operand, pendingMultiplicativeOperator)) {
   abortOperation();
   return;
  }
  display->setText(QString::number(factorSoFar));
 }
 else {
  factorSoFar = operand;
 }

 pendingMultiplicativeOperator = clickedOperator;
 waitingForOperand = true;
}

void Calculator::equalClicked() {
 double operand = display->text().toDouble();

 if (!pendingMultiplicativeOperator.isEmpty()) {
  if (!calculate(operand, pendingMultiplicativeOperator)) {
   abortOperation();
   return;
  }
  operand = factorSoFar;
  factorSoFar = 0.0;
  pendingMultiplicativeOperator.clear();
 }
 if (!pendingAdditiveOperator.isEmpty()) {
  if (!calculate(operand, pendingAdditiveOperator)) {
   abortOperation();
   return;
  }
  pendingAdditiveOperator.clear();
 }
 else {
  sumSoFar = operand;
 }

 display->setText(QString::number(sumSoFar));
 sumSoFar = 0.0;
 waitingForOperand = true;
}

void Calculator::pointClicked() {
 if (waitingForOperand) display->setText("0");
 if (!display->text().contains(".")) display->setText(display->text() + tr("."));
 waitingForOperand = false;
}

void Calculator::changeSignClicked() {
 QString text = display->text();
 double value = text.toDouble();
 if (value > 0.0) text.prepend(tr("-"));
 else if (value < 0.0) text.remove(0, 1);
 display->setText(text);
}

void Calculator::backspaceClicked() {
 if (waitingForOperand) return;

 QString text = display->text();
 text.chop(1);
 if (text.isEmpty()) {
  text = "0";
  waitingForOperand = true;
 }
 display->setText(text);
}

void Calculator::clear() {
 if (waitingForOperand) return;
 display->setText("0");
 waitingForOperand = true;
}

void Calculator::clearAll() {
 sumSoFar = 0.0;
 factorSoFar = 0.0;
 pendingAdditiveOperator.clear();
 pendingMultiplicativeOperator.clear();
 display->setText("0");
 waitingForOperand = true;
}

void Calculator::clearMemory() {
 sumInMemory = 0.0;
}

void Calculator::readMemory() {
 display->setText(QString::number(sumInMemory));
 waitingForOperand = true;
}

void Calculator::setMemory() {
 equalClicked();
 sumInMemory = display->text().toDouble();
}

void Calculator::addToMemory() {
 equalClicked();
 sumInMemory += display->text().toDouble();
}

Button *Calculator::createButton(const QString &text, const QColor &color, const char *member) {
 Button *button = new Button(text, color);
 connect(button, SIGNAL(clicked()), this, member);
 return button;
}

void Calculator::abortOperation() {
 clearAll();
 display->setText(tr("####"));
}

bool Calculator::calculate(double rightOperand, const QString &pendingOperator) {
 if (pendingOperator == tr("+")) sumSoFar += rightOperand;
 else if (pendingOperator == tr("-")) sumSoFar -= rightOperand;
 else if (pendingOperator == tr("*")) factorSoFar *= rightOperand;
 else if (pendingOperator == tr("/")) {
  if (rightOperand == 0.0) return false;
  factorSoFar /= rightOperand;
 }
 return true;
}
Файл main.cpp
#include <QApplication>

#include "calculator.h"

int main(int argc, char *argv[]) {
 QApplication app(argc, argv);
 Calculator calc;
 return calc.exec();
}

Надеюсь, этот листинг хорошо иллюстрирует прелесть QT :)

 Скачать этот проект QT5 в архиве .zip, развернуть, не создавая новой папки (5 Кб)

18.04.2015, 22:47 [12692 просмотра]


теги: учебное c++ qt

показать комментарии (2)