UI用户界面
使用Qt Designer对计算器的界面进行制作
目录
界面设计
界面由22个按钮和1个线型编辑器组成,去除了菜单栏和状态栏。仿照苹果计算器,整体配色为黑、灰、橙;背景为黑色,数字、字母或符号为白色;更改了软件的名字以及软件的图标。
功能描述
C:清楚当前表达式和计算结果的历史记录
H:循环查看计算结果的历史记录
←:退格
CE:清除当前表达式
其他运算符和操作数:输入对应的字符
界面浏览
新功能
1.小数点前后自动补0
输入 “2.” 按下 ‘+’ 号会自动补0变成 “2.0+”,再输入 “.3” 会自动补0变成0.3
2.加减乘除自动切换
输入 “2*” 后输入 ‘/’ 或 ‘+’ 会自动变换当前符号。
3.不允许的操作按了不会生效
一个数字有小数点了就不能再按小数点,这时也按小数点也不会生效
括号里不为空
4.历史记录循环查看
计算若干表达式后按 ‘H’ 键,查看计算历史记录,第一次案会返回最近一次的计算结果,再按一次返回上上次的计算结果,以此类推;当到达最后一条也就是最早的计算记录的时候再按下 ‘H’ 键,则会返回最近一次的计算记录,也就是说这个记录是可以循环查询的。并且每当有一个新的结果产生时,再一次按下 ‘H’ 键还会返回最近一次的计算记录。
dbug
1.除0
通过修改程序使得原本除0会崩溃的程序变成了输出inf
2.负数运算
把负号和减号区分开,这里-4当成一个整体,计算结果正确
3.一个数只能有一个小数点
原代码一个数可以有多个小数点如2.33.44,修改代码后一个数不可输入多个小数点
4.无记录时查看记录出错
无记录时按下 ‘H’ 键会报错,修改后不做任何操作程序正常运行
按钮样式
通过Qt Designer编辑按钮的样式表,设置按钮的背景颜色以及包边,鼠标悬停在按钮上的颜色以及按下按钮的颜色。
QPushButton{
background-color: rgb(180, 180, 180);
border:1px solid gray;
}
QPushButton:hover{
background-color:qlineargradient(x1:0,y1:0,x2:0,y2:1,stop:0 rgb(230, 230, 230), stop:1 rgb(180, 180, 180));
}
QPushButton:pressed{
background-color:qlineargradient(x1:0,y1:0,x2:0,y2:1,stop:0 rgb(180, 180, 180), stop:1 rgb(230, 230, 230));
}
效果
除号 ‘/’ 为未选中效果,乘号’×’ 为按下效果
LineEdit样式
通过Qt Designer编辑按钮的样式表,设置线性编辑框的背景颜色为黑色,和主窗口相同;设置无边框;设置文字颜色为白色;设置文本为纵向居中对齐,横向右对齐。
效果
代码实现
枚举变量
定义枚举变量,区分不同的按钮
//枚举按键类型
enum BtnType
{
Num, //数字类型
Op, //运算符
Dot, //点
Equal, //等于
Back, //退格
Clear, //清除
Empty, //清空
History,//历史记录
Bracket //括号
};
QtGuiApplication类的声明
class QtGuiApplication : public QMainWindow
{
//支持信号和槽
Q_OBJECT
public:
//构造函数
QtGuiApplication(QWidget *parent = Q_NULLPTR);
private:
Ui::QtGuiApplicationClass ui;
//当前串
QString str;
//当前数字
QString cnum;
//历史记录
QStringList list;
//记录按了几下history
int k;
// 声明槽函数
public slots:
void OnClicked(BtnType _type, QString _btn);
};
QtGuiApplication类的定义
构造函数里对窗口名字、图标进行修改,对成员变量进行初始化,对按钮进行绑定
QtGuiApplication::QtGuiApplication(QWidget *parent):
QMainWindow(parent)
{
ui.setupUi(this);
setWindowTitle("LuoHan Calculator v1.0");
setWindowIcon(QIcon("A3.png"));
//初始化成员变量
this->str = "";
//记录按了几下history
this->k = 0;
//数字按钮绑定
connect(ui.pushButton_00, &QPushButton::clicked, [this]() {OnClicked(Num, "0"); });
connect(ui.pushButton_01, &QPushButton::clicked, [this]() {OnClicked(Num, "1"); });
connect(ui.pushButton_02, &QPushButton::clicked, [this]() {OnClicked(Num, "2"); });
connect(ui.pushButton_03, &QPushButton::clicked, [this]() {OnClicked(Num, "3"); });
connect(ui.pushButton_04, &QPushButton::clicked, [this]() {OnClicked(Num, "4"); });
connect(ui.pushButton_05, &QPushButton::clicked, [this]() {OnClicked(Num, "5"); });
connect(ui.pushButton_06, &QPushButton::clicked, [this]() {OnClicked(Num, "6"); });
connect(ui.pushButton_07, &QPushButton::clicked, [this]() {OnClicked(Num, "7"); });
connect(ui.pushButton_08, &QPushButton::clicked, [this]() {OnClicked(Num, "8"); });
connect(ui.pushButton_09, &QPushButton::clicked, [this]() {OnClicked(Num, "9"); });
//运算符按钮绑定
connect(ui.pushButton_plus, &QPushButton::clicked, [this]() {OnClicked(Op, "+"); });
connect(ui.pushButton_minus, &QPushButton::clicked, [this]() {OnClicked(Op, "-"); });
connect(ui.pushButton_multiply, &QPushButton::clicked, [this]() {OnClicked(Op, "*"); });
connect(ui.pushButton_divide, &QPushButton::clicked, [this]() {OnClicked(Op, "/"); });
connect(ui.pushButton_leftbracket, &QPushButton::clicked, [this]() {OnClicked(Bracket, "("); });
connect(ui.pushButton_rightbracket, &QPushButton::clicked, [this]() {OnClicked(Bracket, ")"); });
//其他按钮
connect(ui.pushButton_BACKSPACE, &QPushButton::clicked, [this]() {OnClicked(Back, "Back"); });
connect(ui.pushButton_CE, &QPushButton::clicked, [this]() {OnClicked(Clear, "Clear"); });
connect(ui.pushButton_Dot, &QPushButton::clicked, [this]() {OnClicked(Dot, "."); });
connect(ui.pushButton_equal, &QPushButton::clicked, [this]() {OnClicked(Equal, "="); });
connect(ui.pushButton_C, &QPushButton::clicked, [this]() {OnClicked(Empty, "Empty"); });
connect(ui.pushButton_History, &QPushButton::clicked, [this]() {OnClicked(History, "History"); });
}
槽函数的定义
因为功能较单一,我只定义了一个槽函数对所有按钮进行操作
void QtGuiApplication::OnClicked(BtnType _type, QString _btn);
每按下一个按钮就初始化如下变量:
Calculate()对象用于计算表达式
result用于存放二元运算的结果
temp指向当前表达式的最后一个字符
history为当前历史记录
flag1表示:有无多个小数点
flag2表示:小数点前有无数字
Calculate calculator = Calculate();
string result = "";
QString temp = str.right(1);
QString history = "";
//一个数有无多个小数点;
int flag1 = 0;
//小数点前有无数字;
int flag2 = 0;
接下来就是判断按钮的类型用一个switch语句即可
switch (_type)
如果当前按钮是 数字:
① 如果有小数点且小数点前无数字就在小数点前补0
② 否则直接加上这个数字
case Num:
//如果数字前面是小数点且小数点前面没有数字就补0
if (temp == ".") {
for (int i = str.length() - 1; i >= 0; i--) {
if (str.at(i) == "+" || str.at(i) == "-" || str.at(i) == "*" || str.at(i) == "/" || str.at(i) == "(" || str.at(i) == ")") {
break;
}
if (str.at(i) == "0"|| str.at(i) == "1" || str.at(i) == "2" || str.at(i) == "3" || str.at(i) == "4" || str.at(i) == "5" || str.at(i) == "6" || str.at(i) == "7" || str.at(i) == "8" || str.at(i) == "9") {
flag2 = 1;
break;
}
}
}
if (temp=="." && flag2 == 0) {
//补0
str = str.insert(str.length() - 1, "0");
str += _btn;
break;
}
str += _btn;
break;
如果当前按钮是 运算符:
① 如果是小数点就补0
② +、-、*、/ 可替换
case Op:
//如果前面是小数点补0
if (temp == ".") {
str += "0";
}
//运算符规则
if (temp.compare("+") == 0 || temp.compare("-") == 0) {
if (_btn.compare("-") == 0 || _btn.compare("+") == 0 || _btn.compare("*") == 0 || _btn.compare("/") == 0 ) {
str = str.replace(str.length() - 1, 1, _btn);
break;
}
}
if ((temp.compare("*") == 0 || temp.compare("/") == 0)) {
if (_btn.compare("*") == 0 || _btn.compare("/") == 0 || _btn.compare("+") == 0) {
str = str.replace(str.length() - 1, 1, _btn);
break;
}
if (_btn.compare("-") == 0) {
str += _btn;
break;
}
}
str += _btn;
break;
如果当前按钮是 ‘(’ 或 ‘)’:
① 如果括号里没东西什么也不做
② 否则加上括号
case Bracket:
if (temp.compare("(")==0 && _btn.compare(")") == 0) {
break;
}
str += _btn;
break;
如果当前按钮是 ‘.’:
① 如果前面有括号什么也不做
② 如果前面有小数点也什么都不做
case Dot:
if (temp.compare("(") == 0||temp.compare(")") == 0) {
break;
}
for (int i = str.length() - 1; i >= 0;i--) {
if (str.at(i) == "+"|| str.at(i) == "-" || str.at(i) == "*" || str.at(i) == "/" || str.at(i) == "(" || str.at(i) == ")") {
break;
}
if (str.at(i) == ".") {
flag1 = 1;
break;
}
}
if (flag1 == 1)break;
str += _btn;
break;
如果当前按钮是 ‘=’:
① 如果表达式为空什么也不做
② 如果最后是小数点补0
③ 把计算结果加入到表达式末尾并且存入结果记录并把表达式清空,更新最新历史记录
case Equal:
//如果表达式为空不做操作
if (str.length() == 0) {
k = 0;
return;
}
//如果最后是小数点补0
if (str.right(1) == ".")str += "0";
//string 和 QString的转换,把结果加在等号后面
temp = str;
result = calculator.calculate_expression(str.toStdString());
str = QString::fromStdString(result);
list.append(temp+ QString::fromStdString(" = ") +str);
ui.lineEdit->setText(str);
str = "";
k = 0;
return;
如果当前按钮是 ’ ←’:
① 删除表达式末尾的一个字符
case Back:
str.chop(1);
break;
如果当前按钮是 ‘CE’:
① 清空表达式
case Clear:
str = "";
break;
如果当前按钮是 ‘C’:
① 清空表达式及历史记录
case Empty:
str = "";
list.clear();
break;
如果当前按钮是 ‘H’:
① 循环查看历史记录
case History:
if (list.length() == 0)return;
if (list.length() - 1 - k == -1)k=0;
history = list.at(list.length()-1-k);
ui.lineEdit->setText(history);
k += 1;
return;
最后记得更新编辑框结果
//更新结果
ui.lineEdit->setText(str);