媒介
QT中实现一个简单的盘算器是一个比较好的练手项目,下面是源码:
Calculator盘算器
计划界面
待实现的界面重要包含两个部门:
输入输出栏通过QLabel类实现,而用户点击按钮通过QPushButton或QToolButton,按钮的布局我们使用网格布局(grid)
随后给整个页面进行垂直布局,并将程度垂直策略设为expanding(巨细跟随程序页面巨细)
再通过qss进行样式表美化,最终效果为:
用户输入的数字会显示在下面的displayLabel中,当点击等号时,结果会被盘算显示到上面的outputLabel中。
程序计划分析
对于整个盘算器的功能,都封装在一个calculator类中;
下面是头文件:
- #ifndef CALCULATOR_H
- #define CALCULATOR_H
- #include "ui_calculator.h"
- #include <QWidget>
- #include <QFile>
- #include <QMessageBox>
- #include <QString>
- #include <QStack>
- #include <QStack>
- #include <QMap>
- #include <cmath>
- #include <QDebug>
- #include <QtMath>
- #include <QRegularExpression>
- #include <QRegularExpressionMatch>
- QT_BEGIN_NAMESPACE
- namespace Ui { class Calculator; }
- QT_END_NAMESPACE
- class Calculator : public QWidget
- {
- Q_OBJECT
- public:
- Calculator(QWidget *parent = nullptr);
- ~Calculator();
- // 加载qss
- void loadStyleSheetFile(const QString &styleSheetFile);
- // 各种按钮点击的槽函数
- void btnNumClicked(double x);
- void btnOperatorClicked(char op);
- void btnCClicked();
- void btnCEClicked();
- void btnBackClicked();
- void btnSquareClicked();
- void btnSqrtClicked();
- void btnSpotClicked();
- void btnFractionClicked();
- void btnPerClicked();
- void btnReverseClicked();
- bool btnEqualClicked();
- private:
- // 初始化以及其他功能
- void initConnections();
- void initMembers();
- bool isPureNumber(const QString& sen);
- // int getDecimalPlaces(const QString &text) const;
- private slots:
- private:
- Ui::Calculator *ui;
- size_t decimalCount;
- double num;
- double decimalPlaces;
- double result;
- char operation;
- QString sentence;
- bool isNewOperation;
- bool isFirstElement;
- bool hasDecimalPoint;
- bool EqualBtnClicked;
- };
- #endif // CALCULATOR_H
复制代码 在创建calculator对象时,对槽函数以及相干变乱进行绑定连接,随后就可以正式编写代码:
代码部门
按钮点击
该槽函数用于当用户点击按钮时的操纵,将用户输入的数字存储到成员变量num中即可,通过判定用户是否点击小数点,进行小数点的统计与显示。
- void Calculator::btnNumClicked(double x)
- {
- if(EqualBtnClicked) {
- sentence = "";
- num = '\0';
- }
- // 处理数字输入
- if (isFirstElement) {
- num = x;
- isFirstElement = false;
- ui->displayLabel->setText(QString::number(num, 'f', decimalCount));
- } else {
- if (hasDecimalPoint) {
- // 处理小数部分
- num += x * decimalPlaces;
- decimalPlaces /= 10; // 减少小数点后面的位数
- decimalCount++;
- qDebug() << "decimalConut: " << decimalCount;
- ui->displayLabel->setText(QString::number(num, 'f', decimalCount));
- } else {
- // 处理整数部分
- num = num * 10 + static_cast<int>(x);
- ui->displayLabel->setText(QString::number(num, 'f', decimalCount));
- }
- }
- }
复制代码 小数点点击
判定用户点击小数点前是否有数字 / 点击过了,随后将标识符设为true
- void Calculator::btnSpotClicked()
- {
- if(isFirstElement || hasDecimalPoint) {
- return;
- }
- hasDecimalPoint = true;
- }
复制代码 操纵符点击
sentence 变量负责存储算式,末了由equal盘算,用户点击操纵符后,会根据情况将操纵符加载到算是后面。
- void Calculator::btnOperatorClicked(char op)
- {
- if(EqualBtnClicked) {
- sentence = "";
- num = '\0';
- }
- // 如果上一次操作后有数字,则将其加入 sentence
- if (!isFirstElement) {
- if ((!sentence.isEmpty() && !sentence.back().isDigit()) || sentence.isEmpty())
- sentence += QString::number(num, 'f', decimalCount);
- qDebug() << "num: " << num;
- num = 0; // 重置 num 以便输入新的数字
- isFirstElement = true; // 标记新的数字输入开始
- }
- // 检查 sentence 是否以运算符结尾
- if (!sentence.isEmpty() && (sentence.endsWith('+') || sentence.endsWith('-') || sentence.endsWith('*') || sentence.endsWith('/'))) {
- // 如果最后一位是运算符,替换运算符
- sentence.chop(1); // 删除最后一个运算符
- }
- // 追加新的运算符
- sentence += op;
- // 更新显示
- ui->outputLabel->setText(sentence);
- ui->displayLabel->setText("");
- size_t tmp = decimalCount;
- initMembers();
- decimalCount = tmp;
- }
复制代码 退格
退格键是对用户当前正在输入的数字进行尾删,根据情况更新num,并重设displayLabel上显示的内容
- void Calculator::btnBackClicked()
- {
- if(EqualBtnClicked) {
- sentence = "";
- num = '\0';
- }
- QString currentText = ui->displayLabel->text(); // 获取当前显示的文本
- if (currentText.isEmpty()) {
- return; // 如果没有文本,直接返回
- }
- // 移除最后一个字符
- currentText.chop(1); // 或者使用 remove() 方法:currentText.remove(currentText.length() - 1, 1);
- // 如果移除后的文本为空,重置显示为 0
- if (currentText.isEmpty()) {
- currentText = "0";
- }
- // 更新显示标签
- ui->displayLabel->setText(currentText);
- // 更新 num 变量
- bool ok;
- num = currentText.toDouble(&ok);
- if (!ok) {
- num = 0; // 如果转换失败,则将 num 设置为 0
- }
- }
复制代码 等号(盘算)
等号功能进行实际的运算,通过将用户输入的sentence进行运算:
盘算结果后将内容回显到显示器中。
- bool Calculator::btnEqualClicked() {
- if(isPureNumber(sentence)) {
- ui->outputLabel->setText(QString::number(num, 'f', decimalCount));
- sentence = QString::number(num, 'f', decimalCount);
- return true;
- }
- // 将当前数字(num)转换为字符串,并添加到当前计算表达式(sentence)中
- sentence += QString::number(num, 'f', decimalCount);
- QString str = sentence; // 将表达式字符串复制到局部变量
- QStack<double> numbers; // 用于存储操作数的栈
- QStack<QChar> operators; // 用于存储操作符的栈
- if(!sentence.begin()->isDigit()) {
- ui->outputLabel->setText("Error: There are no numbers before the operator."); // 显示结果(保留两位小数)
- ui->displayLabel->setText("");
- initMembers();
- sentence = "";
- return false;
- }
- // 定义操作符的优先级
- QMap<QChar, int> precedence = {{'+', 1}, {'-', 1}, {'*', 2}, {'/', 2}};
- str = str.trimmed(); // 去除前后的空白字符
- int length = str.length(); // 获取表达式的长度
- for (int i = 0; i < length; ++i) {
- QChar ch = str[i]; // 当前字符
- // 处理数字或小数点
- if (ch.isDigit() || (ch == '.' && (i > 0 && str[i - 1].isDigit()))) {
- QString numberStr;
- while (i < length && (str[i].isDigit() || str[i] == '.')) {
- numberStr += str[i++]; // 读取完整的数字(包括小数点)
- }
- --i; // 回退一个字符,因为循环结束时 i 已经多加了一次
- numbers.push(numberStr.toDouble()); // 将数字转换为 double 并压入操作数栈
- }
- // 处理负号(负数)
- else if (ch == '-' && (i == 0 || (i > 0 && str[i - 1] == '('))) {
- QString numberStr;
- numberStr += ch; // 负号
- while (i + 1 < length && (str[i + 1].isDigit() || str[i + 1] == '.')) {
- numberStr += str[++i]; // 读取负数后的数字
- }
- numbers.push(numberStr.toDouble()); // 将负数转换为 double 并压入操作数栈
- }
- // 处理操作符(+ - * /)
- else if (precedence.contains(ch)) {
- // 处理当前操作符前已有的操作符(具有相同或更高优先级的)
- while (!operators.isEmpty() && precedence[operators.top()] >= precedence[ch]) {
- double right = numbers.pop(); // 从操作数栈弹出右操作数
- double left = numbers.pop(); // 从操作数栈弹出左操作数
- QChar op = operators.pop(); // 从操作符栈弹出操作符
- double result;
- if (op == '+') result = left + right; // 计算加法
- else if (op == '-') result = left - right; // 计算减法
- else if (op == '*') result = left * right; // 计算乘法
- else if (op == '/') {
- if (right == 0) { // 处理除以零的情况
- ui->outputLabel->setText("Error: Division by zero");
- return false;
- }
- result = left / right; // 计算除法
- }
- numbers.push(result); // 将结果压入操作数栈
- }
- operators.push(ch); // 将当前操作符压入操作符栈
- }
- }
- // 处理剩余的操作符
- while (!operators.isEmpty()) {
- double right = numbers.pop(); // 从操作数栈弹出右操作数
- double left = numbers.pop(); // 从操作数栈弹出左操作数
- QChar op = operators.pop(); // 从操作符栈弹出操作符
- double result;
- if (op == '+') result = left + right; // 计算加法
- else if (op == '-') result = left - right; // 计算减法
- else if (op == '*') result = left * right; // 计算乘法
- else if (op == '/') {
- if (right == 0) { // 处理除以零的情况
- ui->outputLabel->setText("Error: Division by zero");
- return false;
- }
- result = left / right; // 计算除法
- }
- numbers.push(result); // 将结果压入操作数栈
- }
- EqualBtnClicked = true;
- // 确保栈中仅剩一个操作数,即计算结果
- if (numbers.size() == 1) {
- double result = numbers.pop(); // 获取计算结果
- qDebug() << "ret: " << result;
- ui->outputLabel->setText(QString::number(result, 'f', decimalCount)); // 显示结果(保留两位小数)
- ui->displayLabel->setText("");
- sentence = QString::number(result, 'f', decimalCount);
- num = result;
- operation = '\0';
- // isNewOperation = true;
- isFirstElement = true;
- hasDecimalPoint = false;
- decimalPlaces = 0.1;
- decimalCount = 0;
- EqualBtnClicked = false;
- return true;
- } else {
- ui->outputLabel->setText("Error"); // 显示错误信息
- return false;
- }
- }
- void Calculator::initConnections()
- {
- // 初始化数字按钮
- for (int i = 0; i <= 9; ++i)
- {
- connect(findChild<QToolButton*>(QString("btn%1").arg(i)), &QToolButton::clicked, [this, i]() { btnNumClicked(i); });
- }
- // 初始化运算符
- connect(ui->btnAdd, &QToolButton::clicked, [this]() { btnOperatorClicked('+'); });
- connect(ui->btnSub, &QToolButton::clicked, [this]() { btnOperatorClicked('-'); });
- connect(ui->btnMul, &QToolButton::clicked, [this]() { btnOperatorClicked('*'); });
- connect(ui->btnDiv, &QToolButton::clicked, [this]() { btnOperatorClicked('/'); });
- // 绑定 等于按钮
- connect(ui->btnEqual, &QToolButton::clicked, [this]() { btnEqualClicked(); });
- // 绑定其他功能按钮
- connect(ui->btnC, &QToolButton::clicked, [this]() { btnCClicked(); });
- connect(ui->btnCE, &QToolButton::clicked, [this]() { btnCEClicked(); });
- connect(ui->btnBack, &QToolButton::clicked, [this]() { btnBackClicked(); });
- connect(ui->btnSquare, &QToolButton::clicked, [this]() { btnSquareClicked(); });
- connect(ui->btnFraction, &QToolButton::clicked, [this]() { btnFractionClicked(); });
- connect(ui->btnSqrt, &QToolButton::clicked, [this]() { btnSqrtClicked(); });
- connect(ui->btnPer, &QToolButton::clicked, [this]() { btnPerClicked(); });
- connect(ui->btnSpot, &QToolButton::clicked, [this]() { btnSpotClicked(); });
- connect(ui->btnReverse, &QToolButton::clicked, [this]() { btnReverseClicked(); });
- }
复制代码 初始化 C / CE
C、CE分别为完全初始化与初始化当前输入,通过调用自实现的initMembers()并更改显示器上的显示内容;
- oid Calculator::btnCClicked()
- {
- // 清空全部内容
- initMembers();
- sentence = "";
- ui-> displayLabel->setText("");
- ui->outputLabel->setText("");
- }
- void Calculator::btnCEClicked()
- {
- initMembers();
- ui->displayLabel->setText("");
- }
- void Calculator::initMembers()
- {
- num = 0;
- operation = '\0';
- isNewOperation = true;
- isFirstElement = true;
- hasDecimalPoint = false;
- decimalPlaces = 0.1;
- decimalCount = 0;
- EqualBtnClicked = false;
- }
复制代码 其他功能
其他的功能诸如平方数、开根号、取分数等,都只需要简单盘算一下再设置num即可。
- void Calculator::btnCClicked()
- {
- // 清空全部内容
- initMembers();
- sentence = "";
- // ui-> displayLabel->setText("displayLabel");
- // ui->outputLabel->setText("outputLabel");
- ui-> displayLabel->setText("");
- ui->outputLabel->setText("");
- }
- void Calculator::btnCEClicked()
- {
- initMembers();
- ui->displayLabel->setText("");
- }
- void Calculator::btnSquareClicked()
- {
- num *= num;
- ui->displayLabel->setText(QString::number(num, 'f', decimalCount + 6));
- }
- void Calculator::btnSqrtClicked()
- {
- if (num >= 0) { // 防止负数开根号的错误
- num = sqrt(num); // 计算平方根
- ui->displayLabel->setText(QString::number(num, 'f', decimalCount + 6)); // 显示6位小数
- } else {
- ui->displayLabel->setText("Error: 负数不能开根号"); // 处理负数开根号的情况
- }
- }
- void Calculator::btnFractionClicked()
- {
- if (num != 0) { // 防止除以0的错误
- num = 1.0 / num;
- ui->displayLabel->setText(QString::number(num, 'f', decimalCount + 6)); // 显示6位小数
- } else {
- ui->displayLabel->setText("Error: 除数不能为0"); // 处理除以0的情况
- }
- }
- void Calculator::btnPerClicked()
- {
- num = num / 100.0; // 将当前值转换为百分比
- ui->displayLabel->setText(QString::number(num, 'f', decimalCount + 6)); // 显示6位小数
- }
- void Calculator::btnReverseClicked()
- {
- num = -num;
- ui->displayLabel->setText(QString::number(num, 'f', decimalCount)); // 更新显示,6位小数
- }
复制代码 结果演示
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |