
## 今天学了什么今天学习Qt中常用控件QLabel、QPushbutton、QLineEdit等、布局管理器结合Qt控件写一个简易计算器案例。## 常用控件QLabel用途显示文本、图片、gif不能编辑常用接口setText() 设置文字text() 获取文字setPixmap() 设置图片setAlignment() 对齐注默认不可以点击要点击可以用 mousePressEvent 或者加 setOpenExternalLinks(true) 做超链接。QPushButton用途可点击按钮常用接口setText() 设置文字setEnabled(true/false) 启用/禁用setIcon() 设置图标自带信号clicked()、pressed()、released()注clicked 是鼠标按下再松开才触发pressed 按下立刻触发。QLineEdit用途单行可编辑输入框只能一行不能换行常用接口setText() 设置内容text() 获取输入的字符串setPlaceholderText() 灰色提示字setEchoMode() 密码模式自带信号textChanged()内容改变就发、returnPressed()按回车注多行要用 QTextEdit / QPlainTextEdit。## 布局管理器特点自动管理大小、位置窗口拉伸时控件跟着自适应QHBoxLayout 水平布局控件从左 → 右排成一行QVBoxLayout 垂直布局控件从上 → 下排成一列QGridLayout 网格布局按「行、列」摆放可以跨行列QFormLayout 表单布局标签‑输入框成对标签: xxx输入框布局通用常用函数addWidget(控件)往布局里加控件addLayout(另一个布局)布局可以嵌套setSpacing(n)控件之间间距setContentsMargins(左,上,右,下)布局四周边距用法示例QHBoxLayout *laynew QHBoxLayoutlay-addWidget(btn)w.setLayoutlay;## 简易计算器两个数之间的运算分析计算器实现的功能有哪些加减乘除、取余、求平方求立方、1/2、删除、左移右移插入数字怎么让Qt知道我点了哪个按钮多个信号共用一个槽函数利用sender会返回当前点击的按钮信息怎么存用户输入的数字运算符怎么存输入的数字以及运算符存入textEdit中并且运算符不能同时输入多个。怎么把两次输入的数据计算出结果读取textEdit中的值利用split分割成两个数据点击运算结果。实现① UI界面设计如下② 暂时不考虑代码简洁性让它先跑起来代码如下#include widget.h #include ./ui_widget.h Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui-setupUi(this); this-setWindowTitle(简易计算器); AddSubMulDivModfalse; //数字 QPushButton *btnNum[11]; for(int i0;i11;i) { QString namenumQString::number(i); btnNum[i]this-findChildQPushButton *(name); connect(btnNum[i],QPushButton::clicked,this,Widget::getNum); } //加减乘除取余 左移右移 删除 清零运算符号 connect(ui-add,QPushButton::clicked,this,Widget::takeSymbol); connect(ui-sub,QPushButton::clicked,this,Widget::takeSymbol); connect(ui-mul,QPushButton::clicked,this,Widget::takeSymbol); connect(ui-div,QPushButton::clicked,this,Widget::takeSymbol); connect(ui-mod,QPushButton::clicked,this,Widget::takeSymbol); connect(ui-forward,QPushButton::clicked,this,Widget::takeSymbol); connect(ui-backward,QPushButton::clicked,this,Widget::takeSymbol); connect(ui-delete_2,QPushButton::clicked,this,Widget::takeSymbol); connect(ui-AC,QPushButton::clicked,this,Widget::takeSymbol); //单目运算 connect(ui-num_half,QPushButton::clicked,this,Widget::onenumberCalculate); connect(ui-square,QPushButton::clicked,this,Widget::onenumberCalculate); connect(ui-cube,QPushButton::clicked,this,Widget::onenumberCalculate); //等号 connect(ui-equal,QPushButton::clicked,this,Widget::calculate); } void Widget::getNum() { QPushButton *btnNumqobject_castQPushButton *(sender()); if(btnNum) { if(btnNum-text().ui-textEdit-toPlainText().contains(.)) { return; } ui-textEdit-textCursor().insertText(btnNum-text()); } } void Widget::takeSymbol() { QPushButton *btnSybqobject_castQPushButton *(sender()); if(!btnSyb) return; QString btnbtnSyb-text(); qDebug()btnbtn; //qDebug()AddSubMulDivMod; if(!(Add||Sub||Mul||Div||Mod)) { if(btn) { Addtrue; ui-textEdit-textCursor().insertText(); } if(btn-) { Subtrue; ui-textEdit-textCursor().insertText(-); } if(btn×) { Multrue; ui-textEdit-textCursor().insertText(×); } if(btn÷) { Divtrue; ui-textEdit-textCursor().insertText(÷); } if(btn) { Modtrue; ui-textEdit-textCursor().insertText(); } } qDebug()AddSubMulDivMod; if(btn◀) { ui-textEdit-moveCursor(QTextCursor::Left); } if(btn▶) { ui-textEdit-moveCursor(QTextCursor::Right); } if(btn←) { mytextui-textEdit-toPlainText(); mytext.chop(1); ui-textEdit-setText(mytext); ui-textEdit-moveCursor(QTextCursor::End); } if(btnAC) { ui-textEdit-setText(); ab0; AddSubMulDivModfalse; } } void Widget::splitText() { mytextui-textEdit-toPlainText(); if(mytext.contains()) { QStringList tmytext.split(); if(t.size()2)return; at[0]; bt[1]; Addtrue; } else if(mytext.contains(-)) { QStringList tmytext.split(-); at[0]; bt[1]; Subtrue; } else if(mytext.contains(×)) { QStringList tmytext.split(×); at[0]; bt[1]; Multrue; } else if(mytext.contains(÷)) { QStringList tmytext.split(÷); at[0]; bt[1]; Divtrue; } else if(mytext.contains()) { QStringList tmytext.split(); at[0]; bt[1]; Modtrue; } else amytext; qDebug()aabb; } void Widget::calculate() { double x; double y; splitText(); xa.toDouble(); yb.toDouble(); if(Add) { ui-textEdit-setText(QString::number(xy)); Addfalse; } if(Sub) { ui-textEdit-setText(QString::number(x-y)); Subfalse; } if(Mul) { ui-textEdit-setText(QString::number(x*y)); Mulfalse; } if(Div) { if(y0) return; ui-textEdit-setText(QString::number(x/y)); Divfalse; } if(Mod) { double resfmod(x,y); ui-textEdit-setText(QString::number(res)); Modfalse; } ui-textEdit-moveCursor(QTextCursor::End); } void Widget::onenumberCalculate() { auto btnNameqobject_castQPushButton *(sender()); QString btnbtnName-text(); QString textui-textEdit-toPlainText(); if(btn½) { int numtext.toInt(); numnum/2; ui-textEdit-setText(QString::number(num)); } else if(btnn²) { int numtext.toInt(); numnum*num; ui-textEdit-setText(QString::number(num)); } else if(btnn³) { int numtext.toInt(); numnum*num*num; ui-textEdit-setText(QString::number(num)); } } Widget::~Widget() { delete ui; }复盘思路分析①double不能直接用x%y需要借助fmod②在点击小数点输入时可能出现1.2.3这种情况需要规避在输入数字时可以多加一条判断进行优化③但仍存在一个问题两个数字只能有一个有小数需要继续优化如果第一个数为小数截取运算符后的数据进行单独判断可以实现两个小数相加④但是如果光标前移第一个数没有被规定会重复出现最开始的错误所以应该根据光标位置结合运算符位置截取当前光标下的数字来判断是否已经输入“ . ”⑤代码重复性内容较多不够简洁多个运算符bool如果有更多运算符还要写更多类似代码可以借助枚举把运算符打包connect多个按钮连接同一个槽可以结合QListfor增加代码可读性优化后#include widget.h #include ./ui_widget.h Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui-setupUi(this); this-setWindowTitle(简易计算器); //数字 QPushButton *btnName[11]; for(int i0;i11;i) { QString namenumQString::number(i); btnName[i]this-findChildQPushButton *(name); connect(btnName[i],QPushButton::clicked,this,Widget::getNum); } //符号 QListQPushButton * Symbol_btn{ui-add,ui-sub,ui-mul,ui-div,ui-mod,ui-forward,ui-backward,ui-del,ui-clear,ui-half_num,ui-squre,ui-cube}; for(auto btn:Symbol_btn) { connect(btn,QPushButton::clicked,this,Widget::makeSymbol); } //等于 connect(ui-equal,QPushButton::clicked,this,Widget::equalResult); } void Widget::getNum() { myTextui-lineEdit-text(); int posui-lineEdit-cursorPosition(); auto btnNameqobject_castQPushButton *(sender()); if(!btnName) return; QString btnTextbtnName-text(); if(btnText!.) { ui-lineEdit-insert(btnText); } else //输入 . { int leftpos; while(left0) { QChar cmyText[left-1]; if(c||c-||c×||c÷||c) break; left--; } int rightpos; while(rightmyText.size()) { QChar cmyText[right]; if(c||c-||c×||c÷||c) break; right; } QString checkPartmyText.mid(left,right-left);//截取光标所在位置的数字 if(!checkPart.contains(.)) { ui-lineEdit-insert(.); } } } void Widget::makeSymbol() { myTextui-lineEdit-text(); auto symbolBtnqobject_castQPushButton *(sender()); if(!symbolBtn) return; const QString tsymbolBtn-text(); static const QMapQString,Op_num symMap{ {,OpAdd}, {-,OpSub}, {×,OpMul}, {÷,OpDiv}, {,OpMod} }; if(symMap.contains(t)) { if(opOpNone) { ui-lineEdit-insert(t); } return; } if(t◀) { int posui-lineEdit-cursorPosition(); if(pos-10) ui-lineEdit-setCursorPosition(pos-1); } if(t▶) { int posui-lineEdit-cursorPosition(); int maxPosui-lineEdit-text().size(); if(pos1maxPos) ui-lineEdit-setCursorPosition(pos1); } if(t←) { myText.chop(1); ui-lineEdit-setText(myText); ui-lineEdit-setCursorPosition(ui-lineEdit-text().size()); } if(tAC) { ui-lineEdit-clear(); ab0; opOpNone; } double nummyText.toDouble(); if(t½) { ui-lineEdit-setText(QString::number(num/2)); } if(tn²) { ui-lineEdit-setText(QString::number(num*num)); } if(tn³) { ui-lineEdit-setText(QString::number(num*num*num)); } } void Widget::splitText() { myTextui-lineEdit-text(); a.clear(); b.clear(); opOpNone; static const QMapQString,Op_num symMap{ {,OpAdd}, {-,OpSub}, {×,OpMul}, {÷,OpDiv}, {,OpMod} }; for(auto itsymMap.cbegin();it!symMap.cend();it) { if(myText.contains(it.key())) { QStringList tmyText.split(it.key()); if(t.size()2) return; at[0]; bt[1]; opit.value(); return; } } amyText; } void Widget::equalResult() { splitText(); if(opOpNone) return; double x; double y; xa.toDouble(); yb.toDouble(); double r0; qDebug()xxyy; switch (op) { case OpAdd:rxy; break; case OpSub:rx-y; break; case OpMul:rx*y; break; case OpDiv: { if(y0) return; rx/y; } break; case OpMod: { if(y0) return; rfmod(x,y); } break; default:return; } ui-lineEdit-setText(QString::number(r)); ui-lineEdit-setCursorPosition(ui-lineEdit-text().size()); opOpNone; } Widget::~Widget() { delete ui; }当前计算方法是利用字符串解析split这样抠字可能还存在其他问题可用状态机替代字符串解析即在输入运算符前的数单独存入一个变量num1把等号前的数字与前面的num1进行运算.后期可拓展当前计算器无法进行123这种连续运算只能进行两个数之间的运算需要扩展