MainWindow_calculator 说明文档

简介

MainWindow_calculator 是一个基于 Qt 框架的简单计算器应用程序的主要窗口类。该计算器支持基本的算术运算,包括加、减、乘、除,并具有清除和退格功能。用户界面由按钮和一个只读文本框组成,允许用户输入和查看表达式及结果。

类构造

构造函数

cpp

复制

1
MainWindow_calculator::MainWindow_calculator(QWidget *parent)
  • 参数

    :

    • parent: 父级 QWidget 指针,通常为主窗口。
  • 功能

    :

    • 设置中心部件和布局,初始化显示区域和按钮布局。

主要组件

  • 中心部件

    :

    • 创建一个新的 QWidget 作为界面的中心部件。
  • 布局

    :

    • 使用 QGridLayout 布局将显示区域和按钮排列。
  • 显示区域

    :

    • QLineEdit 用于显示输入和结果,设置为只读状态。

按钮布局

  • 按钮组织为一个 5 行的矩阵,每行包含 4 个按钮,最后一行有两个特殊按钮:
    • 数字按钮: 0-9
    • 运算符按钮: +, -, *, /
    • 功能按钮: C (清除), CE (退格), = (计算)

成员函数

handleButton

cpp

复制

1
void MainWindow_calculator::handleButton()
  • 功能

    :

    • 处理按钮点击事件,更新显示区域或执行计算。
  • 逻辑

    :

    • 清除 (Clear): 清空显示区域内容。

    • 退格 (CE): 删除最后一个字符。

    • 计算 (=)

      :

      • 使用 QScriptEngine 评估当前表达式。
      • 显示结果或错误信息。
    • 输入处理

      :

      • 过滤连续运算符输入。
      • 处理小数点的输入逻辑,确保每个运算段只有一个小数点。

析构函数

cpp

复制

1
MainWindow_calculator::~MainWindow_calculator()
  • 功能

    :

    • 释放类的资源。Qt 会自动管理对象内存,因此无需手动释放。

使用说明

  1. 运行程序: 启动应用程序后,将显示一个计算器界面。
  2. 输入数字和运算符: 点击数字和运算符按钮,以构建表达式。
  3. 执行计算: 点击 “=” 按钮以计算表达式的结果。
  4. 清除和退格: 使用 “Clear” 按钮清空输入,或使用 “CE” 按钮删除最后一个输入字符。

注意事项

  • 输入格式: 仅支持基本的算术表达式,复杂表达式可能导致错误。
  • 错误处理: 当表达式无效时,显示 “Error” 信息。

结论

MainWindow_calculator 提供了一个简洁明了的用户界面,适合进行基本的数学计算。通过 Qt 的信号与槽机制,确保了用户交互的流畅性和响应性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#include "mainwindow_calculator.h"
#include <QRegExp>

MainWindow_calculator::MainWindow_calculator(QWidget *parent)
: QMainWindow(parent)
{
// 设置中心部件和布局
QWidget *centralWidget = new QWidget(this);
setCentralWidget(centralWidget);

QGridLayout *mainLayout = new QGridLayout(centralWidget);

// 初始化显示区域
display = new QLineEdit();
display->setReadOnly(true);
display->setAlignment(Qt::AlignRight);
display->setStyleSheet("font-size: 24px; padding: 5px;");
mainLayout->addWidget(display, 0, 0, 1, 4);

// 定义按钮布局矩阵
const QVector<QVector<QString>> buttonMatrix = {
{"7", "8", "9", "/"},
{"4", "5", "6", "*"},
{"1", "2", "3", "-"},
{"0", ".", "=", "+"},
{"C", "CE"}
};

// 创建并布局按钮
for (int row = 0; row < buttonMatrix.size(); ++row) {
for (int col = 0; col < buttonMatrix[row].size(); ++col) {
QPushButton *btn = new QPushButton(buttonMatrix[row][col]);
btn->setMinimumSize(70, 50);
btn->setStyleSheet("font-size: 18px;");

// 特殊处理最后一行按钮
if (row == 4) {
mainLayout->addWidget(btn, row + 1, col * 2, 1, 2);
if (col == 0) btn->setText("Clear");
} else {
mainLayout->addWidget(btn, row + 1, col);
}

connect(btn, &QPushButton::clicked, this, &MainWindow_calculator::handleButton);
}
}
}

