思路:
1、通过qt建立一个带有主窗口的工程,然后将数字按键和运算符按键用pushbutton放在ui上,再建立一个qstring读取输入的字符串。
2、用户按下=符号时对字符串进行检查,如果合法则进行计算,如果不合法则输出从错误提示。
3、需要写十几个按键对应的字符串操作函数,再写一个中缀表达式计算的函数(这个函数中包含了判断表达式是否合法,一些字符比如二字节的(×÷)计算前应转换为char字节的(*/),以及对计算结果去除末尾多余的0等)。
4、最后程序调试结束后用QT安装时自带的插件将release编译出来的exe文件封装成可执行程序。
github链接在末尾,先上效果图
启动界面:
计算界面:
报错提示:
主窗口头文件
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QString>
#include <QMainWindow>
#include <string>
#include <stack>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
void get_result();
void sur_win();
private slots:
void on_p1_clicked();
void on_p2_clicked();
void on_p3_clicked();
void on_p4_clicked();
void on_p5_clicked();
void on_p6_clicked();
void on_p7_clicked();
void on_p8_clicked();
void on_p9_clicked();
void on_p0_clicked();
void on_AC_clicked();
void on_backspace_clicked();
void on_padd_clicked();
void on_psubstract_clicked();
void on_pmultiple_clicked();
void on_pequal_clicked();
void on_pdivide_clicked();
void on_pdot_clicked();
void on_ppow_clicked();
void on_jingxi_clicked();
void on_brackestl_clicked();
void on_brackestr_clicked();
void on_pequal2_clicked();
private:
Ui::MainWindow *ui;
QString input = "", ans = "";
std::string s = "";
int tag = 1; //tag = 1表示刚输入了一个符号,再输入符号的时候会直接替换刚才输入的符号
};
#endif // MAINWINDOW_H
主窗口CPP文件
#include "mainwindow.h"
#include "./ui_mainwindow.h"
#include "ui_mainwindow.h"
#include <iostream>
#include "surprise_window.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
setFixedSize(640, 640);
ui->input_line->setPlaceholderText("请点击这里输入算式");
ui->answers->setPlaceholderText("答案会显示在这里哦!!");
}
MainWindow::~MainWindow()
{
delete ui;
}
void caculation(std::stack<double> &s1, std::stack<char>& s2, int& flag){
if (s1.size() < 2){flag = 0; return;}
double a = s1.top();
s1.pop();
double b = s1.top(), d = 1;
s1.pop();
char op = s2.top();
s2.pop();
switch(op){
case('+'): s1.push(b + a); break;
case('-'): s1.push(b - a); break;
case('*'): s1.push(b * a); break;
case('/'): if(a == 0) {flag = 0;break;}s1.push(b / a); break;
case('^'): while(a--) d *= b;s1.push(d); break;
default: flag = 0;
}
}
//计算环节
void MainWindow::get_result(){
if (input.size() < 2){ans = "ERROR_INPUT!!!"; return;} //长度不够可以直接报错
s = input.toStdString();
//16bit的×和÷转化为*和/
for (int i = 0; i < s.size() - 1; ++i){
// std::cout << int(s[i]) << std::endl;
if (s[i] == -61){
if (s[i + 1] == -105){s[i] = '*';s.erase(i + 1, 1); i-= 1;}
else if (s[i + 1] == -73){s[i] = '/'; s.erase(i + 1, 1);i -= 1;}
}
}
// std::cout << s << std::endl;
//写个检查括号数量的函数吧,哎!
int cnt = 0, flag = 1;
for (int i = 0; i < s.size(); ++i){
if (s[i] == '(') {cnt += 1;}
else if(s[i] == ')'){ cnt -= 1;}
if (cnt < 0){ans = "ERROR_INPUT!!!"; return;} //右括号过多
}
if (cnt != 0){ans = "ERROR_INPUT!!!"; return;} //左括号过多
s = '(' + s + ')';//加个括号方便中缀表达式边界条件计算
int n = s.size();
std::stack<double> s1;
std::stack<char> s2;
for (int i = 0; i < n && flag; ++i){
if ('0' <= s[i] && s[i] <= '9'){
double t = 0;
while(i < n && s[i] >= '0' && s[i] <= '9' && flag){t *= 10; t += s[i] - '0'; i += 1;}
//如果后面还有整数部分的话,小数部分不能漏
if(s[i] == '.'){
i += 1;
double tt = 0;
while(i < n && s[i] >= '0' && s[i] <= '9' && flag){tt *= 10;tt += s[i] - '0'; i += 1;}
while(tt > 1){tt /= 10;}
t += tt;
}
i -= 1;
s1.push(t);
}
else if (s[i] == '+'){
while(s2.top() != '(' && flag){caculation(s1, s2, flag);}
s2.push(s[i]);
}
else if (s[i] == '-'){
if (i == 0 || (i && !(s[i - 1] >= '0' && s[i - 1] <= '9') && s[i - 1] != ')')){
double t = 0;
i += 1;
while (i < n && s[i] <= '9' && s[i] >= '0' && flag){t *= 10; t += s[i] - '0';i += 1;}
s1.push(t * -1);
i -= 1;
}
else{
while(s2.top() != '(' && flag){caculation(s1, s2, flag);}
s2.push(s[i]);
}
}
else if (s[i] == '*' || s[i] == '/'){
while (s2.top() != '(' && (s2.top() == '*' || s2.top() == '/' || s2.top() == '^') && flag){caculation(s1, s2, flag);}
s2.push(s[i]);
}
else if (s[i] == '^'){
while (s2.top() != '(' && s2.top() == '^' && flag){caculation(s1, s2, flag);}
s2.push(s[i]);
}
else if (s[i] == ')'){
while (s2.top() != '(' && flag){caculation(s1, s2, flag);}
s2.pop();
}
else if(s[i] == '('){
s2.push(s[i]);
}
}
if (!flag || s2.size() != 0 || s1.size() == 0){ans = "ERROR_INPUT!!!";} //如果因为字符串违规退出或者栈中仍有符号或者栈中没有数字
else{
std::string ss = std::to_string(s1.top());
int i = ss.size() - 1;
//std::cout << ss << std::endl;
while(ss[i] != '.' && ss[i] == '0'){ss.erase(i, 1); i -= 1;}
if(ss[i] == '.') ss.erase(i, 1);
//std::cout << ss << std::endl;
ans = QString::fromStdString(ss);
}
}
void MainWindow::sur_win(){
surprise_window* ww = new surprise_window();
ww->show();
}
void MainWindow::on_p1_clicked(){input = input + "1";ui->input_line->setText(input);tag = 1;}
void MainWindow::on_p2_clicked(){input = input + "2";ui->input_line->setText(input);tag = 1;}
void MainWindow::on_p3_clicked(){input = input + "3";ui->input_line->setText(input);tag = 1;}
void MainWindow::on_p4_clicked(){input = input + "4";ui->input_line->setText(input);tag = 1;}
void MainWindow::on_p5_clicked(){input = input + "5";ui->input_line->setText(input);tag = 1;}
void MainWindow::on_p6_clicked(){input = input + "6";ui->input_line->setText(input);tag = 1;}
void MainWindow::on_p7_clicked(){input = input + "7";ui->input_line->setText(input);tag = 1;}
void MainWindow::on_p8_clicked(){input = input + "8";ui->input_line->setText(input);tag = 1;}
void MainWindow::on_p9_clicked(){input = input + "9";ui->input_line->setText(input);tag = 1;}
void MainWindow::on_p0_clicked(){input = input + "0";ui->input_line->setText(input);tag = 1;}
void MainWindow::on_backspace_clicked(){input = input.left(input.size() - 1);ui->input_line->setText(input); tag = 1;}
void MainWindow::on_AC_clicked(){input = ""; ui->input_line->setText(input); ui->answers->setText("");}
void MainWindow::on_brackestl_clicked(){input = input + "(";ui->input_line->setText(input);}
void MainWindow::on_brackestr_clicked(){input = input + ")";ui->input_line->setText(input);}
void MainWindow::on_pequal2_clicked(){input = ans;ui->input_line->setText(input);}
//下面的按键是运算符
void MainWindow::on_padd_clicked(){
if(tag) {input = input + "+";}
else {input = input.left(input.size() - 1) + "+";}
ui->input_line->setText(input); tag = 0;
}
void MainWindow::on_psubstract_clicked(){
if(tag) {input = input + "-";}
else {input = input.left(input.size() - 1) + "-";}
ui->input_line->setText(input); tag = 0;
}
void MainWindow::on_pmultiple_clicked(){
if(tag) {input = input + "×";}
else {input = input.left(input.size() - 1) + "×";}
ui->input_line->setText(input); tag = 0;
}
void MainWindow::on_pdivide_clicked(){
if(tag) {input = input + "÷";}
else {input = input.left(input.size() - 1) + "÷";}
ui->input_line->setText(input); tag = 0;
}
void MainWindow::on_ppow_clicked(){
if(tag) {input = input + "^";}
else {input = input.left(input.size() - 1) + "^";}
ui->input_line->setText(input); tag = 0;
}
//将结果赋值到input,方便利用当前结果计算计算
void MainWindow::on_pequal_clicked(){
get_result(); ui->answers->setText(ans);
}
void MainWindow::on_pdot_clicked(){
if (input.size() > 0 && input[input.size() - 1] != '.'){input = input + ".";ui->input_line->setText(input);tag = 1;}//不能连续输入2个'.'
}
void MainWindow::on_jingxi_clicked(){
sur_win();
}
还有两个小头文件
#ifndef SURPRISE_WINDOW_H
#define SURPRISE_WINDOW_H
#include <QMainWindow>
namespace Ui {
class surprise_window;
}
class surprise_window : public QMainWindow
{
Q_OBJECT
public:
explicit surprise_window(QWidget *parent = nullptr);
~surprise_window();
private slots:
void on_yes_clicked();
void on_no_clicked();
private:
Ui::surprise_window *ui;
};
#endif // SURPRISE_WINDOW_H
#ifndef CORRECT_H
#define CORRECT_H
#include <QWidget>
namespace Ui {
class correct;
}
class correct : public QWidget
{
Q_OBJECT
public:
explicit correct(QWidget *parent = nullptr);
~correct();
Ui::correct *ui;
public slots:
void on_ok_clicked();
private:
QFont f;
};
#endif // CORRECT_H
两个小文件的cpp
#include "surprise_window.h"
#include "ui_surprise_window.h"
#include "correct.h"
#include "ui_correct.h"
surprise_window::surprise_window(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::surprise_window)
{
ui->setupUi(this);
}
surprise_window::~surprise_window()
{
delete ui;
}
void surprise_window::on_yes_clicked(){
correct * wd = new correct();
wd->ui->texta->setText("恭喜你答对了!!!!!!!!!!!!!!");
wd->show();
}
void surprise_window::on_no_clicked(){
correct *wd = new correct();
wd->ui->texta->setText("我劝你思考清楚再做决定哦!!!!!!!!");
wd->show();
};
#include "correct.h"
#include "ui_correct.h"
correct::correct(QWidget *parent) :
QWidget(parent),
ui(new Ui::correct)
{
ui->setupUi(this);
f.setPixelSize(36);
ui->texta->setFont(f);
}
correct::~correct()
{
delete ui;
}
void correct::on_ok_clicked(){
close();
}
main文件
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
还有3个UI文件..突然发现UI文件不知道怎么发出来,随便截几张图吧,回头把下载链接跟工程上传上来。
然后用qt自带的软件封装一下就行了。
https://github.com/100000000000000000000000000000000/Qt-easy-caculator-s
上面的链接为qt6的widget工程的源码文件以及可执行的计算器文件。