当前位置:网站首页>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
边栏推荐
- 查看rancher中debug端口信息,并做IDEA Remote Jvm Debug
- Application of a class of identities (vandermond convolution and hypergeometric functions)
- Acid transaction theory
- Open3d European clustering
- 12. (map data) cesium city building map
- Redis master-slave mode
- Pytorch softmax regression
- 【yolov5.yaml解析】
- Complete activity switching according to sliding
- Solve readobjectstart: expect {or N, but found n, error found in 1 byte of
猜你喜欢
mmclassification 训练自定义数据
《增长黑客》阅读笔记
Uniapp + unicloud + Unipay realize wechat applet payment function
13. (map data) conversion between Baidu coordinate (bd09), national survey of China coordinate (Mars coordinate, gcj02), and WGS84 coordinate system
yolov5目標檢測神經網絡——損失函數計算原理
Error modulenotfounderror: no module named 'cv2 aruco‘
abap查表程序
Pytorch MLP
[deploy pytoch project through onnx using tensorrt]
Check the debug port information in rancher and do idea remote JVM debug
随机推荐
[calculation of loss in yolov3]
What is the difference between canvas and SVG?
mmclassification 训练自定义数据
阻止瀏覽器後退操作
Error modulenotfounderror: no module named 'cv2 aruco‘
网络五连鞭
【无标题】
redis集群中hash tag 使用
Pytorch MLP
Codeforces Round #804 (Div. 2)
Open3D 欧式聚类
Network five whip
Open3d European clustering
HiEngine:可媲美本地的云原生内存数据库引擎
[loss functions of L1, L2 and smooth L1]
【上采样方式-OpenCV插值】
Mmclassification training custom data
[singleshotmultiboxdetector (SSD, single step multi frame target detection)]
Pytorch softmax regression
yolov5目标检测神经网络——损失函数计算原理