void MainWindow_calculator::handleButton()
{
QPushButton *clickedBtn = qobject_cast<QPushButton*>(sender());
QString btnText = clickedBtn->text();
QString currentText = display->text();

if (btnText == "Clear") {
display->clear();
} else if (btnText == "CE") {
if (!currentText.isEmpty()) {
display->setText(currentText.left(currentText.length() - 1));
}
} else if (btnText == "=") {
// 表达式求值逻辑
QScriptValue result = scriptEngine.evaluate(currentText);

if (result.isError()) {
display->setText("Error");
} else {
double num = result.toNumber();
// 优化显示格式(整数去尾零)
display->setText(QString::number(num, 'g', 12).remove(QRegExp("\\.?0+$")));
}
} else {
// 输入过滤逻辑
QString newText = currentText + btnText;

// 阻止连续运算符输入
QRegExp operatorRegex("[+\\-*/]");
if (operatorRegex.exactMatch(btnText) &&
operatorRegex.exactMatch(currentText.right(1))) {
return;
}

// 处理小数点逻辑
if (btnText == ".") {
QStringList segments = currentText.split(operatorRegex);
if (segments.last().contains('.')) {
return;
}
if (segments.last().isEmpty()) {
newText = currentText + "0.";
}
}

display->setText(newText);
}
}

MainWindow_calculator::~MainWindow_calculator()
{
// 自动管理Qt对象内存,无需手动释放
}

处理运算符是实现计算器功能的关键部分。以下是如何在 MainWindow_calculator 类中处理运算符的详细步骤:

1. 定义运算符的正则表达式

handleButton 函数中,使用正则表达式来匹配运算符。例如:

cpp

复制

1
QRegExp operatorRegex("[+\\-*/]"); // 定义运算符正则表达式

2. 阻止连续运算符输入

在接收到新按钮点击事件时,首先检查当前输入的最后一个字符是否为运算符。如果是,则阻止用户再次输入运算符:

cpp

复制

1
2
3
if (operatorRegex.exactMatch(btnText) && operatorRegex.exactMatch(currentText.right(1))) {
return; // 如果最后一个字符是运算符,则返回
}

3. 处理小数点

当用户输入小数点时,需确保在同一个数字中只允许一个小数点。使用正则表达式来分割当前文本,并检查最后一个数字部分是否已经包含小数点:

cpp

复制

1
2
3
4
5
6
7
8
9
if (btnText == ".") {
QStringList segments = currentText.split(operatorRegex); // 按运算符分割
if (segments.last().contains('.')) {
return; // 如果最后一个段已经有小数点,则返回
}
if (segments.last().isEmpty()) {
newText = currentText + "0."; // 在开头添加 "0."
}
}

4. 更新显示文本

在确保没有连续运算符或错误的输入后,将新输入的文本拼接到当前文本中:

cpp

复制

1
QString newText = currentText + btnText; // 新的显示文本

5. 完整的运算符处理逻辑

综合以上步骤,处理运算符的完整逻辑如下:

cpp

复制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
else {
// 输入过滤逻辑
QString newText = currentText + btnText; // 新的显示文本

// 阻止连续运算符输入
QRegExp operatorRegex("[+\\-*/]"); // 定义运算符正则表达式
if (operatorRegex.exactMatch(btnText) && operatorRegex.exactMatch(currentText.right(1))) {
return; // 如果最后一个字符是运算符,则返回
}

// 处理小数点逻辑
if (btnText == ".") {
QStringList segments = currentText.split(operatorRegex); // 按运算符分割
if (segments.last().contains('.')) {
return; // 如果最后一个段已经有小数点,则返回
}
if (segments.last().isEmpty()) {
newText = currentText + "0."; // 在开头添加 "0."
}
}

display->setText(newText); // 更新显示文本
}

总结

通过上述步骤,运算符的输入得到了有效的管理,确保用户输入的表达式是有效的,避免了连续运算符或无效小数点的出现。这些检查和逻辑是确保计算器正确运行的重要部分。