当前位置:网站首页>Course design of compilation principle --- formula calculator (a simple calculator with interface developed based on QT)
Course design of compilation principle --- formula calculator (a simple calculator with interface developed based on QT)
2022-07-05 11:58:00 【**inevitable**】
It should meet the requirements of compiling principle course design , Made a simple calculator . Project based on Qt5.13.2 Development . Grammar analysis adopts LL(1) Recursive descent grammar . The calculator can realize +、-、*、/ Besides the function , You can also operate on some special functions and characters , such as PI,e,sin,cos,log wait . In the calculator interface, you can press the button to calculate , You can also input and calculate through the keyboard .
List of articles
Reference material
Development tools used
Running environment :Qt 5.13.2
programing language :C++
Interface design
New project
Step1: Click on New Project
Step2: choice Application Inside Qt Widgets Application
Step3: Yes project Name it and save it in a file path ( Name any , But you can't have Chinese , Chinese symbols cannot have , The project path saves any , No requirement )
Step4: Default to the next step
Step5:Base class Choose as QWidget,Class name You can name it yourself , Here I'll name it Calcilator_UI, Also, you must check Generate from( Used to generate the interface )
Step6: choice Desktop Qt 5.13.2 MinGW 64-bit
Step7: Default next step
Interface layout
The layout here is just a demonstration , Friends can design a better layout according to their own aesthetic ideas
Adding styles
Step1: add to myhelper.h and myhelper.cpp file
Class name Defined as myhelper,Base class Defined as QWidget
Default next step , Then click Finish myhelper Create success
Step2: Add the corresponding code
myhelper.h The documents are as follows :
#ifndef MYHELPER_H
#define MYHELPER_H
#include <QWidget>
#include <QtCore>
#include <QtGui>
#include <QDesktopWidget>
#include <QApplication>
class myhelper : public QWidget
{
Q_OBJECT
public:
explicit myhelper(QWidget *parent = nullptr);
// Set to boot
static void AutoRunWithSystem(bool IsAutoRun, QString AppName, QString AppPath)
{
QSettings *reg = new QSettings(
"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run",
QSettings::NativeFormat);
if (IsAutoRun) {
reg->setValue(AppName, AppPath);
} else {
reg->setValue(AppName, "");
}
}
// Set the code to UTF8
static void SetUTF8Code()
{
#if (QT_VERSION <= QT_VERSION_CHECK(5,0,0))
QTextCodec *codec = QTextCodec::codecForName("UTF-8");
QTextCodec::setCodecForLocale(codec);
QTextCodec::setCodecForCStrings(codec);
QTextCodec::setCodecForTr(codec);
#endif
}
// Set skin style
static void SetStyle(const QString &styleName)
{
QFile file(QString("://image/%1.css").arg(styleName));
file.open(QFile::ReadOnly);
QString qss = QLatin1String(file.readAll());
qApp->setStyleSheet(qss);
qApp->setPalette(QPalette(QColor("#F0F0F0")));
}
// Load Chinese characters
static void SetChinese()
{
QTranslator *translator = new QTranslator(qApp);
translator->load("://image/qt_zh_CN.qm");
qApp->installTranslator(translator);
}
// Judge whether it is IP Address
static bool IsIP(QString IP)
{
QRegExp RegExp("((2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)");
return RegExp.exactMatch(IP);
}
// Time delay
static void Sleep(int sec)
{
QTime dieTime = QTime::currentTime().addMSecs(sec);
while ( QTime::currentTime() < dieTime ) {
QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
}
}
// Center the form
static void FormInCenter(QWidget *frm)
{
int frmX = frm->width();
int frmY = frm->height();
QDesktopWidget w;
int deskWidth = w.width();
int deskHeight = w.height();
QPoint movePoint(deskWidth / 2 - frmX / 2, deskHeight / 2 - frmY / 2);
frm->move(movePoint);
}
signals:
public slots:
};
#endif // MYHELPER_H
myhelper.cpp The documents are as follows :
#include "myhelper.h"
myhelper::myhelper(QWidget *parent) : QWidget(parent)
{
}
Step3: Add resources
choice Qt Medium Qt Resource File
Remember that the name here must be rc, Because this is corresponding to the program , If not named rc, You need to make some modifications to the next program
The next step is to complete by default
Then add the prefix
The prefix name must be ’/’
Then add the current path image All styles in the file
And then compile it , The compiled results are as follows
image File download
Step4: add to icon_style.h and icon_style.cpp file
Before you add it, start with Calculator.pro Add... To the file QT += sql, And compile it
Then add icon_style.h and icon_style.cpp file
Class name Defined as icon_style,Base class Defined as QWidget
The next step is to complete by default
Step5: Add the corresponding code
icon_style.h The documents are as follows :
#ifndef ICON_STYLE_H
#define ICON_STYLE_H
#include <QWidget>
#include <QFont>
#include <QFontDatabase>
#include <QMutex>
#include <QLabel>
#include <QPushButton>
#include <QApplication>
class icon_style : public QWidget
{
Q_OBJECT
public:
explicit icon_style(QWidget *parent = nullptr);
static icon_style* Instance()
{
static QMutex mutex;
if (!_instance) {
QMutexLocker locker(&mutex);
if (!_instance) {
_instance = new icon_style;
}
}
return _instance;
}
void SetIcon(QLabel* lab, QChar c, int size = 10);
void SetIcon(QPushButton* btn, QChar c, int size = 10);
signals:
private:
QFont iconFont;
static icon_style* _instance;
public slots:
};
#endif // ICON_STYLE_H
icon_style.cpp The documents are as follows :
#include "icon_style.h"
icon_style* icon_style::_instance = 0;
icon_style::icon_style(QWidget *parent) : QWidget(parent)
{
int fontId = QFontDatabase::addApplicationFont(":/image/fontawesome-webfont.ttf");
QString fontName = QFontDatabase::applicationFontFamilies(fontId).at(0);
iconFont = QFont(fontName);
}
void icon_style::SetIcon(QLabel* lab, QChar c, int size)
{
iconFont.setPointSize(size);
lab->setFont(iconFont);
lab->setText(c);
}
void icon_style::SetIcon(QPushButton* btn, QChar c, int size)
{
iconFont.setPointSize(size);
btn->setFont(iconFont);
btn->setText(c);
}
meanwhile calculator_ui.h The file is changed as follows :
#ifndef CALCULATOR_UI_H
#define CALCULATOR_UI_H
#include <QWidget>
#include <QApplication>
QT_BEGIN_NAMESPACE
namespace Ui { class Calculator_UI; }
QT_END_NAMESPACE
class Calculator_UI : public QWidget
{
Q_OBJECT
public:
Calculator_UI(QWidget *parent = nullptr);
~Calculator_UI();
void InitStyle_Calculator();
private:
Ui::Calculator_UI *ui;
QPoint mousePoint;
bool mousePressed;
bool max;
QRect location;
};
#endif // CALCULATOR_UI_H
calculator_ui.cpp The file is changed as follows :
#include "calculator_ui.h"
#include "ui_calculator_ui.h"
#include "myhelper.h"
#include "icon_style.h"
Calculator_UI::Calculator_UI(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Calculator_UI)
{
ui->setupUi(this);
myhelper::FormInCenter(this);
this->InitStyle_Calculator();
}
Calculator_UI::~Calculator_UI()
{
delete ui;
}
void Calculator_UI::InitStyle_Calculator()
{
// Set the form title bar to hide
this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint);
location = this->geometry();
max = false;
mousePressed = false;
// Install event listener , Let the title bar recognize double clicking
ui->label_title->installEventFilter(this);
icon_style::Instance()->SetIcon(ui->button_close, QChar(0xf00d), 10);
icon_style::Instance()->SetIcon(ui->button_max, QChar(0xf096), 10);
icon_style::Instance()->SetIcon(ui->button_min, QChar(0xf068), 10);
icon_style::Instance()->SetIcon(ui->btnMenu, QChar(0xf0c9), 10);
icon_style::Instance()->SetIcon(ui->lab_Ico, QChar(0xf015), 12);
}
main.cpp The file is modified as follows :
#include "calculator_ui.h"
#include "myhelper.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
myhelper::SetUTF8Code();
myhelper::SetStyle("blue");// Blue style
myhelper::SetChinese();
Calculator_UI w;
w.show();
return a.exec();
}
The effect after compilation and operation is shown in the following figure :
Press the button on the interface here and there will be no response , Then add zoom , Zoom in and close button functions
First, in the ui Add slot function in the design interface , That is, for shrinking , Right click the zoom in and close buttons , Then click go to slot , Then press ok that will do . Here we use button_close For example :
button_max and button_min similar
calculator_ui.h The file is added as follows :
#ifndef CALCULATOR_UI_H
#define CALCULATOR_UI_H
#include <QWidget>
#include <QApplication>
QT_BEGIN_NAMESPACE
namespace Ui { class Calculator_UI; }
QT_END_NAMESPACE
class Calculator_UI : public QWidget
{
Q_OBJECT
public:
Calculator_UI(QWidget *parent = nullptr);
~Calculator_UI();
void InitStyle_Calculator();
protected:
bool eventFilter(QWidget *obj, QEvent *event);
void mouseMoveEvent(QMouseEvent *e);
void mousePressEvent(QMouseEvent *e);
void mouseReleaseEvent(QMouseEvent *);
private slots:
void on_button_close_clicked();
void on_button_max_clicked();
void on_button_min_clicked();
private:
Ui::Calculator_UI *ui;
QPoint mousePoint;
bool mousePressed;
bool max;
QRect location;
};
#endif // CALCULATOR_UI_H
calculator_ui.cpp The file is added as follows :
#include "calculator_ui.h"
#include "ui_calculator_ui.h"
#include "myhelper.h"
#include "icon_style.h"
Calculator_UI::Calculator_UI(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Calculator_UI)
{
ui->setupUi(this);
myhelper::FormInCenter(this);
this->InitStyle_Calculator();
}
Calculator_UI::~Calculator_UI()
{
delete ui;
}
void Calculator_UI::InitStyle_Calculator()
{
// Set the form title bar to hide
this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint);
location = this->geometry();
max = false;
mousePressed = false;
// Install event listener , Let the title bar recognize double clicking
ui->label_title->installEventFilter(this);
icon_style::Instance()->SetIcon(ui->button_close, QChar(0xf00d), 10);
icon_style::Instance()->SetIcon(ui->button_max, QChar(0xf096), 10);
icon_style::Instance()->SetIcon(ui->button_min, QChar(0xf068), 10);
icon_style::Instance()->SetIcon(ui->btnMenu, QChar(0xf0c9), 10);
icon_style::Instance()->SetIcon(ui->lab_Ico, QChar(0xf015), 12);
}
bool Calculator_UI::eventFilter(QWidget*obj, QEvent *event)
{
if (event->type() == QEvent::MouseButtonDblClick) {
this->on_button_max_clicked();
return true;
}
return QObject::eventFilter(obj, event);
}
void Calculator_UI::mouseMoveEvent(QMouseEvent *e)
{
if (mousePressed && (e->buttons() && Qt::LeftButton) && !max)
{
this->move(e->globalPos() - mousePoint);
e->accept();
}
}
void Calculator_UI::mousePressEvent(QMouseEvent *e)
{
if (e->button() == Qt::LeftButton) {
mousePressed = true;
mousePoint = e->globalPos() - this->pos();
e->accept();
}
}
void Calculator_UI::mouseReleaseEvent(QMouseEvent *)
{
mousePressed = false;
}
void Calculator_UI::on_button_max_clicked()
{
if (max) {
this->setGeometry(location);
icon_style::Instance()->SetIcon(ui->button_max, QChar(0xf096), 10);
ui->button_max->setToolTip(" Maximize ");
} else {
location = this->geometry();
this->setGeometry(qApp->desktop()->availableGeometry());
icon_style::Instance()->SetIcon(ui->button_max, QChar(0xf079), 10);
ui->button_max->setToolTip(" Restore ");
}
max = !max;
}
void Calculator_UI::on_button_min_clicked()
{
this->showMinimized();
}
void Calculator_UI::on_button_close_clicked()
{
qApp->exit();
}
After adding the corresponding code , The interface can be reduced , close , Move and zoom , Note that the interface will not zoom in after pressing the zoom in button , Because in interface design , The maximum length of the overall interface , The width and the minimum length and width are fixed , If you want to see the zoom function, you only need to make corresponding adjustments and layout in the interface design
Lexical analysis
preparation
add to token.h and token.cpp file , The steps are similar to the previous style addition .
Right click Calculator_Design -> Click on Add New -> choice C++ Inside C++ Class -> Class name As the token -> Base class As the QWidget -> Click next -> Click finish
After the project is completed , When formally writing code , First the Calculator_Design.pro Medium c++ 11 Change it to c++ 17 standard , Because it needs to be used in later programming c++17 New characteristics .
Code addition
token.h
#ifndef TOKEN_H
#define TOKEN_H
#include <QWidget>
#include <string>
#include <tuple> // Used to store the return value
#include <variant>
#include <functional> // hold lambda Stored as a variable
#include <optional>
enum class TokenType
{
// Numbers
Number,
// Symbol , English letter a-z,A-Z
Symbo,
// Used to indicate the end of
End, // Stop sign
// Used to indicate an error
Error, // Error symbol
Plus = '+',
Minus = '-',
Mul = '*',
Div = '/',
Lp = '(',
Rp = ')',
};
struct Token // Define the symbolic structure
{
TokenType type; // Symbol type
std::variant<double,std::string> value = 0.0;
};
// Find the specific definition of the symbol in the symbol table
std::optional<std::variant<double, std::function<double(double)>>> getSymboValue(std::string symbo);
//input = "1 + 2 * 3"
//tokenize("1 + 2 * 3") -> Symbol 1 + The remaining string "+ 2 * 3"
//tokenize("+ 2 * 3") -> Operator + + The remaining string "2 * 3"
//tokenize("2 * 3") -> Numbers 2 + The remaining string "* 3"
//....
// The return values here are multiple , It can be used tuple
std::tuple<Token, std::string> tokenize(std::string input);
// Input is std::string input
// The first return value is Token, The second return value is the remaining string std::string
class token : public QWidget
{
Q_OBJECT
public:
explicit token(QWidget *parent = nullptr);
signals:
public slots:
};
#endif // TOKEN_H
token.cpp
#include "token.h"
#include <math.h>
#include <stdexcept> // exception handling
#include <unordered_map> // The index value can be a string
#include <functional> // hold lambda Stored as a variable
// The symbol table
// The index value is string
// The return type is variant, There are two possibilities. One is double, The other is to input double, Return to double A function of
static std::unordered_map<std::string, std::variant<double, std::function<double(double)>>> SymboTable
{
{"PI",atan(1.0) * 4},
{"e",exp(1.0)},
{"sin",[](double val) {return sin(val); }},
{"cos",[](double val) {return cos(val); }},
{"asin",[](double val) {return asin(val); }},
{"acos",[](double val) {return acos(val); }},
{"tan",[](double val) {return tan(val); }},
{"atan",[](double val) {return atan(val); }},
{"sqrt",[](double val) {return sqrt(val); }},
{"log", [](double val) {return log(val); }},
};
// Analytic symbol
static std::tuple<std::string, std::string> parseSymbo(std::string input)
{
std::string symbo;
while (1)
{
// The input string ends , Get out of the loop
if (input.empty())
{
break;
}
// Get the first character
char ch = input.front();
if (isalpha(ch))
{
symbo.push_back(ch);
input.erase(input.begin());
}
else
{
break;
}
}
return { symbo,input };
}
// use static Indicates that this function is only used in this .cpp Meaningful in the document
static std::tuple<double, std::string> parseNumber(std::string input)
{
std::string numstr;
// It means that the decimal point is encountered for the first time
// avoid 1.5.5 This situation
bool firstDot = true;
while (1)
{
if (input.empty())
{
break;
}
char ch = input.front();
if ((ch >= '0' && ch <= '9') || (ch == '.' && firstDot))
{
numstr.push_back(ch);
input.erase(input.begin());
if (ch == '.')
{
firstDot = false;
}
}
else
{
break;
}
}
//stod Used to convert characters into numbers
return { std::stod(numstr) , input };
}
// Find the specific definition of the symbol in the symbol table
std::optional<std::variant<double, std::function<double(double)>>> getSymboValue(std::string symbo)
{
if (auto iter = SymboTable.find(symbo); iter != SymboTable.end())
{
// Return its specific value
return { iter->second };
}
return {};
}
std::tuple<Token, std::string> tokenize(std::string input)
{
Token tk;
char ch;
// The first thing is to remove the opening space
do
{
if (input.empty()) // Input empty
{
tk.type = TokenType::End;
return { tk,"" };
}
else
{
// Get input The first character
ch = input.front();// Take the first character
// And change this character from input Remove the beginning of
input.erase(input.begin());
}
} while (ch == ' ');
// The second thing is to produce the corresponding character based on the first non blank character token For return
switch (ch)
{
case '+':
case '-':
case '*':
case '/':
case '(':
case ')':
tk.type = TokenType(ch);
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
tk.type = TokenType::Number;
// hold ch Re add to input The beginning of
// For example, it begins with 1.0
input.insert(input.begin(), ch);
// Turn the number in this string into a real number
std::tie(tk.value, input) = parseNumber(input);
break;
default:
// Judge whether it is a-z,A-Z The characters of
if (isalpha(ch))
{
tk.type = TokenType::Symbo;
// hold ch Re add to input The beginning of
input.insert(input.begin(), ch);
// Parse this out symbo
std::tie(tk.value, input) = parseSymbo(input);
}
else
{
// Use exceptions to express errors
throw std::runtime_error(" error : There are illegal symbols !\n");
}
break;
}
return { tk,input };
}
token::token(QWidget *parent) : QWidget(parent)
{
}
Syntax analysis
preparation
add to parser.h and parser.cpp file , The steps are similar to the previous style addition .
Right click Calculator_Design -> Click on Add New -> choice C++ Inside C++ Class -> Class name As the parser -> Base class As the QWidget -> Click next -> Click finish
After the project is completed , Start writing code
Code addition
parser.h
#ifndef PARSER_H
#define PARSER_H
#include <QWidget>
#include <string>
#include <tuple>
// Parsing is not one-time , Instead, analyze them one by one So return with tuple To return multiple values
std::tuple<double, std::string> parseExpress(std::string input);
class parser : public QWidget
{
Q_OBJECT
public:
explicit parser(QWidget *parent = nullptr);
bool is_contain_lp = false;
signals:
public slots:
};
#endif // PARSER_H
parser.cpp
#include "parser.h"
#include "token.h"
// Parsing is not one-time , Instead, analyze them one by one So return with tuple To return multiple values
static std::tuple<double, std::string> parseFactor(std::string input)
{
double result;
Token tk;
// Parse the first token
std::tie(tk, input) = tokenize(input);
switch (tk.type)
{
case TokenType::Number:
result = std::get<double>(tk.value);
break;
case TokenType::Symbo:
{ // First search whether the symbol is defined in the symbol table
auto search = getSymboValue(std::get<std::string>(tk.value));
if (search)
{
// There are two situations
// situation 1 symbo Is a constant , here result be equal to symbo The specific value of the corresponding constant
if (std::holds_alternative<double>(search.value()))
{
result = std::get<double>(search.value());
}
// situation 2 symbo Is the function , Continue parsing at this time (E) And put the parsed E Act on symbo Corresponding function
// The value calculated by the function is assigned to result
else
{
// Get the function ontology
auto fun = std::get<std::function<double(double)>>(search.value());
// Analyze a (
std::tie(tk, input) = tokenize(input);
if (tk.type != TokenType::Lp)
{
throw std::runtime_error(" Grammar mistakes : The expression is missing '('\n");
}
// Analytic expression
double v;
std::tie(v, input) = parseExpress(input);
// analysis )
std::tie(tk, input) = tokenize(input);
if (tk.type != TokenType::Rp)
{
throw std::runtime_error(" Grammar mistakes : The expression is missing ')'!\n");
}
result = fun(v);
}
}
// An exception is thrown when the symbol is not found
else
{
throw std::runtime_error(" Grammar mistakes : There are illegal symbols "+ std::get<std::string>(tk.value)+"\n");
}
break;
}
case TokenType::Lp:
// analysis (E) Inside E
std::tie(result, input) = parseExpress(input);
// Analyze another )
std::tie(tk, input) = tokenize(input);
// If the parsed one is not ) It means that the expression entered is wrong
if (tk.type != TokenType::Rp)
{
throw std::runtime_error(" Grammar mistakes : The expression is missing ')'!\n");
}
break;
default:
// Grammatical mistakes , Exception should be thrown
throw std::runtime_error(" Grammar mistakes : The expression is missing numbers or '('!\n");
break;
}
return { result,input };
}
// Parsing is not one-time , Instead, analyze them one by one So return with tuple To return multiple values
static std::tuple<double, std::string> parseTerm(std::string input)
{
double result;
// translate T -> FR Medium F
std::tie(result, input) = parseFactor(input);
// translate T -> FR Medium R
bool loop = true; // Use this variable to jump out of the loop
while (loop)
{
Token op;
std::string res;
double term;
// translate R -> *TR | /TR | null One of the first token, That's it + perhaps - Or empty
std::tie(op, res) = tokenize(input);
switch (op.type)
{
case TokenType::Mul:
// analysis *TR Medium T
std::tie(term, input) = parseFactor(res);
// Update according to the semantics of multiplication result The numerical
result *= term;
break;
case TokenType::Div:
// analysis /TR Medium T
std::tie(term, input) = parseFactor(res);
// You can't divide by 0
if (term == 0.0)
{
throw std::runtime_error(" error : The divisor cannot be zero 0!\n");
}
// Update according to the semantics of division result The numerical
result /= term;
break;
default:
// Exit loop
loop = false;
break;
}
}
return { result,input };
}
// Parsing is not one-time , Instead, analyze them one by one So return with tuple To return multiple values
//E -> TR
//R -> +TR | -TR | null
std::tuple<double, std::string> parseExpress(std::string input)
{
double result;
// translate E -> TR
std::tie(result, input) = parseTerm(input);
// translate E -> TR Medium R
bool loop = true; // Use this variable to jump out of the loop
while (loop)
{
Token op;
std::string res;
double term;
// translate R -> +TR | -TR | null One of the first token, That's it + perhaps - Or empty
std::tie(op, res) = tokenize(input);
switch (op.type)
{
case TokenType::Plus:
// analysis +TR Medium T
std::tie(term,input) = parseTerm(res);
// Update according to the semantics of addition result The numerical
result += term;
break;
case TokenType::Minus:
// analysis -TR Medium T
std::tie(term, input) = parseTerm(res);
// Update according to the semantics of subtraction result The numerical
result -= term;
break;
default:
// Exit loop
loop = false;
break;
}
}
return { result,input };
}
parser::parser(QWidget *parent) : QWidget(parent)
{
}
Test without interface
main.cpp
#include "calculator_ui.h"
#include "myhelper.h"
#include <QApplication>
#include "parser.h"
#include <stdio.h>
#include <QDebug>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
//std::string input = "1.23 + 2 * (1 + 2 / 5 - 4)";
std::string input = "1.23 + 2 * (1 + 2 / 5 - 4)";
//std::string input = "1+tan(PI/4)";
//std::string input = "1+sin(PI/6)*sqrt(32*sin(PI/6))";
//auto[result,res] = parseExpress(input);
try
{
auto[result, res] = parseExpress(input);
qDebug() << result;
}
catch (std::exception& e)
{
qDebug() << e.what();
}
myhelper::SetUTF8Code();
myhelper::SetStyle("blue");// Blue style
myhelper::SetChinese();
Calculator_UI w;
w.show();
return a.exec();
}
The test results are as follows :
Realize the interface calculation function
preparation
double-click calculator_ui.ui -> Right click each button -> Click to go to slot -> Click on ok
Code addition
calculator_ui.h
#ifndef CALCULATOR_UI_H
#define CALCULATOR_UI_H
#include <QWidget>
#include <QApplication>
QT_BEGIN_NAMESPACE
namespace Ui { class Calculator_UI; }
QT_END_NAMESPACE
class Calculator_UI : public QWidget
{
Q_OBJECT
public:
Calculator_UI(QWidget *parent = nullptr);
~Calculator_UI();
void InitStyle_Calculator();
protected:
bool eventFilter(QWidget *obj, QEvent *event);
void mouseMoveEvent(QMouseEvent *e);
void mousePressEvent(QMouseEvent *e);
void mouseReleaseEvent(QMouseEvent *);
private slots:
void on_button_close_clicked();
void on_button_max_clicked();
void on_button_min_clicked();
void on_button_0_clicked();
void on_button_1_clicked();
void on_button_2_clicked();
void on_button_3_clicked();
void on_button_4_clicked();
void on_button_5_clicked();
void on_button_6_clicked();
void on_button_7_clicked();
void on_button_8_clicked();
void on_button_9_clicked();
void on_button_dot_clicked();
void on_button_clear_clicked();
void on_button_back_clicked();
void on_button_Plus_clicked();
void on_button_Minus_clicked();
void on_button_Mul_clicked();
void on_button_Div_clicked();
void on_button_Lp_clicked();
void on_button_Rp_clicked();
void on_button_euqal_clicked();
void on_button_sin_clicked();
void on_button_asin_clicked();
void on_button_cos_clicked();
void on_button_acos_clicked();
void on_button_tan_clicked();
void on_button_atan_clicked();
void on_button_sqrt_clicked();
void on_button_log_clicked();
void on_button_PI_clicked();
void on_button_e_clicked();
private:
Ui::Calculator_UI *ui;
QPoint mousePoint;
bool mousePressed;
bool max;
QRect location;
// The initialization output box displays 0
QString my_Display = "0";
// Determine whether to input for the first time , If yes, yes true
bool is_FirstInput = true;
// To judge whether something is wrong , In case of error true, Otherwise false
bool is_Error = false;
// Determine whether there is an operator , If yes, it is true, Otherwise false
bool is_Sym = false;
// Judge "(" Is it a number or +-*/(, If it is a number, it is true, Otherwise false
bool lp_left_is_num = false;
};
#endif // CALCULATOR_UI_H
calculator_ui.cpp
#include "calculator_ui.h"
#include "ui_calculator_ui.h"
#include "myhelper.h"
#include "icon_style.h"
#include <string>
#include <stdexcept>
#include "parser.h"
#include <QVariantList>
// Set the display mode of the text box
#include <QCompleter>
#include <QStringList>
#include <QPushButton>
#include <QLineEdit>
//QT Regular expression engine
#include <QRegExp>
Calculator_UI::Calculator_UI(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Calculator_UI)
{
ui->setupUi(this);
myhelper::FormInCenter(this);
this->InitStyle_Calculator();
ui->lineEdit->setText(my_Display);
}
Calculator_UI::~Calculator_UI()
{
delete ui;
}
void Calculator_UI::InitStyle_Calculator()
{
// Set the form title bar to hide
this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint);
location = this->geometry();
max = false;
mousePressed = false;
// Install event listener , Let the title bar recognize double clicking
ui->label_title->installEventFilter(this);
icon_style::Instance()->SetIcon(ui->button_close, QChar(0xf00d), 10);
icon_style::Instance()->SetIcon(ui->button_max, QChar(0xf096), 10);
icon_style::Instance()->SetIcon(ui->button_min, QChar(0xf068), 10);
icon_style::Instance()->SetIcon(ui->btnMenu, QChar(0xf0c9), 10);
icon_style::Instance()->SetIcon(ui->lab_Ico, QChar(0xf015), 12);
}
bool Calculator_UI::eventFilter(QWidget*obj, QEvent *event)
{
if (event->type() == QEvent::MouseButtonDblClick) {
this->on_button_max_clicked();
return true;
}
return QObject::eventFilter(obj, event);
}
void Calculator_UI::mouseMoveEvent(QMouseEvent *e)
{
if (mousePressed && (e->buttons() && Qt::LeftButton) && !max)
{
this->move(e->globalPos() - mousePoint);
e->accept();
}
}
void Calculator_UI::mousePressEvent(QMouseEvent *e)
{
if (e->button() == Qt::LeftButton) {
mousePressed = true;
mousePoint = e->globalPos() - this->pos();
e->accept();
}
}
void Calculator_UI::mouseReleaseEvent(QMouseEvent *)
{
mousePressed = false;
}
void Calculator_UI::on_button_max_clicked()
{
if (max) {
this->setGeometry(location);
icon_style::Instance()->SetIcon(ui->button_max, QChar(0xf096), 10);
ui->button_max->setToolTip(" Maximize ");
} else {
location = this->geometry();
this->setGeometry(qApp->desktop()->availableGeometry());
icon_style::Instance()->SetIcon(ui->button_max, QChar(0xf079), 10);
ui->button_max->setToolTip(" Restore ");
}
max = !max;
}
void Calculator_UI::on_button_min_clicked()
{
this->showMinimized();
}
void Calculator_UI::on_button_close_clicked()
{
qApp->exit();
}
void Calculator_UI::on_button_0_clicked()
{
// Assign the contents of the text box to my_Display
my_Display = ui->lineEdit->text();
// Get the information of pressing the button
QString text = ui->button_0->text();
if(my_Display!="0") // Not the first one 0( It's not just one 0)
{
// Find the last one +-*/() The location of
auto index = my_Display.lastIndexOf(QRegExp("[+-*/()]"));
if(index!=-1)
{
// Find the last one +-*/() String after
auto res = my_Display.right(my_Display.length()-index-1);
if(res != "0")
{
my_Display += "0";
ui->lineEdit->setText(my_Display);
}
}
else
{
my_Display += "0";
ui->lineEdit->setText(my_Display);
}
}
bool is_Sym = my_Display.contains(QRegExp("[+-*/]"));
// Used to display the initial 0.0000.....number
bool is_Number = my_Display.contains(QRegExp("[123456789]"));
if(!is_Sym && is_Number)
{
my_Display = text;
ui->lineEdit->setText(my_Display);
}
}
void Calculator_UI::on_button_1_clicked()
{
// Here, the content of the text box is assigned to my_Display In order to give consideration to keyboard input
my_Display = ui->lineEdit->text();
// Get text information
QString text = ui->button_1->text();
if(is_FirstInput || is_Error || !is_Sym)
{
my_Display = text;
ui->lineEdit->setText(my_Display);
is_FirstInput = false;
is_Error = false;
is_Sym = true;
}
else
{
// Add a new button to the existing text
my_Display += text;
// Set back
ui->lineEdit->setText(my_Display);
}
}
void Calculator_UI::on_button_2_clicked()
{
my_Display = ui->lineEdit->text();
// Get text information
QString text = ui->button_2->text();
if(is_FirstInput || is_Error || !is_Sym)
{
my_Display = text;
ui->lineEdit->setText(my_Display);
is_FirstInput = false;
is_Error = false;
is_Sym = true;
}
else
{
// Add a new button to the existing text
my_Display += text;
// Set back
ui->lineEdit->setText(my_Display);
}
}
void Calculator_UI::on_button_3_clicked()
{
my_Display = ui->lineEdit->text();
my_Display = ui->lineEdit->text();
// Get text information
QString text = ui->button_3->text();
if(is_FirstInput || is_Error || !is_Sym)
{
my_Display = text;
ui->lineEdit->setText(my_Display);
is_FirstInput = false;
is_Error = false;
is_Sym = true;
}
else
{
// Add a new button to the existing text
my_Display += text;
// Set back
ui->lineEdit->setText(my_Display);
}
}
void Calculator_UI::on_button_4_clicked()
{
my_Display = ui->lineEdit->text();
// Get text information
QString text = ui->button_4->text();
if(is_FirstInput || is_Error || !is_Sym)
{
my_Display = text;
ui->lineEdit->setText(my_Display);
is_FirstInput = false;
is_Error = false;
is_Sym = true;
}
else
{
// Add a new button to the existing text
my_Display += text;
// Set back
ui->lineEdit->setText(my_Display);
}
}
void Calculator_UI::on_button_5_clicked()
{
my_Display = ui->lineEdit->text();
// Get text information
QString text = ui->button_5->text();
if(is_FirstInput || is_Error || !is_Sym)
{
my_Display = text;
ui->lineEdit->setText(my_Display);
is_FirstInput = false;
is_Error = false;
is_Sym = true;
}
else
{
// Add a new button to the existing text
my_Display += text;
// Set back
ui->lineEdit->setText(my_Display);
}
}
void Calculator_UI::on_button_6_clicked()
{
my_Display = ui->lineEdit->text();
// Get text information
QString text = ui->button_6->text();
if(is_FirstInput || is_Error || !is_Sym)
{
my_Display = text;
ui->lineEdit->setText(my_Display);
is_FirstInput = false;
is_Error = false;
is_Sym = true;
}
else
{
// Add a new button to the existing text
my_Display += text;
// Set back
ui->lineEdit->setText(my_Display);
}
}
void Calculator_UI::on_button_7_clicked()
{
my_Display = ui->lineEdit->text();
// Get text information
QString text = ui->button_7->text();
if(is_FirstInput || is_Error || !is_Sym)
{
my_Display = text;
ui->lineEdit->setText(my_Display);
is_FirstInput = false;
is_Error = false;
is_Sym = true;
}
else
{
// Add a new button to the existing text
my_Display += text;
// Set back
ui->lineEdit->setText(my_Display);
}
}
void Calculator_UI::on_button_8_clicked()
{
my_Display = ui->lineEdit->text();
// Get text information
QString text = ui->button_8->text();
if(is_FirstInput || is_Error || !is_Sym)
{
my_Display = text;
ui->lineEdit->setText(my_Display);
is_FirstInput = false;
is_Error = false;
is_Sym = true;
}
else
{
// Add a new button to the existing text
my_Display += text;
// Set back
ui->lineEdit->setText(my_Display);
}
}
void Calculator_UI::on_button_9_clicked()
{
my_Display = ui->lineEdit->text();
// Get text information
QString text = ui->button_9->text();
if(is_FirstInput || is_Error || !is_Sym)
{
my_Display = text;
ui->lineEdit->setText(my_Display);
is_FirstInput = false;
is_Error = false;
is_Sym = true;
}
else
{
// Add a new button to the existing text
my_Display += text;
// Set back
ui->lineEdit->setText(my_Display);
}
}
void Calculator_UI::on_button_dot_clicked()
{
my_Display = ui->lineEdit->text();
// Find the last of the text first '.'
auto index = my_Display.lastIndexOf('.');
if(index == -1) // There is no decimal point in front
{
my_Display += '.';
ui->lineEdit->setText(my_Display);
is_Sym = true;
is_FirstInput = false;
is_Error = false;
}
else
{
// Take out the string after the last decimal point
auto res = my_Display.right(my_Display.length()- index - 1);
// Judge this res Whether there is an operator in () + - * / ( Regular expressions )
//rbegin Of r It means reverse
if(res.contains(QRegExp("[()+-*/]")) && res.rbegin()->isNumber())
{
my_Display += '.';
ui->lineEdit->setText(my_Display);
}
}
}
// Empty
void Calculator_UI::on_button_clear_clicked()
{
my_Display = ui->lineEdit->text();
my_Display = "0";
is_FirstInput = true;
ui->lineEdit->setText(my_Display);
}
// Backspace
void Calculator_UI::on_button_back_clicked()
{
my_Display = ui->lineEdit->text();
if(my_Display != "")
{
my_Display.remove(my_Display.length()-1,1);
ui->lineEdit->setText(my_Display);
}
if(my_Display == "")
{
my_Display = "0";
ui->lineEdit->setText(my_Display);
is_FirstInput = true;
}
}
void Calculator_UI::on_button_Plus_clicked()
{
my_Display = ui->lineEdit->text();
// Get text information
QString text = ui->button_Plus->text();
// Add a new button to the existing text
my_Display += text;
// In order to make the calculation continue
is_Sym = my_Display.contains(QRegExp("[+-*/]"));
// Set back
ui->lineEdit->setText(my_Display);
}
void Calculator_UI::on_button_Minus_clicked()
{
my_Display = ui->lineEdit->text();
// Get text information
QString text = ui->button_Minus->text();
// Add a new button to the existing text
my_Display += text;
is_Sym = my_Display.contains(QRegExp("[+-*/]"));
// Set back
ui->lineEdit->setText(my_Display);
}
void Calculator_UI::on_button_Mul_clicked()
{
my_Display = ui->lineEdit->text();
// Get text information
QString text = ui->button_Mul->text();
// Add a new button to the existing text
my_Display += text;
is_Sym = my_Display.contains(QRegExp("[+-*/]"));
// Set back
ui->lineEdit->setText(my_Display);
}
void Calculator_UI::on_button_Div_clicked()
{
my_Display = ui->lineEdit->text();
// Get text information
QString text = ui->button_Div->text();
// Add a new button to the existing text
my_Display += text;
is_Sym = my_Display.contains(QRegExp("[+-*/]"));
// Set back
ui->lineEdit->setText(my_Display);
}
void Calculator_UI::on_button_Lp_clicked()
{
my_Display = ui->lineEdit->text();
// Get text information
QString text = ui->button_Lp->text();
if(is_FirstInput || is_Error || !is_Sym)
{
my_Display = text;
ui->lineEdit->setText(my_Display);
is_FirstInput = false;
is_Error = false;
is_Sym = true;
}
else
{
// Add the value of the new button to the existing text
my_Display += text;
// Set back
ui->lineEdit->setText(my_Display);
}
// Find the last one "(" The location of
auto index = my_Display.lastIndexOf("(");
// Find the last one "(" The first character and itself
auto res = my_Display.right(my_Display.length()-index+1);
res = res.left(res.length()-1);
bool lp_left_is_sym = res.contains(QRegExp("[+-*/(gnst]"));
//g,n,s,t respectively log,tan,atan... The last character
if(!lp_left_is_sym && index!=0)
{
lp_left_is_num = true;
}
}
void Calculator_UI::on_button_Rp_clicked()
{
my_Display = ui->lineEdit->text();
// Get text information
QString text = ui->button_Rp->text();
if(is_FirstInput || is_Error || !is_Sym)
{
my_Display = text;
ui->lineEdit->setText(my_Display);
is_FirstInput = false;
is_Error = false;
is_Sym = true;
}
else
{
// Add the value of the new button to the existing text
my_Display += text;
// Set back
ui->lineEdit->setText(my_Display);
}
}
// Calculation
void Calculator_UI::on_button_euqal_clicked()
{
my_Display = ui->lineEdit->text();
// Statistics '(' The number of
int count_lp=0;
// Statistics ')' The number of
int count_rp=0;
for(int i=0;i<my_Display.length();i++)
{
if(my_Display[i] == '(')
{
count_lp++;
}
if(my_Display[i] == ')')
{
count_rp++;
}
}
try
{
auto[result, res] = parseExpress(my_Display.toLatin1().data());
my_Display = QString::number(result);
is_Sym = false;
// Set back
ui->lineEdit->setText(my_Display);
if(lp_left_is_num == true)
{
is_Error = true;
lp_left_is_num = false;
throw std::runtime_error(" error : Symbol '(' Missing operator on the left !\n");
}
if(count_lp != count_rp)
{
throw std::runtime_error(" error : Symbol '(' And ')' Number mismatch !\n");
}
}
catch (std::exception& e)
{
my_Display = e.what();
is_Error = true;
// Set back
ui->lineEdit->setText(my_Display);
}
}
void Calculator_UI::on_button_sin_clicked()
{
my_Display = ui->lineEdit->text();
// Get text information
QString text = ui->button_sin->text();
if(is_FirstInput || is_Error || !is_Sym)
{
my_Display = text;
ui->lineEdit->setText(my_Display);
is_FirstInput = false;
is_Error = false;
is_Sym = true;
}
else
{
// Add a new button to the existing text
my_Display += text;
// Set back
ui->lineEdit->setText(my_Display);
}
}
void Calculator_UI::on_button_asin_clicked()
{
my_Display = ui->lineEdit->text();
// Get text information
QString text = ui->button_asin->text();
if(is_FirstInput || is_Error || !is_Sym)
{
my_Display = text;
ui->lineEdit->setText(my_Display);
is_FirstInput = false;
is_Error = false;
is_Sym = true;
}
else
{
// Add a new button to the existing text
my_Display += text;
// Set back
ui->lineEdit->setText(my_Display);
}
}
void Calculator_UI::on_button_cos_clicked()
{
my_Display = ui->lineEdit->text();
// Get text information
QString text = ui->button_cos->text();
if(is_FirstInput || is_Error || !is_Sym)
{
my_Display = text;
ui->lineEdit->setText(my_Display);
is_FirstInput = false;
is_Error = false;
is_Sym = true;
}
else
{
// Add a new button to the existing text
my_Display += text;
// Set back
ui->lineEdit->setText(my_Display);
}
}
void Calculator_UI::on_button_acos_clicked()
{
my_Display = ui->lineEdit->text();
// Get text information
QString text = ui->button_acos->text();
if(is_FirstInput || is_Error || !is_Sym)
{
my_Display = text;
ui->lineEdit->setText(my_Display);
is_FirstInput = false;
is_Error = false;
is_Sym = true;
}
else
{
// Add a new button to the existing text
my_Display += text;
// Set back
ui->lineEdit->setText(my_Display);
}
}
void Calculator_UI::on_button_tan_clicked()
{
my_Display = ui->lineEdit->text();
// Get text information
QString text = ui->button_tan->text();
if(is_FirstInput || is_Error || !is_Sym)
{
my_Display = text;
ui->lineEdit->setText(my_Display);
is_FirstInput = false;
is_Error = false;
is_Sym = true;
}
else
{
// Add a new button to the existing text
my_Display += text;
// Set back
ui->lineEdit->setText(my_Display);
}
}
void Calculator_UI::on_button_atan_clicked()
{
my_Display = ui->lineEdit->text();
// Get text information
QString text = ui->button_atan->text();
if(is_FirstInput || is_Error || !is_Sym)
{
my_Display = text;
ui->lineEdit->setText(my_Display);
is_FirstInput = false;
is_Error = false;
is_Sym = true;
}
else
{
// Add a new button to the existing text
my_Display += text;
// Set back
ui->lineEdit->setText(my_Display);
}
}
void Calculator_UI::on_button_sqrt_clicked()
{
my_Display = ui->lineEdit->text();
// Get text information
QString text = ui->button_sqrt->text();
if(is_FirstInput || is_Error || !is_Sym)
{
my_Display = text;
ui->lineEdit->setText(my_Display);
is_FirstInput = false;
is_Error = false;
is_Sym = true;
}
else
{
// Add a new button to the existing text
my_Display += text;
// Set back
ui->lineEdit->setText(my_Display);
}
}
void Calculator_UI::on_button_log_clicked()
{
my_Display = ui->lineEdit->text();
// Get text information
QString text = ui->button_log->text();
if(is_FirstInput || is_Error || !is_Sym)
{
my_Display = text;
ui->lineEdit->setText(my_Display);
is_FirstInput = false;
is_Error = false;
is_Sym = true;
}
else
{
// Add a new button to the existing text
my_Display += text;
// Set back
ui->lineEdit->setText(my_Display);
}
}
void Calculator_UI::on_button_PI_clicked()
{
my_Display = ui->lineEdit->text();
// Get text information
QString text = ui->button_PI->text();
if(is_FirstInput || is_Error || !is_Sym)
{
my_Display = text;
ui->lineEdit->setText(my_Display);
is_FirstInput = false;
is_Error = false;
is_Sym = true;
}
else
{
// Add a new button to the existing text
my_Display += text;
// Set back
ui->lineEdit->setText(my_Display);
}
}
void Calculator_UI::on_button_e_clicked()
{
my_Display = ui->lineEdit->text();
// Get text information
QString text = ui->button_e->text();
if(is_FirstInput || is_Error || !is_Sym)
{
my_Display = text;
ui->lineEdit->setText(my_Display);
is_FirstInput = false;
is_Error = false;
is_Sym = true;
}
else
{
// Add a new button to the existing text
my_Display += text;
// Set back
ui->lineEdit->setText(my_Display);
}
}
Test with interface
Calculate the test correctly
test 1
test 2
test 3
Miscalculation test
test 1
test 2
test 3
test 4
Complete project Download
边栏推荐
- Sentinel sentinel mechanism of master automatic election in redis master-slave
- liunx禁ping 详解traceroute的不同用法
- C operation XML file
- Is investment and finance suitable for girls? What financial products can girls buy?
- MySQL statistical skills: on duplicate key update usage
- 2022年国内云管平台厂商哪家好?为什么?
- [yolov5.yaml parsing]
- Recyclerview paging slide
- Riddle 1
- 1. Laravel creation project of PHP
猜你喜欢
Pytorch softmax regression
redis主从模式
splunk配置163邮箱告警
《增长黑客》阅读笔记
全网最全的新型数据库、多维表格平台盘点 Notion、FlowUs、Airtable、SeaTable、维格表 Vika、飞书多维表格、黑帕云、织信 Informat、语雀
12. (map data) cesium city building map
Simply solve the problem that the node in the redis cluster cannot read data (error) moved
【使用TensorRT通过ONNX部署Pytorch项目】
【L1、L2、smooth L1三类损失函数】
redis主从中的Master自动选举之Sentinel哨兵机制
随机推荐
1 plug-in to handle advertisements in web pages
redis主从中的Master自动选举之Sentinel哨兵机制
Ncp1342 chip substitute pn8213 65W gallium nitride charger scheme
yolov5目标检测神经网络——损失函数计算原理
Principle of persistence mechanism of redis
redis主从模式
Acid transaction theory
pytorch-softmax回归
Splunk configuration 163 mailbox alarm
Thoughts and suggestions on the construction of intelligent management and control system platform for safe production in petrochemical enterprises
Multi table operation - Auto Association query
Open3d mesh (surface) coloring
Open3d European clustering
Video networkState 属性
【 YOLOv3中Loss部分计算】
谜语1
codeforces每日5题(均1700)-第五天
POJ 3176 cow bowling (DP | memory search)
ABAP table lookup program
XML解析