一. 计算机程序界面分析
从效果图我们可以得知
1.QLineEdit 用于接受用户输入
2.QLineEdit 能够获取用户输入的字符串
3.QLineEdit 是功能性组件, 需要父组件作为容器
4.QLineEdit 能够在父组件中进行定位
该计算器的坐标及位置如图所示
界面的代码实现
- #include "Widget.h"
- #include <QApplication>
- #include <QPushButton>
- #include <QLineEdit>
- int main(int argc, char *argv[])
- {
- QApplication a(argc, argv);
- QWidget* w = new QWidget(NULL, Qt::WindowCloseButtonHint);
- w->setWindowTitle("Calculator");
- QLineEdit* le = new QLineEdit(w);
- QPushButton* button[20] = {0};
- const char* btnText[20] =
- {// 数字键与功能键
- "7", "8", "9", "+", "(",
- "4", "5", "6", "-", ")",
- "1", "2", "3", "*", "<-",
- "0", ".", "=", "/", "C",
- };
- int ret = 0;
- // 设置的大小以及坐标
- le->move(10, 10);
- le->resize(240, 30);
- le->setReadOnly(true);
- // 数字键与功能键的位置的实现
- for(int i=0; i<4; i++)
- {
- for(int j=0; j<5; j++)
- {
- button[i*5 + j] = new QPushButton(w);
- button[i*5 + j]->resize(40, 40);
- button[i*5 + j]->move(10 + (10 + 40)*j, 50 + (10 + 40)*i);
- button[i*5 + j]->setText(btnText[i*5 + j]);
- }
- }
- w->show();
- w->setFixedSize(w->width(), w->height());
- ret = a.exec();
- delete w;
- return ret;
- }
运行的结果如图所示
上面只是暂时生成了计算机 demo 的 UI, 会存在许多的问题以及算法的实现按会在接下来进行介绍
A. 计算器界面的代码重构
1. 重构 -- 以改善代码质量为目的代码重写, 使其软件设计的设计和架构更加合理, 提高软件的扩展性和维护性
代码的实现与重构不同
代码实现 -- 按照设计编程实现, 重心在于功能的实现
代码重构 -- 以提高代码质量为目的软件架构优化
区别: 代码实现是不考虑架构的好坏, 只考虑功能的实现, 代码重构时不能影响已实现的功能, 只考虑架构的改善
计算器界面代码重构
重构的实现
- main.cpp
- #include "CalculatorUI.h"
- #include <QApplication>
- int main(int argc, char *argv[])
- {
- QApplication a(argc, argv);
- QCalculatorUI* cal = QCalculatorUI::NewInstance();
- int ret = -1;
- if( cal != NULL )
- {
- cal->show();
- ret = a.exec();
- delete cal;
- }
- return ret;
- }
- CalculatorUI.h
- #ifndef WIDGET_H
- #define WIDGET_H
- #include <QWidget>
- #include <QLineEdit>
- #include <QPushButton>
- class QCalculatorUI : public QWidget
- {
- private:
- QLineEdit* m_edit;
- QPushButton* m_buttons[20];
- QCalculatorUI();
- bool construct();
- public:
- static QCalculatorUI* NewInstance();
- void show();
- ~QCalculatorUI();
- };
- #endif // WIDGET_H
- CalculatorUI.cpp
- #include "CalculatorUI.h"
- QCalculatorUI::QCalculatorUI() : QWidget(NULL, Qt::WindowCloseButtonHint)
- {
- }
- bool QCalculatorUI::construct()
- {
- bool ret = true;
- const char* btnText[20] =
- {
- "7", "8", "9", "+", "(",
- "4", "5", "6", "-", ")",
- "1", "2", "3", "*", "<-",
- "0", ".", "=", "/", "C",
- };
- m_edit = new QLineEdit(this);
- if( m_edit != NULL )
- {
- m_edit->move(10, 10);
- m_edit->resize(240, 30);
- m_edit->setReadOnly(true);
- }
- else
- {
- ret = false;
- }
- for(int i=0; (i<4) && ret; i++)
- {
- for(int j=0; (j<5) && ret; j++)
- {
- m_buttons[i*5 + j] = new QPushButton(this);
- if( m_buttons[i*5 + j] != NULL )
- {
- m_buttons[i*5 + j]->resize(40, 40);
- m_buttons[i*5 + j]->move(10 + (10 + 40)*j, 50 + (10 + 40)*i);
- m_buttons[i*5 + j]->setText(btnText[i*5 + j]);
- }
- else
- {
- ret = false;
- }
- }
- }
- return ret;
- }
- QCalculatorUI* QCalculatorUI::NewInstance()
- {
- QCalculatorUI* ret = new QCalculatorUI();
- if( (ret == NULL) || !ret->construct() )
- {
- delete ret;
- ret = NULL;
- }
- return ret;
- }
- void QCalculatorUI::show()
- {
- QWidget::show();
- setFixedSize(width(), height());
- }
- QCalculatorUI::~QCalculatorUI()
- {
- }
代码实现的结果
B. 在这里要对 Qt 的消息处理做介绍, 对之后计算器的操作会有帮助
1.Qt 消息模型
Qt 封装了具体操作系统的消息机制
Qt 遵循经典的 GUI 消息驱动事件模型
C.Qt 定义了与系统消息相关的概念
a. 信号 -- 由操作系统产生的消息
b. 槽 -- 程序中的消息处理函数
c. 连接 -- 将系统消息绑定到消息处理函数
Qt 的消息处理机制
上图从 Qt 帮助文档中对 connect 进行查找, connect 函数包含了发送对象, 消息名, 接收对象, 接收对象的的成员函数
D. 自定义槽
1. 只有 QObject 的子类才能自定义槽
2. 定义槽的类必须在声明的最开始处使用 Q_OBJECT
3. 类中声明槽时需要使用 slots 关键字
4. 槽与所处理的信号在函数签名上必须一致
5.SIGNAL 和 SLOT 所指定的名称中可以包含参数类型, 不能包含具体参数名
- // 在上面的 Calculator.h 上添加槽函数
- private slots:
- void onButtonClicked();
- // 同时在 cpp 上将其实现, 通过 connect 函数将其相连
- void QCalculatorUI::onButtonClicked()
- {
- QPushButton* btn = (QPushButton*)sender();
- qDebug() <<"onButtonClicked()";
- qDebug() << btn->text();
- }
- connect(m_buttons[i*5 + j], SIGNAL(clicked(bool)), this, SLOT(onButtonClicked()));
按钮按下实现的打印结果
E. 计算器算法的实现
1. 前缀表达式, 中缀表达式, 后缀表达式的区别
a. 前缀表达式 -- 前缀表达式是一种没有括号的算术表达式, 与中缀表达式不同的是, 其将运算符写在前面, 操作数写在后面. 为纪念其发明者波兰数学家 Jan Lukasiewicz, 前缀表达式也称为 "波兰式". 例如,- 1 + 2 3, 它等价于 1-(2+3).
b. 中缀表达式 -- 是一个通用的算术或逻辑公式表示方法, 操作符是以中缀形式处于操作数的中间 (例: 3 + 4), 中缀表达式是人们常用的算术表示方法. 与前缀表达式(例:+ 3 4) 或后缀表达式 (例: 3 4 +) 相比, 中缀表达式不容易被计算机解析, 但仍被许多程序语言使用, 因为它符合人们的普遍用法. 与前缀或后缀记法不同的是, 中缀记法中括号是必需的. 计算过程中必须用括号将操作符和对应的操作数括起来, 用于指示运算的次序.
c. 后缀表达式 -- 后缀表达式, 又称逆波兰式, 指的是不包含括号, 运算符放在两个运算对象的后面, 所有的计算按运算符出现的顺序, 严格从左向右进行(不再考虑运算符的优先规则)
计算器的算法实现
1. 将中缀表达式进行数字和运算符的分离
2. 将中缀表达式转换为后缀表达式
3. 通过后缀表达式计算最终结果
所有要计算的中缀表达式中包含
分离算法的实现 -- 思想: 以符号作为标志对表达式中的字符逐个访问
中缀转后缀
中缀表达式转后缀表达式的过程类似编译过程
1. 四则运算表达式中的括号必须匹配
2. 根据运算符优先级进行转换
3. 转换后的表达式中没有括号
4. 转换后可以顺序的计算出最终结果
转换过程的实现: a 当前元素 e 为数字对其输出; b 当前元素 e 为运算符, 先与栈顶运算符进行优先级比较, 当其小于或者等于时将栈顶元素输出, 转 1, 如果大于将栈顶元素 e 入栈; c 当前元素 e 为左括号进行入栈; d 当前元素 e 为右括号时弹出栈顶元素并输出, 直至栈顶元素为左括号, 然后将栈顶的左括号从栈中弹出
合法的四则运算表达式中 -- 括号匹配成对出现, 左括号必然先于右括号出现
后缀表达式计算
遍历后缀表达式中的数字和运算符 --a 当前元素为数字进栈; b 当前元素为运算符先从栈中弹出右操作数, 再从栈中弹出昨操作数; c 根据符号进行运算; d 将运算结果压入栈中
最后附上完整的代码下载链接 https://down.51cto.com/data/2464399
来源: http://www.bubuko.com/infodetail-3149113.html